Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fool Windows into thinking that your application is still busy, although it's not responding

Tags:

windows

qt

My application is a windowing application that performs certain complex mathematical algorithms. Because I started with the application a long time ago, most of it is still single-threaded. To be more precise, the main thread executes all the complex calculation logic. It's important to mention that during the calculations, I show some progress on the screen.

In most cases, the mathematical algorithms only take several seconds, so after the user has started the action, an hourglass (or the running circle in Windows 7) is shown, and a few seconds later the results are shown.

In some cases, the algorithm can take several minutes. During this time, I show the hourglass, and while the algorithm is busy, I show the progress in my window. But, if the user clicks in the application after it has been busy for a while, the Window becomes 'more white' (as if a non-completely-transparent piece of plastic is laid over the window), the Window is not updated anymore, and Windows reports 'the application is not responding'.

I use Qt and I use the Qt function QWidget::repaint to force a repaint while my algorithm is busy. The repaint works for some time, but as said above, Windows seems to block this after a while.

What is the correct way to tell Windows that your application is still busy so that the window keeps on updating? If I enter an explicit message loop, the user might trigger other actions in the application which I don't want.

  • Is it enough to call PeekMessage?
  • It is enough to call GetMessage?
  • Or should I call DispatchMessage? And how do I prevent the user from starting another action (actually, prevent all user input)
  • Should I call one of these messages every time I update my window, or can I limit myself to call it every few seconds (10 seconds?, 30 seconds? ...)

Notice that moving the calculation logic to a separate thread is currently not an option.

I'm using Visual Studio 2010 on Windows 7, in combination with Qt 4.7.

like image 754
Patrick Avatar asked Dec 07 '11 08:12

Patrick


3 Answers

You should separate the GUI from the application logic. All other solutions are hacks. Moving the calculation logic to a separate thread can easily be achieved with Qt using minor effort.

I assume that there is a function (lets call it execute()) that when called performs all these time consuming mathematical operations. One option is to use the Qt Concurrent API for calling this function in a separate thread, without using low-level thread handling.

What you need is the QtConcurrent::run function :

The QtConcurrent::run() function runs a function in a separate thread. The return value of the function is made available through the QFuture API.

Instead of simply calling execute() which will block your User Interface you can do the following (let A be the class in which execute() is defined):

QFuture<void> future = QtConcurrent::run(this, &A::execute);

You can use QFutrureWatcher in order to get notified about when the function has finished.

like image 178
pnezis Avatar answered Oct 10 '22 02:10

pnezis


You could simply call QApplication::processEvents() from time to time, say every 2 or 3 seconds or so. That should trigger a repaint event and refresh your progress bar and other elements.

like image 37
laurent Avatar answered Oct 10 '22 00:10

laurent


Similar question and lots of info here: I need a message pump that doesn't mess up my open window

However, as you probably already know, this is quite a hack and it would be better to try to move the code to another thread. Why is this "not an option"?

like image 33
swinefeaster Avatar answered Oct 10 '22 02:10

swinefeaster