1

I have been trying to update tkinter canvas text based on an external event (not bindings to keyboard event).

For eg I have a canvas text set to "Hello world", suppose now I call the update funtion updateUI("good bye"), the canvas text should change to the data that is passed in the updateUI(data) funtion.

Another example to explain my question would be as follows, Suppose I have a for loop

for i in range(5):
   updateUI(i)

Here, the canvas text changes dynamically based on the value supplied;(The text will be set to 1 2 3 4 5) I'd like to send the data externally and update the UI in Tkinter so that the data changes dynamically dependent on an external event, such as the for loop in this example.

Here is a working model,

import tkinter as tk
import threading
import time
class gui:

    def __init__(self, master, event):
        self.master = master
        self.event = event
        self.i =0
        self.canvas= tk.Canvas(master, width= 1000, height= 750, bg="SpringGreen2")
        self.id = self.canvas.create_text(300, 50, text="HELLO WORLD", fill="black", font=('Helvetica 15 bold'))
        self.canvas.pack()
        self.eventCheck()

    def updateUI(self):
        self.i+=1
        self.canvas.itemconfig(self.id, text=f"Goodbye, world {self.i}")

        print(f"updated {self.i}")

    def eventCheck(self):
        flag = self.event.is_set()
        if flag:
            self.updateUI()
        self.master.after(2000, self.eventCheck)

def timingLoop(event):
    while True:
        event.set()
        time.sleep(2)
        event.clear()
        time.sleep(2)

def main():
    root = tk.Tk()
    event = threading.Event()
    t = threading.Thread(target=timingLoop, args=(event,))
    t.daemon = True
    t.start()
    app = gui(root, event)
    root.mainloop()

if __name__ == "__main__":
    main()

Now, I want the freedom of sending the data and updating the UI, that is I should be able to call updateUI(data) from any other file, class, and Tkinter should update the UI based on the data received.

NotYaniv
  • 11
  • 1
  • The only way to do what you want is by periodically polling some queue in the tkinter application and checking for messages in it that indicate what GUI widget changes to make. This way the tkinter app's `mainloop()` won't be interrupted. There are a number of questions on this site about doing things like that. See [Freezing/Hanging tkinter GUI in waiting for the thread to complete](https://stackoverflow.com/questions/53696888/freezing-hanging-tkinter-gui-in-waiting-for-the-thread-to-complete) for an example of using such a queue. – martineau Jan 31 '22 at 08:33
  • Yes, I got it working. thanks, @martineau. Can you guide me in making Tkinter main loop() event run on a thread? As in, here is an example of what I am trying to achieve print("hi") root.mainloop() print("hello world") Now, I want the mainloop to run on a separate thread such that the python code executes asynchronously without waiting for the mainloop to end. – NotYaniv Feb 01 '22 at 05:27
  • Not sure I understand your follow-on question. In [my answer](https://stackoverflow.com/a/53697547/355230) to the linked question, the tkinter GUI is in class `GuiPart` which runs in a separate thread. If you want to quit the `mainloop()`, change the `periodic_call()` method of the `ThreadedClient` class so it calls `self.master.quit()` instead of `sys.exit(1)` when the `self.running` flag is `False`. – martineau Feb 01 '22 at 08:02
  • @martineau I want to run Tkinter in a nonblocking way, that ie `root.mainloop() print("hello world") ` now when I run this, I want to run the `root.mainloop()` in the background and make python run my next command which is `print`. I know for a fact that Tkinter can only run on the main thread, can I get a workaround such that my python code never gets in a blocking state ( due to `root.mainloop()` ), and continues the execution even when Tkinter is running in the background. – NotYaniv Feb 01 '22 at 09:15
  • Not that I know of — to say that tkinter is running *means* that its `mainloop()` is executing. It doesn't have to be running in the main thread, as it could be a secondary one — the constraint being that everything related to it has to occur in whatever thread it's executing in because the module does not support multithreading. – martineau Feb 01 '22 at 09:40

0 Answers0