Home > Enterprise >  Python Tkinter Simple Multithreading Question
Python Tkinter Simple Multithreading Question

Time:12-15

I have a simple Listbox with a list of names that I would like to print concurrently, but also in the order of which they were added to the Listbox (alphabetically in this case).

So, just to clarify, I'd like to have 1 thread for each name in the list to print each name. I prefer to do this in the order they are in queue from whatever the listbox has in it.

Here's what I've tried thus far:

from tkinter import Tk, Button, Listbox
import threading

class MainWindow(Tk):
  def __init__(self):
    super().__init__()

    self.lb1 = Listbox(self, width=26, cursor='hand2')
    self.lb1.pack(side='left', fill='y', padx=20, pady=20)

    self.b1 = Button(self, text='START', bg='green', fg='white', cursor='hand2', command=self.start_thread)
    self.b1.pack(side='left')

    self.lb1.insert('end', 'Aaron')
    self.lb1.insert('end', 'Billy')
    self.lb1.insert('end', 'Chris')
    self.lb1.insert('end', 'David')
    self.lb1.insert('end', 'Edward')
    self.lb1.insert('end', 'Frank')
    self.lb1.insert('end', 'George')
    self.lb1.insert('end', 'Howard')
    self.lb1.insert('end', 'Ian')
    self.lb1.insert('end', 'Johnny')

def start_thread(self):
    for i in range(self.lb1.size()):
        t1 = threading.Thread(target = self.work, args=(i,))
        t1.start()



def work(self, i):
    print(self.lb1.get(i))



if __name__ == '__main__':
    app = MainWindow()
    app.title('Main Window')
    app.configure(bg='#333333')

    app.mainloop()

The problem that I'm having is that the threads do not fire off properly. They print the names out in random order and also on the same exact line as if they are just one name at times. How do I get better control of each thread that will print each name concurrently?

Below is an example of what is being printed out:

ChrisEdward
DavidBilly

George

Aaron
Frank
Ian
JohnnyHoward

CodePudding user response:

You can use a Lock object to let only one thread calling print() inside work():

...

def start_thread(self):
    self.lock = threading.Lock()
    for i in range(self.lb1.size()):
        t1 = threading.Thread(target = self.work, args=(i,))
        t1.start()

def work(self, i):
    with self.lock:
        print(self.lb1.get(i))

...

Note that it is not guaranteed that the order of execution of the threads is the same as the order of starting the threads.

  • Related