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

问题描述 投票:13回答:5

我是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();
    }

窗口:

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);
};

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

谢谢你的帮助

qt qt4 signals-slots
5个回答
8
投票

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

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();
}

16
投票

stribika几乎是对的:

QMetaObject::invokeMethod( textEdit, "append", Qt::QueuedConnection,
                           Q_ARG( QString, myString ) );

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

               Qt::QueuedConnection ); // <-- This option is important!

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


6
投票

你需要使用QMetaObject::invokeMethod。例如:

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

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


2
投票

我不认为你可以直接调用导致除主线程之外的任何其他线程的绘制事件的东西。这将导致崩溃。

我认为你可以使用事件循环异步调用事物,以便主gui线程获取,然后从主线程进行更新,这是cjhuitt建议的。


2
投票

如果我们的线程亲和力说GUI,但我们不在GUI线程中,也不在QThread中,该怎么办?

我的意思是,非Qt(通知)线程调用QObject的接口方法,我们在其中发出自动连接信号。 QObject的Thread亲缘关系是主线程,但实际上是从另一个线程调用该过程。 Qt在这做什么?

© www.soinside.com 2019 - 2024. All rights reserved.