我的应用程序有一个简单的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
- 但我在线程中有点新东西,所以请给出简单易懂的答案新手:)
答案 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的子类化)。另请查看QMutex和QMutexLocker,您可能需要它们。
答案 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
那样灵活,但它们的实施速度非常快。