3

我想在代码中的函数运行时在主窗口上设置标签的文本。但是标签在函数结束之前不会改变。

for (int i = 0; i < files.size(); ++i) {

    ui->label->setText(files[i]);
    myfoo();

}
4

3 回答 3

4

没有看到标签更新的原因是更新 GUI 的主线程正忙于您的 for 循环并且没有时间处理事件,除其他外,这会导致 GUI 小部件被重绘。

虽然您可以使用 QApplication::processEvents,但这并不理想,尤其是在处理您的函数期间收到许多事件时。

处理此问题的正确方法是创建一个单独的线程 (QThread) 和一个从 QObject 派生的对象,该对象将在向主 (GUI) 线程发送消息以更新标签时工作。

与其重复代码,我建议你阅读这篇关于如何正确使用 QThread 的文章。这并不难。

然后,您将现在位于第二个线程的对象中的函数更改为如下所示:-

for (int i = 0; i < files.size(); ++i) 
{
    // calling UpdateLabel signal, which connects to an object on the main thread
    UpdateLabel(files[i]);        
    myfoo();  
}

假设来自 Worker 类的信号已连接到主线程上的对象中的插槽,例如 QMainWindow,您将收到插槽中的文本并更新标签:-

void QMainWindow::UpdateLabel(const QString text)
{
    ui->label->setText(text);
}
于 2014-03-28T14:52:50.620 回答
0

发生这种情况是因为您的循环阻塞了事件循环——您永远不会返回到事件循环。在您的代码中调用大多数任何插槽时,都会从事件循环中调用它。只有当您从插槽或方法返回时,事件循环才能继续QObject::event

使用 Qt 5 和 C++11,从单独的线程更新文件列表非常容易。

QtConcurrent::run([this] {
  // This code runs in a separate thread
  for (int i = 0; i < files.size(); ++i) {
    // This is safe for cross-thread use
    QMetaObject::invokeMethod(ui->label, "setText", files[i]);
    myfoo();
  }
});

的实现myfoo() 必须是线程安全的,并且不能直接访问任何小部件。它仍然可以通过使用该invokeMethod机制安全地“写入”到小部件,因为它是跨线程的。

在我的 photomosaic Qt 示例中给出了演示如何编写不阻塞 gui 的完全多线程文件访问的一个相当好的起点,该示例仅用 300 行实现

于 2014-03-28T15:37:26.910 回答
-1

您可以在一个单独的线程中执行您的 for 循环,该线程仅向 gui 线程发送信号,然后在适当的插槽中调用 label->setText()。(使用 Qt::QueuedConnection)

或者试试这个:

for (int i = 0; i < files.size(); ++i) {
    ui->label->setText(files[i]);
    QApplication::processEvents();
    myfoo();  
}
于 2014-03-28T14:40:42.450 回答