使用 Qt GUI 打包线程程序

Packaging a threaded program with Qt GUI

本文关键字:线程 程序 包线程 Qt GUI 使用      更新时间:2023-10-16

我有一个工作完成的应用程序,它使用多个加速线程并且可以在命令行界面上正常工作。

我用"包装器"类打包了这个程序,以便我可以从Qt主窗口运行程序中的函数。

例如:

netWrap.getImgs(ui->sampleNameEdit->text().toStdString());

这将从带有文本框参数 sampleName 的网络程序中获取图像,并从由按钮触发的插槽调用。

这一切都工作正常,但是,某些函数(例如上面的函数)可能需要大约 20 秒才能运行,这会挂起 GUI。我希望它不要挂起 GUI。

显而易见的选择是使用 QThread ,但我不想向我的程序添加额外的类,因为这只应该是一个简单的前端。有没有办法我可以在线程中运行此功能并等待终止信号而不挂起 GUI?

编辑: 问题:

 QFuture<int> run = QtConcurrent::run(&(netWrap.getImgs), ui->sampleNameEdit->text().toStdString());

这会产生 4 个错误,最相关的可能是:

error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&networkWrapper::getImgs' [-fpermissive]
     QFuture<int> run = QtConcurrent::run(&(netWrap.getImgs), ui->sampleNameEdit->text().toStdString());

和:

error: no matching function for call to 'run(int (networkWrapper::*)(std::string), std::string)'
     QFuture<int> run = QtConcurrent::run(&(netWrap.getImgs), ui->sampleNameEdit->text().toStdString());

你不会子类 QThread 在不同的线程中运行某些东西。QThread通过信号/插槽使用。

http://doc.qt.io/qt-5/qthread.html#started

默认的 QThread::run() 启动一个事件循环,允许您处理其他线程中的网络事件等内容。这意味着您连接到QThread::started信号,启动您的请求,然后它们在不同的线程中得到处理。然后,您可以使用另一个信号来指示您的主 GUI 线程,表明您已完成并且数据可用。

如果你只需要在不同的线程中调用某个函数,那么使用Qt Concurrent。这比QThread更容易使用。

http://doc.qt.io/qt-5/qtconcurrent.html#run

void my_function(int a, double b) {
     .... do something in another thread ....
}
    ....
    auto some_function = std::function<void(int, double)>(&my_function);
    QFuture<void> ret = QtConcurrent::run(some_function, 10, 20.0);
    ....

或者不使用任何std::function,直接使用普通函数指针,

QFuture<void> ret = QtConcurrent::run(&my_function, 10, 20.0);

调用类成员,也一样简单,

class Foo {
public:
     void foo(int a) {}
};
...
Foo *foo_instance = new Foo;
QFuture<void> ret = Qtconcurrent::run(foo_instance, &Foo::foo, 10);
...

并且您的函数正在另一个线程中运行。就是这么简单。

注意:不要从非 GUI 线程访问/操作 GUI 类。

你应该提供指向对象的指针,以及类成员函数的地址和所需的参数,如:

QFuture<void> future = QtConcurrent::run(netWrap, &networkWrapper::dbsChanged, ui->sampleNameEdit->text().toStdString());

您可以检查未来表示的异步计算的状态,例如:

if(future.isRunning())
{
    // It is currently running
}

或者等待它完成:

future.waitForFinished();

QtConcurrent::run()不会像QtConcurrent::mappedReduced()那样自动提供进度信息。但是您可以使用信号拥有自己的进度报告机制。

要通知终止,从函数发出信号以显示它已完成是一种简单的方法。