QStackedWidget::setCurrentWidget has no effect
-
I have a navigation setup inside the application using
QStackedWidget
. I am using Qt 5.9.0 with MSVC 2015. On clicking a button, the slot callsQStackedWidget::setCurrentIndex
, which sets the current widget to index-th widget. The widget itself has a nestedQStackedWidget
and thus it further callssetCurrentWidget
to set the current nested widget. However, none ofsetCurrentIndex
andsetCurrentWidget
works. Also, in the slot emits a signal, whose handler does a similar change, which happens fine.QObject::connect(button, &QPushButton::clicked, [this](bool toggle){ topStackedWidget->setCurrentIndex(some_index); //nothing happens childStackedWidget->setCurrentWidget(waiting_animation_widget); //nothing happens // ...some time taking operation... emit customSignal(); // The slot for this signal also calls setCurrentIndex/Widget on topStackedWidget which works fine...
Nothing happens here implies that the widget in view does not change, it remains the same.
-
Hi,
The important line is:
// ...some time taking operation...
. You are likely blocking the event loop thus your stacks don't have the possibility to update before you emitcustomSignal
. -
What should then be the approach? Delegate the operation to a separate thread? i.e. spawn a QThread, let it finish, wait for the thread finished signal and continue ? Also, note that the operation can throw exceptions which I need to display in the GUI.
-
Yes, you should encapsulate that work properly using e.g. the worker object approach.
For the GUI update in case of an error, design your worker object or QThread based object so that it emit a signals to signal an error and also an accessor function to retrieve the information you want to show.
-
I created a worker object based on this:
class Worker : public QObject { Q_OBJECT; public: void operate() { bool ret; try { ret = expensive_op(); } catch (...) { emit error(code); ret = false; } emit done(ret); } signals: void done(bool); void error(int); };
In my GUI class, I have a QThread instance. So, in the slot where I need to do the operation, the code is as follows:
void myslot() { // ... code updating the stacked widget... auto worker = new Worker; worker->moveToThread(m_thread); // ... code for handling the signals error and done m_thread.start(); worker->operate(); }
However, the result is identical, the QStackedWidget is not updated. I think I must be doing something wrong/not understanding the worker/QThread model. What is the correct approach ?
-
The error is the way you call operate. Moving your object in another thread won't help if you still call the expensive operation yourself from the main thread. You should connect the QThread::started signal to your Worker operate method which you should make a slot.
-
Thank you for the guidance! I got it working.