2

I have made a python program based on Tkinter that analyses a CSV file and returns a PDF file. If there is a big CSV file, the tkinter window will freeze until the process is done. This is not desirable and instead I would like to introduce an indeterminate progress bar that disappears when a question is prompted for the user and then reappears when more processing is followed. I have read that somehow it needs a different thread, but I am quite stuck.

My program looks like:

import threading
from time import sleep
import tkinter as tk
import tkinter.ttk as ttk


root = tk.Tk()
root.title('text')
label = tk.Label(text = 'text')
label.pack()


class myThread(threading.Thread):
    def __init__(self, threadID):
        threading.Thread.__init__(self)
        self.threadID = threadID
    def run(self):
        func()


def func():
    #some processing
    #ask the user a question and based on the answer more processing will be done
    if True:
        #more processing1
        sleep(1)
    else:
        #more processing2
        sleep(1)

def check_thread(th):
    if not th.isAlive():
        root.destroy()
    root2.after(100, check_thread, th)


root2 = tk.Tk()
root2.title("New Top Level")
root2.geometry("400x170")

tk.Label(root2, text='Doing some work', justify=tk.CENTER, bg="#CBFDCB").place(x=43, y=30)
progress_bar = ttk.Progressbar(root2, orient="horizontal",
mode="indeterminate", takefocus=True, length=320)
progress_bar.place(x=40, y=80)
progress_bar.start()

thread1 = myThread(1)
thread1.start()

root2.after(100, check_thread, thread1)
root2.mainloop()

Button1 = tk.Button(root, text="sample", padx=10,
                    pady=5, fg="white", bg="#263D42", command=func)
Button1.pack()

root.mainloop()

Edit1: I have updated it with the version of the progress bar I was trying to use.

martineau
  • 119,623
  • 25
  • 170
  • 301
tmg28
  • 25
  • 7
  • 2
    Use another thread to set a global variable which can hold the progress. Then use a `tkinter` `.after` loop like [this](https://stackoverflow.com/a/459131/11106801) one to set the value of the progressbar – TheLizzard Sep 08 '21 at 21:00
  • 2
    What part exactly are you stuck on? – martineau Sep 08 '21 at 22:08
  • I have tried to follow an example which uses sleep() and after I have read more I understood sleep is not compatible to Tkinter. When I tried that nothing worked anymore; the initial window didn't appear. So basically I am back at step 1. – tmg28 Sep 09 '21 at 12:39
  • As I am quite new to Python, I have tried to look for examples related about ProgressBar and after method but couldn't find anything that I could use or get inspiration. – tmg28 Sep 09 '21 at 12:42
  • When you respond to someone please put @their_user_name in your reply so they will be notified. Regarding your question: Please put what you have attempted in it to make it easier for someone to show you either how to fix it or how to use a different approach to accomplish the goal. – martineau Sep 09 '21 at 18:38
  • 1
    @martineau I have updated the post with the approach that I have tried. – tmg28 Sep 10 '21 at 11:17
  • 1
    `tkinter` is **not** thread-safe, in the sense that you can't have two different threads interacting with it (even if each creates its own `Tk` instance). This doesn't mean you can't have multiple threads, but that only one of them can be or have a GUI based on it. See [my answer](https://stackoverflow.com/a/53697547/355230) to [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 a sample/template showing how to do that. – martineau Sep 10 '21 at 17:37
  • @martineau Thank you! Does that mean that I cannot have two GUIs (one for the main window and one for progress bar)? – tmg28 Sep 11 '21 at 20:17
  • 1
    I think it's possible via *one* GUI with two windows — you can create a 2nd window as a [`Toplevel`](https://anzeljg.github.io/rin2/book2/2405/docs/tkinter/toplevel.html) widget to put the progress bar with some buttons or whatever in it, as long as it's all done in same thread that has the default window. The tricky part will be communicating with the thread that's doing analysis of the CSV file and creating the PDF. In the example I linked to this is done via a `Queue` which the main thread running the GUI periodically polls using the `after()` universal widget method. – martineau Sep 11 '21 at 22:18
  • @martineau I have followed your suggestion and the software is not freezing anymore. Thank you. However, the function starts automatically, but I want the function to be started by pressing a button and also having more functions to be called. I have tried to added the functions under while self.running, but that did not work. – tmg28 Sep 13 '21 at 18:01
  • 1
    You can add more buttons to the `GuiPart` or to a separate `Toplevel` window if one exists. These buttons can have commands which launch various thread functions. For simplicity they can all share the same queue for communications. – martineau Sep 13 '21 at 19:51
  • @martineau Thanks for all your help until now. I have added buttons in the GuiPart as you suggested; for ex: self.button1 = tk.Button(master, text="text", command=ThreadedClient.worker_thread1) then sellf.button1.pack(). However, the processing starts automatically as the window open without pressing the button. Can you please help me to fix that? – tmg28 Sep 14 '21 at 12:52
  • That looks like what I was suggesting (and what a comment in the `GuiPart` of the linked answer says to do, too). If you're a happy camper now, the best way to say thanks around here is by up-voting answers (even if they are to other questions ;¬). – martineau Sep 14 '21 at 13:01
  • @martineau I have tried to up-vote, but unfortunately I don't have the possibility to do it. I have read that I need a score of at least 15 to allow me to do it, but my score is only 11. – tmg28 Sep 14 '21 at 17:14
  • No worries (problem fixed). – martineau Sep 14 '21 at 17:19
  • @martineau Thank you! I have up-voted your answer. – tmg28 Sep 14 '21 at 17:31

0 Answers0