Подтвердить что ты не робот

QT + Как вызывать слот из пользовательского кода на С++, запущенного в другом потоке

Я новичок в QT, и я занимаюсь некоторым обучением.

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

К сожалению, я получаю: ASSERTION не удалось: Q_ASSERT (qApp & & ap; 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();
    }

Window:

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 с помощью кода в другом потоке.

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

4b9b3361

Ответ 1

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

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

Ответ 2

stribika получил почти прав:

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

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

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

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

Ответ 4

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

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

Ответ 5

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

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