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 calls QStackedWidget::setCurrentIndex , which sets the current widget to index-th widget. The widget itself has a nested QStackedWidget and thus it further calls setCurrentWidget to set the current nested widget. However, none of setCurrentIndex and setCurrentWidget 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.


  • Lifetime Qt Champion

    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 emit customSignal.



  • 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.


  • Lifetime Qt Champion

    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 ?


  • Lifetime Qt Champion

    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.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.