Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [Solved] GUI unresponsive during intensive computation
QtWS25 Last Chance

[Solved] GUI unresponsive during intensive computation

Scheduled Pinned Locked Moved General and Desktop
11 Posts 4 Posters 4.7k Views
  • 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.
  • J Offline
    J Offline
    Jyang772
    wrote on last edited by
    #1

    I am writing a program that displays/calculates checksums for all files in the current directory and all directories under it. The problem is, as QDirIterator is going through all of the files calculating checksums, the GUI freezes and turns grey. GUI will only become responsive again after the function has finished.

    How do I implement threading so that the GUI remains responsive while the function is running?

    This is what I have right now. It doesn't seem to work, since if I replace the function with a for loop, the GUI is still not responding until the for loop finishes.

    MainWindow.cpp
    @
    MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);
    ui->textBrowser->setFont(QFont("Monospace",11));
    ui->textBrowser->setLineWrapMode(QTextEdit::NoWrap);

    updater->moveToThread(pthread);
    connect(this,SIGNAL(getHash()),updater,SLOT(getHash()));
    connect(updater,SIGNAL(req()), this, SLOT(getCheckSum()));
    connect(updater,SIGNAL(Finished()),pthread,SLOT(quit()));
    connect(pthread, SIGNAL(finished()), updater, SLOT(deleteLater()));
    

    }@

    MainWindow.h
    @
    private:
    Ui::MainWindow *ui;
    QByteArray sig;
    QString buffer;

    QThread *pthread = new QThread(this);
    GUIUpdater *updater = new GUIUpdater();
    

    @

    When user presses button:
    @
    void MainWindow::on_pushButton_clicked()
    {
    pthread->start();
    emit getHash();
    }
    @

    doWork() will work, but how do I call a function in MainWindow?
    Worker.h
    @
    void getpHash(){ emit req();}

    void doWork()
    {
        while(1)
            qDebug() << "Sleeping";
    }
    

    @

    1 Reply Last reply
    0
    • F Offline
      F Offline
      frankiefrank
      wrote on last edited by
      #2

      I don't see how your MainWindow.h code would compile - are you trying to initialize the thread and the updater members there?

      If I understand correctly, you have a worker thread, and you want to notify the main UI thread that it finished work with a certain result? You can emit a signal from that worker thread, and connect that signal to a slot in your main window.

      "Roads? Where we're going, we don't need roads."

      1 Reply Last reply
      0
      • J Offline
        J Offline
        Jyang772
        wrote on last edited by
        #3

        Hi,
        I want to run a member function from MainWindow in a different thread. Is that possible?

        @
        MainWindow::getHash()
        @

        I only included the private member declaration part of MainWindow.h.

        1 Reply Last reply
        0
        • F Offline
          F Offline
          frankiefrank
          wrote on last edited by
          #4

          If you have something happening in a worker thread, can't you pass it all the information so that it does all the work in that thread?

          If getHash() is public, and you pass a pointer to your worker thread so that it can access the MainWindow object, then you can call getHash() and it will be executed in the worker thread. But I think this is really complicating things.

          "Roads? Where we're going, we don't need roads."

          1 Reply Last reply
          0
          • D Offline
            D Offline
            DBoosalis
            wrote on last edited by
            #5

            If you have a long procedure, perhaps executing a for loop, sprinkle some of these in your code

            qApp->processEvents(QEventLoop::ExcludeSocketNotifiers,10);

            This will give the app a few (10 in this case) milliseconds to handle window events

            A better way would be do put rethink your worker thread so it does not block

            1 Reply Last reply
            0
            • J Offline
              J Offline
              Jyang772
              wrote on last edited by
              #6

              Okay, so I copied everything from the MainWindow::getHash() function over to a member function in the worker object. Then I connected a signal/slot and it works.

              However, I would rather just have the function be a member function of MainWindow.

              [quote author="frankiefrank" date="1401064145"]If you have something happening in a worker thread, can't you pass it all the information so that it does all the work in that thread?

              If getHash() is public, and you pass a pointer to your worker thread so that it can access the MainWindow object, then you can call getHash() and it will be executed in the worker thread. But I think this is really complicating things.[/quote]

              How would I pass a pointer to the worker thread?

              1 Reply Last reply
              0
              • F Offline
                F Offline
                frankiefrank
                wrote on last edited by
                #7

                From the code parts you posted I understand you have your Updater object which you move to the worker thread. You can store a pointer to MainWindow as a member of Updater, and set it via the constructor.

                Of course, if you access the same code both in the Main UI thread and in the worker thread - without any thread safety mechanics - you may end up in trouble.

                "Roads? Where we're going, we don't need roads."

                1 Reply Last reply
                0
                • J Offline
                  J Offline
                  Jyang772
                  wrote on last edited by
                  #8

                  I see.
                  So just to be clear, is there no other way of having MainWindow::function() run in a different thread?

                  I would either have to pass a pointer to a MainWindow object or just implement MainWindow::function() as a member function of the worker class?

                  1 Reply Last reply
                  0
                  • F Offline
                    F Offline
                    frankiefrank
                    wrote on last edited by
                    #9

                    Maybe there are other ways, I can't think of them right now and even these ones may be a bit too complicated for the problem you presented.

                    "Roads? Where we're going, we don't need roads."

                    1 Reply Last reply
                    0
                    • J Offline
                      J Offline
                      Jyang772
                      wrote on last edited by
                      #10

                      [quote author="frankiefrank" date="1401090123"]Maybe there are other ways, I can't think of them right now and even these ones may be a bit too complicated for the problem you presented.[/quote]

                      I did some more reading and @Qtconcurrent@ seems to work.

                      1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        adolby
                        wrote on last edited by
                        #11

                        I'd recommend separating your business logic/algorithm methods from your GUI classes. This would allow you to follow the object-oriented single responsibility principle better.

                        If you moved your getHash function to a class of your own that inherits from QObject, you will be able to do something like this:

                        @MainWindow::MainWindow(QWidget *parent) :
                        QMainWindow(parent),
                        ui(new Ui::MainWindow)
                        {
                        ui->setupUi(this);
                        ui->textBrowser->setFont(QFont("Monospace",11));
                        ui->textBrowser->setLineWrapMode(QTextEdit::NoWrap);

                        // Make sure not to parent updater, so you can move it to a thread
                        GUIUpdater* updater = new GUIUpdater();
                        QThread* pthread = new QThread(this);
                        
                        updater->moveToThread(pthread);
                        connect(this,SIGNAL(getHash()),updater,SLOT(getHash()));
                        connect(updater,SIGNAL(req()), this, SLOT(getCheckSum()));
                        connect(updater,SIGNAL(Finished()),pthread,SLOT(quit()));
                        connect(pthread, SIGNAL(finished()), updater, SLOT(deleteLater()));
                        

                        }@

                        To call a slot in MainWindow from an updater method, you can use signal and slots like the req() signal you connected in the MainWindow constructor. This will be an asynchronous method call; when you emit the signal from updater, execution will continue in the updater method. The main/GUI thread will have the slot waiting in its event queue.

                        If you need a direct function call, in the case where the timing is important or the doWork method needs a return value from a class on the main/GUI thread (in your case, MainWindow), I would recommend refactoring your doWork method. Make the place where you emit the signal to cause the main/GUI thread to compute be the last line of your doWork method. Then, in the class on the main/GUI thread (MainWindow), your slot will do your computation, and then emit a new signal that will be connected to a new slot containing the rest of the code that was previously in your doWork method after the signal emission.

                        It will look like this:
                        @MainWindow::MainWindow()
                        {
                        connect(worker, SIGNAL(doGUISlot()), this, SLOT(doImportantComputation()));
                        connect(this, SIGNAL(doRestOfWorkSlot()), worker, SLOT(finishWork()));
                        }

                        Class::doWork()
                        {
                        // Do the first part of your work here, then emit to allow GUI to compute. GUI will signal when it's done to
                        // cause finishWork to be executed

                        emit doGUISlot();
                        

                        }

                        MainWindow::doImportantComputation
                        {
                        // Do computation here, then go back to Worker::finishWork

                        emit doRestOfWorkSlot();
                        

                        }

                        Class::finishWork()
                        {
                        // Finish work
                        }@

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved