Qt GUI数学应用程序在计算时挂起了GUI

时间:2013-09-30 13:43:09

标签: c++ qt user-interface

我的应用程序有一个简单的GUI =我必须为我的数学函数设置一些输入参数,然后单击“计算”按钮,然后启动函数。数学函数是用纯C编写的,所以没有对象,只有函数。

看起来像这样:

#include "mymath.h"

class myMath : public QMainWindow
{
    Q_OBJECT

    // ...
    void compute();
};

void myMath::compute()
{
   //get parameters from gui
   call_C_fun();
   // save results to GUI
}

这段代码的主要问题是,当我点击“计算”时(它需要大量的计算,大约需要5分钟左右)它会挂掉我的GUI,所以我不能做任何事情(我可以​​'甚至看到我的GUI,窗口在计算运行的时间被“冻结”。在功能完成后,它在QLabel上打印出结果,GUI又一次“活着”。我怎么能解决这个问题?我不知道当计算需要时间时,我希望我的GUI被“冻结”。任何想法?我想到了QThread - 但我在线程中有点新东西,所以请给出简单易懂的答案新手:)

5 个答案:

答案 0 :(得分:6)

将计算分解为另一个线程,如下所示: -

// This is the object that will run the computation on a different thread
class Computation : public QObject
{
signals:
    void Finished();
public slots:
    void Compute();
};

然后在主窗口类中创建另一个线程并开始运行: -

class MyMath : public QMainWindow
{
    public:
        void StartComputation();
};


MyMath::StartComputation()
{
    QThread* pThread = new QThread;
    Computation* pComputation = new Computation;

    // move computation to the new thread
    pCompuation->moveToThread(pThread);

    // Note Qt5 connection style    

    // ensure the computation starts when the thread starts
    connect(pThread, &QThread::started, pComputation, &Computation::Compute); 
    // when computation is finished, quit the thread
    connect(pComputation, &Compute::Finished, pThread, &QThread::quit);
    // have the thread tidy up when finished
    connect(pThread, &QThread::finished, pThread, &QThread::deleteLater);
    // start it!
    pThread->start();
}

答案 1 :(得分:3)

尝试内置 QtConcurrent命名空间,而不是滚动自己的线程。它更容易,更优化,更不容易出错。无需担心将内容移动到其他线程并使用互斥锁执行显式同步。

QtConcurrent::run使用内部线程池来运行您的任务并返回QFuture,您可以使用QFutureWatcher和信号&插槽。名称可能听起来很复杂,但代码很简单:

class MyMath : public QObject 
{
    Q_OBJECT
public:

    explicit MyMath(QObject* parent) : QObject(parent) {
        this->watcher = new QFutureWatcher(this);
        connect(this->watcher, SIGNAL(finished()),
                this, SLOT(computationFinished()));
    }

public slots:

    void compute() {

        // This one is called by the user. Retrieve
        // the computation arguments (whatever they
        // may be), start the computation using 
        // QtConcurrent::run and prepare to receive
        // the results. 
        // 
        // Maybe update the UI to tell the user that 
        // the computationis being performed?

        Args args = getSomeArgs();
        QFuture<Result> res = QtConcurrent::run(this, &MyMath::internalCompute, args);
        this->watcher->setFuture(res);
    }

    void computationFinished() {
        // The computation is done. Update the GUI
        // to display the results. Done.
    }

private:

    QFutureWatcher<Result>* watcher;

    Args getSomeArgs() const {
        // return arguments needed by compute.
    }

    Result internalCompute(Args args) const {
        // perform very expensive math.
    }
};

更新。在Merlin069的评论之后,我认为推荐使用QtConcurrent提供的更复杂的操作是不明智的。

答案 2 :(得分:2)

在您的情况下,线程将是一个解决方案。您的计算将在一个单独的线程中运行,这样可以让您的GUI在计算您需要的任何内容时做出响应。

根据我的经验,这是关于GUI的常见问题。 GUI有自己的线程,你的逻辑使用自己的线程。

您可以使用非常简单的模式处理此问题,使用来自启动工作人员的GUI的信号,以及来自触发GUI中更新的工作人员的信号。

您需要注意常见的线程安全问题。我强烈建议你学习一下线程,以便更好地掌握你正在做的事情。它还可以帮助您理解使用线程代码时可能发生的奇怪行为(对于不熟悉它的人来说,这并不总是微不足道的。)

我还建议你阅读QThread documentation,它很好地解释了如何在Qt中实现线程代码(更喜欢单独的worker到Qthread的子类化)。另请查看QMutexQMutexLocker,您可能需要它们。

答案 3 :(得分:2)

Qt GUI数学应用程序在计算时挂起GUI

我的应用程序有一个简单的GUI ... ..

这段代码的主要问题是,当我点击“计算”时(计算量太大,需要5分钟左右)它会挂掉我的GUI,所以我什么也做不了(我甚至看不到我的GUI,窗口在计算运行的时候被“冻结”。在功能完成后,它在QLabel上打印出结果,GUI又一次“活着”。我该如何解决这个问题?我不希望我的GUI在计算需要时间时被“冻结”。任何想法?我想到了QThread - 但我在线程中有点新东西,所以请为新手提供简单易懂的答案:)

您的程序(GUI)似乎永远不会挂起。它继续使用'compute()'函数的'call_C_fun()'进行处理。但GUI不响应。请参阅{{3>}处的保持GUI响应的参考。 在长时间操作期间GUI的冻结的反复出现的问题可以处理许多方法。但最简单的方法是手动事件处理

要使用手动事件处理,必须在循环中定期调用 QCoreApplication :: processEvents()

以下示例显示了如何工作:

call_C_fun(){
....
while(Your_loop_condition) {
    ....
    QCoreApplication::processEvents();
    if (!your_compute_button->isChecked()) {
        //"Aborted"
        return;
    }
}
....
}

答案 4 :(得分:1)

作为完整QThread解决方案的替代方法,您还可以使用QEventLoop创建单独的事件循环来运行计算,以保持主事件循环(托管UI)免费。它不像QThread那样灵活,但它们的实施速度非常快。