GUI Freeze in loop



  • Hello.

    I have a loop in my code for reading a .txt file. When reading that file the GUI freezes, i tried

    QCoreApplication::processEvents();
    

    But it still freezes. Can someone give me a tip on how to run this on a separate thread or something like this?

    if (!file.open(QIODevice::ReadOnly))
        {
           qDebug() << file.errorString();
           ui->textBrowser->append(file.errorString());
        }    
        while (!file.atEnd())
        {
           QByteArray line = file.readLine();
           wordList.append(line.split(',').first());
          //  QCoreApplication::processEvents();
        }
    

    Thanks.


  • Qt Champions 2016

    Hi
    Im a bit surprised it still lagged with processEvents()

    Anyway, you can use a worker object and run that in a thread.
    It can then emit signal to tell main its finished.

    http://wiki.qt.io/QThreads_general_usage


  • Moderators

    @jemazter Yea you definitely want your heavy non GUI operations in their own threads. This will keep your GUI responsive even under load.

    Qt makes this quite easy (well as easy as threading ever can be) and mrjj sent ya a link to that.

    If you need help with the threading or don't understand the docs, let me know and I can show you an example.



  • @jemazter You can also check the QtConcurrent Word Count Example.



  • @ambershark

    Hi. If you can show some examples i would appreciate it, i read the documentation but still didn't understand it quite well.


  • Moderators

    @jemazter Yea threading is complicated. Even when Qt makes it easy, it is still tricky.

    I'll write up a quick little program to show you how to do it.


  • Moderators

    @jemazter Ok here is a fully working example... Please note that the thread will create a 1GB file in order to cause enough delay so you can see the GUI is still responsive. It is called deleteme.txt. Make sure to clean it up. :)

    tmp.pro:

    TEMPLATE = app
    TARGET = tmp
    INCLUDEPATH += .
    QT += gui widgets
    
    # Input
    HEADERS += window.h worker.h
    SOURCES += main.cpp window.cpp worker.cpp
    

    main.cpp:

    #include <QApplication>
    #include "window.h"
    
    int main(int ac, char **av)
    {
            QApplication app(ac, av);
            Window w;
            w.show();
            return app.exec();
    }
    

    window.h:

    #ifndef window_h
    #define window_h
    
    #include <QWidget>
    
    class QProgressBar;
    class QPushButton;
    
    class Window : public QWidget
    {
            Q_OBJECT
    
    public:
            Window(QWidget *parent=0);
            virtual ~Window();
    
    private:
            void startProgress();
            QProgressBar *pb_;
            QPushButton *button_;
    
    private slots:
            void threadDone(bool success);
    };
    
    #endif
    

    window.cpp:

    #include "window.h"
    #include <QPushButton>
    #include <QTextEdit>
    #include <QVBoxLayout>
    #include <QThread>
    #include <QProgressBar>
    #include <QMessageBox>
    #include "worker.h"
    
    Window::Window(QWidget *parent)
            : QWidget(parent)
    {
            // set up our gui
            auto layout = new QVBoxLayout();
            button_ = new QPushButton("Start Thread");
            auto textEdit = new QTextEdit(); // this is here to type in while the thread run
    s to test responsiveness
            pb_ = new QProgressBar();
            layout->addWidget(textEdit);
            layout->addWidget(pb_);
            layout->addWidget(button_);
            setLayout(layout);
    
            // set up the thread for our worker and move it to the thread
            auto worker = new Worker();
            auto thread = new QThread();
            worker->moveToThread(thread);
    
            // starts writing a file when start thread is clicked
            connect(button_, &QPushButton::clicked, worker, &Worker::doSomething);
    
            // starts a progress bar and disables start thread button
            connect(button_, &QPushButton::clicked, this, &Window::startProgress);
    
            // tells our window here that our thread is done
            connect(worker, &Worker::finished, this, &Window::threadDone);
    
            // cleans up memory
            connect(worker, &Worker::finished, thread, &QThread::quit);
            connect(worker, &Worker::finished, worker, &Worker::deleteLater);
            connect(worker, &Worker::finished, thread, &QThread::deleteLater);
    
            thread->start();
    }
    
    Window::~Window()
    {
    }
    
    void Window::threadDone(bool success)
    {
            // stop progress bar
            pb_->setMaximum(100);
            pb_->setValue(100);
    
            if (success)
                    QMessageBox::information(this, "Result", "Success!");
            else
                    QMessageBox::information(this, "Result", "Failure!");
    }
    
    void Window::startProgress()
    {
            // disable our start button
            button_->setEnabled(false);
    
            // set our progress bar to "busy" mode
            pb_->setMinimum(0);
            pb_->setMaximum(0);
    }
    

    worker.h:

    #ifndef worker_h
    #define worker_h
    
    #include <QObject>
    
    class Worker : public QObject
    {
            Q_OBJECT
    
    public:
            Worker();
    
    public slots:
            void doSomething();
    
    signals:
            void finished(bool success);
    };
    
    #endif
    

    worker.cpp:

    #include "worker.h"
    #include <QFile>
    
    Worker::Worker()
    {
    }
    
    void Worker::doSomething()
    {
            // write a 1000MB file byte by byte
            // that should take long enough to test this
    
            QFile f("deleteme.txt");
            if (!f.open(QIODevice::Text | QIODevice::WriteOnly))
            {
                    // we failed..
                    emit finished(false);
            }
    
            auto size = 1024*1000000;
            for (auto i=0;i<size;++i)
            {
                    f.write("1");
            }
    
            f.close();
            emit finished(true);
    }
    

    Hope that helps, let me know if you need any part explained. :)


Log in to reply
 

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