QT + Как вызвать слот из пользовательского кода C ++, запущенного в другом потоке - PullRequest
13 голосов
/ 17 июля 2009

Я новичок в QT и немного учусь.

Я хотел бы вызвать слот, который изменяет виджет GUI из потока C ++ (в настоящее время Qthread).

К сожалению, я получаю: ASSERTION не удалось в: Q_ASSERT (qApp && qApp-> thread () == QThread :: currentThread ());

вот код:

(MAIN + класс резьбы)

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

Так что мне любопытно, как обновить часть графического интерфейса с помощью кода в другом потоке.

Спасибо за помощь

Ответы [ 5 ]

16 голосов
/ 20 июля 2009

stribika понял это почти правильно:

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

Право cjhuitt, хотя: обычно вы хотите объявить сигнал в потоке и подключить его к слоту append(), чтобы бесплатно получить управление временем жизни объекта(ну за небольшую смену интерфейса).В отношении sidenote дополнительный аргумент:

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

из ответа cjhuitt больше не нужен (это было в Qt <= 4.1), поскольку <code>connect() по умолчанию имеет значение Qt::AutoConnection, которое теперь (Qt>= 4.2) делает все правильно и переключается между режимом очереди и прямым соединением на основе QThread::currentThread() и привязки потока к получателю QObject в испускают времени (вместо привязки отправителя и получателя во время подключения).

8 голосов
/ 18 июля 2009

В дополнение к ответу стрибика мне часто проще использовать соединение сигнал / слот. Вы можете указать, что это соединение должно быть в очереди при подключении, чтобы избежать проблем с сигналами потока, находящимися в контексте его собственного объекта.

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();
}
6 голосов
/ 17 июля 2009

Вам необходимо использовать 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 голосов
/ 18 марта 2010

Что, если наша привязка к потоку говорит GUI, но мы не в потоке GUI и не в QThread?

Я имею в виду, что поток, не являющийся Qt (уведомлением), вызывает метод интерфейса QObject, в котором мы излучаем сигнал AutoConnected. Сходство с потоком QObject является основным потоком, но процедура фактически вызывается из другого потока. Что здесь сделает Qt?

2 голосов
/ 18 июля 2009

Я не думаю, что вам разрешено напрямую вызывать вещи, которые приводят к событиям рисования из любого другие темы, чем основная тема. Это приведет к сбою.

Я думаю, что вы можете использовать цикл обработки событий для асинхронного вызова, так что основной поток графического интерфейса забирает и затем выполняет обновление из основного потока, что и предлагает cjhuitt.

...