1

Lets say I have folder with music.

--Iron Maiden
  --Prowler
  --Sanctuary
  --Iron Maiden
  --etc

And I have class with method in it which is finding all music in this folder and adding information about this song to the list.

Little example, just getting path to all files in folder.

from tkinter import Frame, Listbox, Menu, BOTH, filedialog, Tk, LEFT
import os

class GUI(Frame): 

    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.list = Listbox(parent)
        self.parent = parent
        self.init_ui()

    def init_ui(self):
        menu_bar = Menu(self.parent)
        self.parent.config(menu=menu_bar)
        file_menu = Menu(menu_bar, tearoff=False)
        self.list.pack(side=LEFT)
        file_menu.add_command(label="Choose folder with music",
                              underline=0, command=self.get_music)
        menu_bar.add_cascade(label="File", underline=0, menu=file_menu)

    def get_music(self):
        dir_name = filedialog.askdirectory(parent=self, initialdir="/",
                                           title='Please select a directory')
        self.config(cursor="wait")
        self.update()
        for data in os.walk(dir_name):
            for filename in data[2]:
                self.list.insert(0,os.path.join(data[0], filename))

GUI(Tk()).mainloop()

Lets imagine that get_music lasts for minutes and user doesn't know what is going on, he is bored and scared.

I want to show him new window with listbox and progress bar and in the listbox show him what now is doing my program and in the progress bar show him progress.

Here I've found very good example and for a few hours I've been trying to make it work with what I have, but whatever I do it doesn't work.

I've even tried to start test thread from get_music(), but id didn't work.

How can I connect what I have with what is in the example ?

Or maybe there is other, better way to do what I want to do ?

Community
  • 1
  • 1
Aleksander Monk
  • 2,787
  • 2
  • 18
  • 31
  • 1) you don't need multi-threading to show progress. Just update your widgets each time you found a file and call update_idletasks on the parent widget. 2) you need multi-threading if you want your interface to stay responsive or to be able to stop the search. Multi-threading is tricky. – Eric Levieil Jun 05 '15 at 23:04

1 Answers1

0

So, after 4 hours I hav solution.

First of all, all things connected GUI must be in main thread or you will be getting Tcl_AsyncDelete Error all time.

Thus, I created new class with my window.

class App(Frame):  
    def __init__(self, master, queue1):
        Frame.__init__(self, master)
        self.root = master
        self.root.title("Please, bear with me, for a moment : )")
        self.queue = queue1
        self.listbox = tk.Listbox(self.root, width=50, height=20)
        self.listbox.pack(padx=10, pady=10)
        self.running = 1
        self.periodiccall()

    def periodiccall(self):
        self.check_queue()
        if self.running:
            self._job = self.after(100, self.periodiccall)

    def check_queue(self):
        while self.queue.qsize():
            try:
                msg = self.queue.get(0)
                self.listbox.insert('end', msg)
                self.listbox.yview(END)
            except queue.Empty:
                # killing thread
                self.running = 0
                self.root.destroy()

In this class I'm checking what I have in queue and wright it in my listbox.

And I'm running get_music in new thread and giving information about what is going in thread to my Information Window through the Queue.

     def get_music(self):
        dir_name = filedialog.askdirectory(parent=self, initialdir="/",
                                           title='Please select a directory')
        thread = threading.Thread(target=self.do_staff, args=(dir_name,))
        self.config(cursor="wait")
        self.update()

     def do_staff(self, dir_name):
        for data in os.walk(dir_name):
            for filename in data[2]:
                self.list.insert(0,os.path.join(data[0], filename))
self.queue.put(filename)
Aleksander Monk
  • 2,787
  • 2
  • 18
  • 31