Prevent GUI from blocking
-
Hi, in my application I need to operate on a qt UI stuff heavily which blocks the GUI:
for(int i = start; i < end; i++) { QModelIndex index = tableview->model()->index(i,selectColNo); tableview->selectionModel()->select(index, QItemSelectionModel::Select); tableview->scrollTo(index); }
Since I cannot access and operate tableview from another thread, I tried the following:
for(int i = start; i < end; i++) { QModelIndex index = tableview->model()->index(i,selectColNo); tableview->selectionModel()->select(index, QItemSelectionModel::Select); tableview->scrollTo(index); if(i % 10 == 0) QCoreApplication::processEvents(); //Let GUI update occasionally }
Though slightly slow GUI respondings, this method works, may I ask the following questions:
-
Is calling QCoreApplication::processEvents(); the normal and standard way to keep GUI responsive? Any drawbacks of this method?
-
Based on my understanding, any codes running in main (GUI) thread after
return app.exec();
actually block the event loop for some time? Normally we don't see the GUI freezing because they just run for very short of times, when there are no codes running in the GUI thread, event loop can respond to GUI events without any blockings. The key to prevent GUI from freezing is to let GUI process events without blocked or without blocked for too long. -
How long we can block the GUI before it's frozen and not responding?
I am gradually understanding the event-driven nature of Qt, thank you very much
-
-
@StudyQt1
GUI "freezing" will happen if you a do a "lot" of time-consuming work in the GUI thread. Interpolating an occasionalprocessEvents()
does allow un-freeze, but complicates code as it may start servicing new events. If possible, we try to avoid ever calling it. Also calling it too frequently incurs a cost itself.Since I don't think selecting an index is that costly I would guess
QTableView::scrollTo()
is the culprit here, as it will require the table view to recalculate the whole layout in order to determine how to scroll something into view.If that is the case it is pretty pointless to select and then scroll into view one cell at a time. If it takes longer than the user can see/interact with the visuals it is unnecessarily time consuming. And mostly a later scroll-into-view is going to waste whatever work was done to have scrolled a previous item into view anyway. If your range is, say, 1,000 items that is an awful lot of wasted updates.
If you really want to do this, and want to avoid
processEvents()
, do one of:- Only
scrollTo()
after the last selection. - Create a
QTimer
ticking, say, once per second, or whatever. Split your range so that it only performs, say, 100 iterations on each timer tick, remember where you got to, and do the next batch on the next tick. This keeps the amount of blocking work down to a manageable amount so you do not notice the blocking.
How long we can block the GUI before it's frozen and not responding?
That is platform/windowing system dependent, Qt does not know. I think window managers put up a notice after a few seconds of non-response.
If you really, really have a lot of non-UI computation to do, consider moving that off to a
QThread
. Secondary threads can communicate with the main UI thread using signals & slots to keep the Ui responsive. But do not rush into this --- far too many beginners dive into threading when it's not needed and they don't understand the pitfalls. - Only
-
@StudyQt1 said in Prevent GUI from blocking:
for(int i = start; i < end; i++)
{
QModelIndex index = tableview->model()->index(i,selectColNo);
tableview->selectionModel()->select(index, QItemSelectionModel::Select);
tableview->scrollTo(index);}
What are you trying to achieve with this?
-
@jsulm Select multiple rows of tables and scroll to the row selected. Maybe it's not a good example, I just want to use this to understand the generic way to prevent GUI blocking when operating heavily on GUI stuff and to understand the nature of GUI freezing
-
@StudyQt1
GUI "freezing" will happen if you a do a "lot" of time-consuming work in the GUI thread. Interpolating an occasionalprocessEvents()
does allow un-freeze, but complicates code as it may start servicing new events. If possible, we try to avoid ever calling it. Also calling it too frequently incurs a cost itself.Since I don't think selecting an index is that costly I would guess
QTableView::scrollTo()
is the culprit here, as it will require the table view to recalculate the whole layout in order to determine how to scroll something into view.If that is the case it is pretty pointless to select and then scroll into view one cell at a time. If it takes longer than the user can see/interact with the visuals it is unnecessarily time consuming. And mostly a later scroll-into-view is going to waste whatever work was done to have scrolled a previous item into view anyway. If your range is, say, 1,000 items that is an awful lot of wasted updates.
If you really want to do this, and want to avoid
processEvents()
, do one of:- Only
scrollTo()
after the last selection. - Create a
QTimer
ticking, say, once per second, or whatever. Split your range so that it only performs, say, 100 iterations on each timer tick, remember where you got to, and do the next batch on the next tick. This keeps the amount of blocking work down to a manageable amount so you do not notice the blocking.
How long we can block the GUI before it's frozen and not responding?
That is platform/windowing system dependent, Qt does not know. I think window managers put up a notice after a few seconds of non-response.
If you really, really have a lot of non-UI computation to do, consider moving that off to a
QThread
. Secondary threads can communicate with the main UI thread using signals & slots to keep the Ui responsive. But do not rush into this --- far too many beginners dive into threading when it's not needed and they don't understand the pitfalls. - Only
-
@JonB said in Prevent GUI from blocking:
Only scrollTo() after the last selection.
Thank you for your help, as far as I understand from your reply. The general way is:
- Try to avoid heavy operations on UI stuff first, since UI stuff are not intended for heavy operations.
- If heavy operations are really necessary, then consider moving to work thread.
But in general, try to resolve within step 1, don't create another thread easily