在使用Qt时,工作线程创建新的GUI元素

5
我会尽可能简单地编写代码,以便您们能够看到我想要做的事情;)我知道所有锁定问题等等。我正在尝试弄清楚信号和槽与线程的关系。
在main.cpp中:
int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    MyConsole c;       // Subclasses QThread and implements run()
    MyReceiver r(app); // We pass app to MyReceiver for later (see below)
    QObject::connect(&c, SIGNAL(sendit()),
                     &r, SLOT(gotit()));
    c.start();         // Start the worker thread
    app.exec();
}

假设信号和槽已经在头文件中正确设置(我已经测试过了)。现在,这里有一个问题:
在MyReceiver.cpp中:
void MyReceiver::gotit()
{
    QLabel *label = new QLabel(0, "Hello");  // Some GUI element, any will do
    app.setMainWidget(*label);               // Some GUI action, any will do
}

问题是:因为MyReceiver对象是在主线程main()中创建的,这意味着槽(例如gotit())将在主线程上运行,因此可以安全地进行GUI操作吗?即使信号是从不同的QThread(例如此示例中的MyConsole)引发的?
是否有更好的方法允许工作线程与GUI交互(例如,Obj-C / Cocoa有一种“在主线程上发送消息”的方法)。那么,“Qt方式”是什么?
提前感谢!

https://dev59.com/zXRB5IYBdhLWcg3wZWbi 这个回答了你的问题吗? - parapura rajkumar
2个回答

5
默认情况下(Qt::AutoConnection),槽函数将在创建QObject的线程中运行。因此,无论从哪个线程发出信号,该槽函数始终在与QObject“所在”的线程中运行(如果该线程中运行了Qt事件循环,则可以传递事件;否则无法传递)。由于主线程将成为Qt GUI线程,因此这将按预期工作。这确实是与GUI交互的Qt方式。 另请参见:http://doc.qt.nokia.com/4.7/thread-basics.html(查找线程亲和性)。

无论从哪个线程发出信号,槽函数始终在同一线程中运行。这句话有点含糊不清,听起来好像槽函数将始终在发出信号的同一线程中运行。我知道你的意思不是这样的(因为你的其他回答都是正确的),但这可能会让其他人感到困惑。 - Christian Rau
1
好的,那句话有歧义,我已经重新表达了。感谢您的评论。 - awx
需要注意的是,即使没有执行循环在运行,您仍然可以发送信号。只需定期调用QCoreApplication::processEvents(),它就会像您有执行循环在运行一样。这对于您无法将控制权交还给操作系统但仍需要来自不同线程的信号的输入/输出的情况非常有用。 - g19fanatic
正确。QCoreApplication::processEvents()更多是针对长时间运行的操作的解决方法,如果没有事件循环,它就没有什么意义(它只处理调用线程上的事件)。 - awx

2
使用Queued连接是在一个线程中发射信号,然后在另一个线程中接收信号的“Qt方式”。
connect( obj, SIGNAL(foo()), other_obj, SLOT(bar()), Qt::QueuedConnection )

以下是Qt::QueuedConnection的文档翻译:

当接收者线程的事件循环恢复控制时,将调用该槽函数。槽函数在接收者线程中执行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接