Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Keeping GUI responsive

    General and Desktop
    3
    10
    6655
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • X
      xiit last edited by

      Hi again!

      Basically I want to keep my GUI responsive while, for example, processing data in a loop. So I guess I would have to do that processing in another thread.

      If I want to wait for a thread to finish before continuing in my main thread I would have to use a QEventLoop, right?

      Here is my code which creates a new thread and does what it should, but doesn't seem to exit the QEventLoop ("end" doesn't get printed out):

      @ MyWorker w;
      QThread t;
      QEventLoop l;

          connect(&t, &QThread::started, &w, &MyWorker::doLotsOfStuff);
          connect(&t, &QThread::finished, &l, &QEventLoop::quit);
      
          qDebug() << "begin";
      
          w.moveToThread(&t);
      
          t.start();
          l.exec&#40;&#41;;
      
          qDebug(&#41; << "end";@
      

      What am I doing wrong?

      Help is appreciated! :)

      1 Reply Last reply Reply Quote 0
      • Chris Kawa
        Chris Kawa Moderators last edited by

        t.start() calls QThread::run() in another thread, which in default implementation just calls exec(). What that means is that your thread never actually finishes and keeps going in circles after finishing doLotsOfStuff. You would need to call something like QThread::currentThread().quit() at the end of doLotsOfStuff or do something like
        @
        connect(&w, &MyWorker::someFinishedSignal, &t, &QThread::quit());
        @

        1 Reply Last reply Reply Quote 0
        • X
          xiit last edited by

          Oh, that makes things more clear. Thank you very much!

          1 Reply Last reply Reply Quote 0
          • A
            andre last edited by

            Take a look at the "example":/doc/qt-5.0/qtcore/qthread.html#details in the documentation.
            You don't need the event loop in here. Instead, create your thread and your worker on the heap (using the new keyword) and listen for a signal from your worker when it is done.

            1 Reply Last reply Reply Quote 0
            • X
              xiit last edited by

              Alright, I skipped the QEventLoop.

              What if I want to cancel what the thread is processing (i.e exit a loop)?

              I've added a signal to MainWindow called "abort()", added a slot to MyWorker called "abort()" and connected the both with:

              @connect(this, &MainWindow::abort, w, &MyWorker::abort);@

              And then when I click a button, I emit the signal with:

              @emit abort();@

              But whatever is in the "abort()" slot of MyWorker doesn't get executed.

              Is this the wrong way of doing it?

              1 Reply Last reply Reply Quote 0
              • A
                andre last edited by

                No, that is ok in principle. However, it only works if your thread actually returns to the event loop.

                1 Reply Last reply Reply Quote 0
                • X
                  xiit last edited by

                  [quote author="Andre" date="1360167554"]No, that is ok in principle. However, it only works if your thread actually returns to the event loop.[/quote]

                  Would you like to elaborate on this one? :)

                  1 Reply Last reply Reply Quote 0
                  • A
                    andre last edited by

                    For slots to work in a thread, the thread needs a running event loop. That means: exec() must have been called on it (done by default, so a vanilla QThread has one) and the thread must not be stuck in a busy loop.

                    If your thread is doing some huge calculation in one big chunk, and it thus never returns to the event loop, the event that wraps the signal will never be processed, and thus the slot won't be called. It is the same in the main event loop: if you do something very big, or do a busy wait or something like that, events won't be processed anymore, and your application will appear unresponsive to the user.

                    So, if you want to use a signal/slot for an abort, you will need to have a thread that stays responsive and regulary returns to the event loop. Note that you could probably also call processEvents() from within your loop or other time consuming procedure to reach the same effect. Not the nicest solution though.

                    As an alternative, considder creating a normal abort() method, that just sets a flag that you check from your time consuming procedures. Best use a QAtomicInt for such a flag.

                    1 Reply Last reply Reply Quote 0
                    • X
                      xiit last edited by

                      Wow, thanks Andre!

                      So basically I should just add a method to MyWorker (and call it with worker->abort()) and that would work just fine?

                      Just out of curiosity (and because my knowledge is pretty inadequate), why use a QAtomicInt instead of say, a boolean or normal integer as a "flag"?

                      Sorry for my stupidity. :)

                      1 Reply Last reply Reply Quote 0
                      • A
                        andre last edited by

                        The check for the bool flag would be optimized out, as there is no code to change it inside the loop where it is checked over and over again. That doesn't happen with a QAtomicInt.

                        1 Reply Last reply Reply Quote 0
                        • First post
                          Last post