Python Forum
[Tkinter] Defining a self made module's function to interact with the main .py variables?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Defining a self made module's function to interact with the main .py variables?
#6
You cannot use threads that easily to update a widget's contents in tkinter because the widgets must be updated from the thread that is running the mainloop().

I give you below a complete example of what I mean with the after() method. In this example, a "producer thread" is started that reads data in a file and puts this data in a queue at a random speed.

At the other end of the queue, there is a generator that extracts items from the queue in a non blocking way (so possiby no items at all) and updates the text widget with the data that it receives. This code is run by the main thread. I'm using a trick here: after trying to extract data from the queue, the function runs the "yield" statement, thus becoming a generator. The GUI will use my custom PeriodicConsumer class to drive this generator by intervals of 500 milliseconds. This is done with Tkinter's after() method.

It is a complete example, so you can run it and try to understand it.

import threading

class Error(RuntimeError):
    pass

class PeriodicConsumer:
    def __init__(self, widget):
        self.master =  widget
        self._job = None
        self._stopped = threading.Event()
        self._stopped.set()
        self._seq = None
        
        
    def start(self, sequence, millisecs):
        self.ms = millisecs
        if self._stopped.is_set():
            self._stopped.clear()
            self._seq = sequence
            self._job = self.master.after(self.ms, func=self._step)
        else:
            raise Error('Expected AfterThread in stopped state')

    def stop(self):
        if self._stopped.is_set():
            return
        self._stopped.set()
        if self._job and (
            threading.current_thread() is threading.main_thread()):
            self.master.after_cancel(self._job)
            self._job = None

    def _step(self):
        if self._stopped.is_set():
            return
        try:
            next(self._seq)
        except StopIteration:
            self.stop()
        else:
            self._job = self.master.after(self.ms, func=self._step)

if __name__ == '__main__':
    import io
    import queue
    import random
    import time
    import tkinter as tk
    root = tk.Tk()
    text = tk.Text(root)
    text.pack()
    pc = PeriodicConsumer(root)
    
    def update_text_from_queue(aqueue):
        while True:
            result = []
            try:
                while True:
                    x = aqueue.get_nowait()
                    if x is None:
                        # None in the queue is our signal for
                        # end of data.
                        if result:
                            text.insert(tk.END, "".join(result))
                        return
                    else:
                        result.append(x)
            except queue.Empty:
                pass
            if result:
                text.insert(tk.END, "".join(result))
            yield
    
    myqueue = queue.Queue()
    pc.start(update_text_from_queue(myqueue), 500)
    

    source_file = io.StringIO("""\
Lorem ipsum dolor sit amet, consectetur
adipiscing elit. Proin commodo turpis ex, commodo
pretium nunc tincidunt vel. Maecenas quis mi ac
ligula sagittis placerat ut ac justo.
Fusce nec sodales tortor. Duis hendrerit leo at odio faucibus.
""")
    
    def produce(aqueue):
        for line in source_file:
            aqueue.put(line)
            time.sleep(random.random())
        aqueue.put(None) # our convention for end of input
    
    producer = threading.Thread(target=produce, args=(myqueue,))
    producer.start()
    root.mainloop()
Reply


Messages In This Thread
RE: How can I define a selfmade module's functio to interact with the main .py variables? - by Gribouillis - Jun-07-2020, 04:58 PM

Possibly Related Threads…
Thread Author Replies Views Last Post
  How can I run an interface I made using PyQt5 and a Map program I made using Tkinter bki 6 1,442 Nov-09-2023, 11:12 PM
Last Post: bki
  [PyQt] Managing variables accross a multiple module GUI Oolongtea 18 11,228 Sep-19-2019, 12:13 PM
Last Post: Oolongtea
  “main thread is not in main loop” in Tkinter Long_r 1 24,599 Jun-26-2019, 11:00 PM
Last Post: metulburr
  [Tkinter] Bringing function out of class into main loop zukochew 1 2,737 Jul-30-2018, 06:43 PM
Last Post: Axel_Erfurt
  GTK main window calling a main window DennisT 4 7,057 Oct-19-2016, 09:36 PM
Last Post: DennisT

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020