1

I am new to Python tkinter . I have written the following code for my gui . I want to update my label 1 with received body message from rabbitmq . 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 . Once i am closing the gui then again its coming with new value. I want my gui tkinter window to be constant and label should be refreshed on receiving new message in body.

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()
Smartcard
  • 11
  • 3
  • 1
    Please try to reduce this code down to a [mcve]. If the question is about updating a single label from another thread, we don't need any of the other widgets or images for the purposes of this question. – Bryan Oakley Aug 11 '20 at 22:27
  • This not a duplicate [answer](https://stackoverflow.com/q/47895765/4865723) but maybe it can give you more ideas about how to solve your problem. – buhtz Feb 23 '23 at 08:23

1 Answers1

2

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 e.g. 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:
message_queue = deque()


# Create a thread, that will periodically emit text updates.
def emit_text():  # The task to be called from the thread.
    while True:  # Normally should check some condition here.
        message_queue.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=emit_text)
# 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 consume_text():
    try:
        label["text"] = message_queue.popleft()
    except IndexError:
        pass  # Ignore, if no text available.
    # Reschedule call to consumeText.
    root.after(ms=1000, func=consume_text)


consume_text()  # Start the consumeText 'loop'.

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

See also:

queue.Queue
"collections.deque is an alternative implementation of
unbounded queues with fast atomic append() and popleft()
operations that do not require locking."
collections.deque
threading.Thread

Thegerdfather
  • 398
  • 4
  • 13