QT +如何从在不同线程中运行的自定义C++代码调用插槽

13 qt qt4 signals-slots

我是QT的新手,我正在做一些学习.

我想触发一个从C++线程(目前是Qthread)修改GUI小部件的插槽.

不幸的是我得到了:ASSERTION失败了:Q_ASSERT(qApp && qApp-> thread()== QThread :: currentThread());

这是一些代码:

(MAIN + Thread类)

   class mythread : public QThread
    {
    public:
        mythread(mywindow* win){this->w = win;};
        mywindow* w;
        void run()
        {
            w->ui.textEdit->append("Hello");        //<--ASSERT FAIL
            //I have also try to call a slots within mywindow which also fail.
        };
    };

    int main(int argc, char *argv[])
    {
        QApplication* a = new QApplication(argc, argv);
        mywindow* w = new mywindow();

        w->show();
        mythread* thr = new mythread(w);
        thr->start();

        return a->exec();
    }
Run Code Online (Sandbox Code Playgroud)

窗口:

class mywindow : public QMainWindow
{
    Q_OBJECT

public:
    mywindow (QWidget *parent = 0, Qt::WFlags flags = 0);
    ~mywindow ();
    Ui::mywindow ui;

private:



public slots:
    void newLog(QString &log);
};
Run Code Online (Sandbox Code Playgroud)

所以我很好奇如何在不同的线程中通过代码更新gui部分.

谢谢你的帮助

Mar*_*utz 17

stribika几乎是对的:

QMetaObject::invokeMethod( textEdit, "append", Qt::QueuedConnection,
                           Q_ARG( QString, myString ) );
Run Code Online (Sandbox Code Playgroud)

但是,cjhuitt是正确的:您通常希望在线程上声明一个信号并将其连接到append()插槽,以免费获得对象生命周期管理(嗯,对于次要接口更改的代价).在旁注中,附加论点:

               Qt::QueuedConnection ); // <-- This option is important!
Run Code Online (Sandbox Code Playgroud)

来自cjhuitt的答案是不再需要的(在Qt <= 4.1中),因为connect()默认情况下Qt::AutoConnection现在(Qt> = 4.2)做正确的事情并在排队和直接连接模式之间切换并且基于QThread::currentThread()线程亲和力接收器QObject发射时间(而不是发送器和接收器在连接时的亲和力).

  • 我不知道连接现在处于发射时间...这仍然适用于线程对象,它在创建它的线程中"活动",而不是在调用QThread :: run时生成的线程吗?(几周前我们刚开始讨论这个问题,并决定在这些情况下指定QueuedConnection选项更安全.) (2认同)

Cal*_*itt 8

除了stribika的答案,我经常发现使用信号/插槽连接更容易.您可以在连接时指定它应该是排队连接,以避免线程信号出现在其拥有对象的上下文中.

class mythread : public QThread
{
signals:
    void appendText( QString );
public:

    mythread(mywindow* win){this->w = win;};
    mywindow* w;
    void run()
    {
        emit ( appendText( "Hello" ) );
    };
};

int main(int argc, char *argv[])
{
    QApplication* a = new QApplication(argc, argv);
    mywindow* w = new mywindow();

    w->show();
    mythread* thr = new mythread(w);
    (void)connect( thr, SIGNAL( appendText( QString ) ),
                   w->ui.textEdit, SLOT( append( QString ) ),
                   Qt::QueuedConnection ); // <-- This option is important!
    thr->start();

    return a->exec();
}
Run Code Online (Sandbox Code Playgroud)

  • mythread类需要包含Q_OBJECT宏 (5认同)

str*_*ika 6

您需要使用QMetaObject :: invokeMethod.例如:

void MyThread::run() {
    QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello"));
}
Run Code Online (Sandbox Code Playgroud)

(上面的代码来自这里:http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)

  • “ invokeMethod”仅使用函数名(“ setText””),而不是“ SLOT”的结果。 (2认同)