简体   繁体   English

如何用线程更新 tkinter gui 标签?

[英]how to update tkinter gui label with a thread?

I am new to Python tkinter .我是 Python tkinter 的新手。 I have written the following code for my gui .我为我的 gui 编写了以下代码。 I want to update my label 1 with received body message from rabbitmq .我想用从 rabbitmq 收到的正文消息更新我的标签 1。 But i am facing issue once my gui get populate after that even i receive different message in body ,but its not able to update .但是,一旦我的 gui 被填充,即使我在正文中收到不同的消息,我也面临问题,但它无法更新。 Once i am closing the gui then again its coming with new value.一旦我关闭 gui,它就会再次带来新的价值。 I want my gui tkinter window to be constant and label should be refreshed on receiving new message in body.我希望我的 gui tkinter 窗口保持不变,并且在接收到正文中的新消息时应该刷新标签。

import tkinter
from PIL import ImageTk, Image as PILImage
import datetime as dt
from tkinter import *
import pika

connection = pika.BlockingConnection(
    pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='hello')


def callback(ch, method, properties, body):
    global myval
    print(" [x] Received %r" % body)
   
    window=Tk()
    window.attributes('-fullscreen',True)
    window.bind("<F11>", lambda event: window.attributes("-fullscreen",
                                        not window.attributes("-fullscreen")))
    window.bind("<Escape>", lambda event: window.attributes("-fullscreen",False))
    top_left=Frame(window,width=200,height=200)
    top_middle=Frame(window,width=550,height=200)
    top_right=Frame(window,width=250,height=200)
    middle_left=Frame(window,width=200,height=300)
    middle_middle=Frame(window,width=300,height=300)
    middle_right=Frame(window,width=300,height=300)
    bottom_left=Frame(window,width=0,height=200)
    bottom_middle=Frame(window,width=300,height=200)
    bottom_right=Frame(window,width=300,height=200)
    top_left.grid(row=0,column=0)
    top_middle.grid(row=0,column=1)
    top_right.grid(row=0,column=2,sticky=E+W)
    middle_left.grid(row=1,column=0,padx=100,pady=100)
    middle_middle.grid(row=1,column=1) 
    middle_right.grid(row=1,column=2)
    bottom_left.grid(row=2,column=0)
    bottom_middle.grid(row=2,column=1)
    bottom_right.grid(row=2,column=2)
    dte=Label(top_left, text="Date: "f"{dt.datetime.now():%a,%d/ %m/ %Y}",fg="black",font=("Arial Bold ",12 ))
    dte.place(x=0,y=40)
    lbl=Label(top_middle, text="Welcome to Smartcards Division",fg='#3333ff',font=("Arial Bold Italic",24 ))
    lbl.place(x=0,y=30)
    logo_path="logo.jpg"
    logo = ImageTk.PhotoImage((PILImage.open(logo_path)).resize((280,100),PILImage.ANTIALIAS))
    logo_panel = Label(top_right,image = logo)
    logo_panel.place(x=10,y=30)
    string_clsname=str(body.decode())
    lblxt=StringVar()
    lbl1=Label(middle_left, textvariable=lblxt,fg='#ff6600',font=("Arial Bold Italic",16))
    lblxt.set("Hello "+string_clsname+" Sir")
    lbl1.place(x=0,y=100)
    path = "NewPicture_Copy.jpg"
    image = ImageTk.PhotoImage((PILImage.open(path)).resize((250,250),PILImage.ANTIALIAS))
    panel = Label(middle_middle,image = image,borderwidth=5, relief="ridge")
    panel.pack()
    lbl2=Label(bottom_middle, text="\u00a9"+"2020-Smartcards Division",fg='black',font=("Helvetica",8))
    lbl2.place(x=0,y=0)
    window.title('Image Classification')
    window.mainloop()

channel.basic_consume(
    queue='hello', on_message_callback=callback, auto_ack=True)
print(' [*] Waiting for messages. To exit press CTRL+C')
channel.start_consuming()

At a base level, you need:在基本级别,您需要:

  • Separate threads of execution,独立的执行线程,
    for separate tasks (that must run concurrently).对于单独的任务(必须同时运行)。
  • A way for the threads to communicate with each other;线程相互通信的一种方式;
    while avoiding race conditions同时避免竞争条件
    (like modifying a variable in one thread, (比如在一个线程中修改一个变量,
    while another thread is reading it).而另一个线程正在阅读它)。
    Here you can eg use mutexes/locks, message-passing, etc.例如,您可以在这里使用互斥锁/锁、消息传递等。
import tkinter as tk

from collections import deque
from threading import Thread

from random import randint
from time import sleep

# Starting out (this is the main/gui thread).

root = tk.Tk()

label = tk.Label(root, text='Original text')
label.pack()

# Means of communication, between the gui & update threads:
messageQueue = deque()

# Create a thread, that will periodically emit text updates.
def emitText():  # The task to be called from the thread.
  while(True):  # Normally should check some condition here.
    messageQueue.append(f'Random number: {randint(0, 100)}')
    sleep(1)  # Simulated delay (of 1 sec) between updates.
# Create a separate thread, for the emitText task:
thread = Thread(target=emitText)
# Cheap way to avoid blocking @ program exit: run as daemon:
thread.setDaemon(True)
thread.start()  # "thread" starts running independently.

# Moving on (this is still the main/gui thread).

# Periodically check for text updates, in the gui thread.
# Where 'gui thread' is the main thread, 
# that is running the gui event-loop. 
# Should only access the gui, in the gui thread/event-loop.
def consumeText():
  try: label['text'] = messageQueue.popleft()
  except IndexError: pass  # Ignore, if no text available.
  # Reschedule call to consumeText.
  root.after(ms=1000, func=consumeText)
consumeText()  # Start the consumeText 'loop'.

root.mainloop()  # Enter the gui event-loop.

See also:也可以看看:

queue.Queue 队列.队列
"collections.deque is an alternative implementation of “collections.deque 是另一种实现
unbounded queues with fast atomic append() and popleft()具有快速原子 append() 和 popleft() 的无界队列
operations that do not require locking."不需要锁定的操作。”
collections.deque 集合.deque
threading.Thread 线程.Thread

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM