0

I have a simple app that presents you with a button, when the button is pressed, some long running computations are done(not in a separate thread, there is no need for a separate thread as these computations are the sole reason of the app). These computations take place in a for loop and at every iteration, the for look has a callback to the main frame that updates it so it shows the current iteration(same with a small gauge underneath that fills up).

    def _delay(self):
            for i in range(15000):
                    self.update_stats(f'{i}', i)

    def on_button_click(self, event):
            self.init_completion_gauge(15000)
            self._delay()
            self.set_state_comparison_done()

    def init_completion_gauge(self, maxval):
            self.gauge.SetRange(maxval)
            self.Layout()
            self.Update()

    def update_stats(self, current_iter, count):
            self.label_current_iter.SetLabelText(
                    '\n'.join((f'Iter:', current_iter)))
            self.gauge.SetValue(count)
            self.label_percent_complete.SetLabelText(
                    f'{(count + 1) * 100 // self.gauge.GetRange()}%')
            self.Layout()
            self.Update()

When this runs, everything goes smoothly for a few seconds before the app shows Not responding in the title bar and hangs until it is complete. I don't mean is just hands and shows no error. Since the computations are done in the main loop it is intended for the app to block the main loop until they are done, but I doubt it is normal to randomly show not responding without being interacted with. After the computations are done the app behaves normally but it will stop responding at completely random points.

Any advice as to why this happens and what should be done to fix this?

3
  • 1
    use threads or wxThread. don't do anything (especially long-running) on the main (GUI) thread. Commented Jan 30, 2018 at 16:09
  • Why? I explained why I didn't use threads in my question so please tell me why is should use threads. Also, the behaviour is the exact same with or without threads. That was the first thing I have tried Commented Jan 30, 2018 at 18:44
  • ....because using threads will prevent the problem you are trying to solve.... Commented Jan 31, 2018 at 22:22

1 Answer 1

2

GUI updates are queued.
Let's suppose your code looks like:

myLongTask
{
    loop:
        ... do something
        UpdateGUI()
    end loop
}

Each time you call UpdateGUI() a message is sent to the OS, and the control returns inmediately and continues with the loop.

When has the OS the oportunity to handle that message? It's too busy running that loop.

You could use wx.Yield or better set a thread for the long task, that sends messages to the OS requesting update.

See more here

Sign up to request clarification or add additional context in comments.

3 Comments

So it stops because the queue becomes full? Meaning maybe a sleep 10 ms at the end of every loop would do the trick and let the os do it's thing? (I'm not actually thinking of using that, just trying to understand the underlying cause)
@RaresDima, you misunderstood. It's not that the queue becomes full. The main thread is busy doing you calculation in a loop and it doesn't have time/resources to update the GUI. It just impossible. As Rip2 suggested - use wx.Yield() to give the program an opportunity to update the GUI or use threads and send a message from the working thread to the main one to update the GUI. Basically you didn't give the program a chance to update the gauge - hopefully this sentence will clear it.
sleep just holds the current thread. If you only have one thread (i.e. the main one) it will hold and nothing will be done during sleep-lap, updating neither.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.