【问题标题】:Updating GUI from different thread从不同的线程更新 GUI
【发布时间】:2014-05-25 16:52:39
【问题描述】:

我需要在不同的线程中运行一个计算密集型函数,以便 GUI 在运行时不会冻结或变灰。

我按照这个例子:https://stackoverflow.com/a/16501374/2904614

但 GUI 仍然冻结并变灰。

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(thread);
    connect(updater,SIGNAL(req()), this, SLOT(getCheckSum()));
    connect(thread, SIGNAL(destroyed()), updater, SLOT(deleteLater()));
    thread->start();
}

当用户点击指定按钮时。由于一个目录中可能有很多文件,所以当 QDirIterator 遍历所有文件时,GUI 将冻结。我希望添加一个进度条,向用户显示程序仍在运行。

void MainWindow::on_pushButton_clicked()
{
    updater->getHash();
    //getCheckSum();
}

编辑 我想让MainWindow::getCheckSum() 函数在与 GUI 不同的线程中运行。我将如何实施?

Github:https://github.com/Jyang772/PenguSniff

【问题讨论】:

  • 你在哪里更新更新?它有父母吗?你开始线程了吗?
  • 我在 MainWindow 的类声明中这样做。是的,我在连接插槽/信号后启动线程。 updater 没有父级,因为如果有的话我不能使用moveToThread
  • 你的 for 循环在哪里执行?您的问题尚不清楚,可能在 GUI 线程中运行。我建议在发出 req() 之前把它放在 getHash() 中。
  • @Basilevs 我确实把它放在了getHash()。现在我只是用一个无限循环替换它来测试 GUI 是否响应。
  • @MicroPenguin,请以某种方式更新问题,以便清楚执行循环的位置。目前还不清楚什么是“我想在不同的线程中调用的函数”。另外,看看SSCCE

标签: c++ multithreading qt


【解决方案1】:

鉴于您只需要运行一个函数,我建议您使用 QtConcurrent。从文档中提取:

在单独的线程中运行函数

要在另一个线程中运行函数,请使用 QtConcurrent::run():

extern void aFunction();
QFuture<void> future = QtConcurrent::run(aFunction);

这将在从默认 QThreadPool 获得的单独线程中运行 aFunction。您可以使用 QFuture 和 QFutureWatcher 类来监控函数的状态。

【讨论】:

  • 顺便说一句,没有其他框架拥有像 QFuture 和 QFutureWatcher 这样酷的类。听起来很容易实现时间机器
  • 谢谢!但是,如果用户按下不同的按钮,我想调用其他一些函数。我需要清除 textbrowser 中的任何文本,但似乎线程在 textbrowser 清除之前就开始了。
  • 清除文本浏览器并不打算在单独的线程中运行。根据您的描述,只有计算功能必须在单独的线程中运行,因此使用 QtConcurrent 是合格的。
  • 我意识到我有一个与函数中的局部变量同名的全局变量。这就是为什么 textbrowser 在我想要的时候从未被修改过的原因。感谢您的建议QtConcurrent
【解决方案2】:

问题是你直接在另一个线程中调用了一个类的函数:

updater->getHash();

它会在您的应用程序中导致未定义的行为并使其崩溃。正确的方法是从 MainWindow 发出一个信号,该信号连接到 updater 中的 getHash() 插槽:

connect(this,SIGNAL(getHash()), updater, SLOT(getHash()));


void MainWindow::on_pushButton_clicked()
{
    emit getHash();
}

这将导致连接排队并在更新程序线程中运行插槽。

【讨论】:

  • 应用程序不会“崩溃”,它只是在遍历目录时变成灰色。完成后,GUI 将再次响应。我试过这个方法,结果还是一样。我如何确定它是在不同的线程上处理的?
【解决方案3】:

您在 GUI 线程中调用您的 getHash() 计算函数(根据您的评论它是计算的)。将其绑定到 clicked 信号,然后在对象的线程中调用。

connect(button, SIGNAL(clicked()), this, SLOT(getHash()));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    相关资源
    最近更新 更多