0

Using PyGubu (tool to create Tkinter interfaces) I obtained the following GUI: enter image description here

Current situation:

When I click the Button "Create", a function is called. This function takes quite some time, and the graphical interfaces is just frozen. As I would like to keep the graphical interface and the functional part as much separated as possible, I don't want to update the Progress Bar or the interface in general from the function I call

Desired situation

The best case for me would be a solution without Threading: I would like, upon clicking "Create", that my function runs, while the Progress Bar updates itself (just to show a feedback to the user, and to tell him "look, I am doing something") and the interface remains responsive, so the user can actually interact with it while the function finish.

Current attempts

I tried to solve this using Threading:

#I have this code in my main.py:
from threading import Thread 
from queue import Queue, Empty
my_queue=Queue()

#And this is a simplified version of the Command of the "Create" Button:
def create_command(self):
    #Show the progress bar and start it
    self.show_item(self.progress)
    self.progress.start()

    #Run the big function
    thrd = Thread(target = my_big_function, args=(some_arguments, my_queue))
    thrd.start()

    
    do_retry = True
    while do_retry:                      #Repeat until you have a result
        try:
            result = my_queue.get(False) #If you have a result, exit loop. Else, throw Empty
            do_retry = False
        except Empty:                    #Queue is still empty
            self.progress_var.set(self.progress_var.get()+1)
            sleep(0.05)
            self.mainwindow.update()     #Update the progress bar
 
    q.task_done()                        
    self.progress.stop()

Problem of the current attempt

As I am not used to work with threads, I am facing two problems:

  1. In some runs (not all of them, just some) I have a RuntimeError stating

    RuntimeError: main thread is not in main loop I tried to overcome this looking at other question in StackOverflow, but now it just happens randomly, and I don't know how to avoid it. The module mtTinker is no more maintained for python 3.x (there is a vague attempt full of ToDoes and blood)

  2. If there is some kind of exception in the big function, I don't know how to handle it. The program would just run forever waiting for a result that will never come back

So

How can I obtain my desired outcome? Thanks in advance

Community
  • 1
  • 1
Federico Dorato
  • 710
  • 9
  • 27
  • See my answer to the question [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). – martineau Apr 03 '20 at 11:38
  • @martineau I will test it for myself, but it's probably what I was searching for. Should I flag this question as a duplicate? Thanks a lot! – Federico Dorato Apr 03 '20 at 11:58
  • @martineau In your example the logic is "Start the GUI and start a separate thread. When the separate thread has some results, the GUI will interact with them". My case is different: the start of the separate thread should start when a Button is pressed, and the thread will use information provided by the GUI. Once the separate thread has done what it needs to, I don't need it anymore. So the example is quite far away from what I need – Federico Dorato Apr 06 '20 at 08:37
  • 1
    Federico: I believe it would be possible (and relatively simple) to not start the separate non-GUI thread until a `Button` was pressed as well as use information provided via the GUI to the thread when it's started. – martineau Apr 06 '20 at 13:41
  • @martineau Yeah, you are probably right. I am not used to Tkinter, and honestly I was hoping to find some kind of quick solution (after all looks like many people had troubles in using many threads with tkinter). The point is that I am just trying to send to the user the idea of "the program is not broken, it's just loading". If I use even just a couple of hours to do this, well, it would be a waste... I could just use a popup before running the long function. I find strange that you cannot have a simple loading progressbar while you run a task, it is not intuitive. – Federico Dorato Apr 07 '20 at 09:14
  • I think you could probably find out how to implement such as progressbar if you spent some time looking for it on this site (or via google). One problem with your question is there too much unrelated information which obscures what you're really asking. – martineau Apr 07 '20 at 09:22

1 Answers1

-1

You can try adding root.update() inside the function you call, inside the main loop. Hope that's helpful!

rizerphe
  • 1,340
  • 1
  • 14
  • 24