Domanda QT + Come chiamare lo slot dal codice C ++ personalizzato in esecuzione in un thread diverso


Sono nuovo di QT e sto facendo un po 'di apprendimento.

Vorrei attivare uno slot che modifica un widget GUI da un thread C ++ (attualmente un Qthread).

Sfortunatamente ricevo un: ASSERZIONE non riuscita a: Q_ASSERT (qApp && qApp-> thread () == QThread :: currentThread ());

ecco un codice:

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

Finestra:

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

Quindi sono curioso su come aggiornare la parte gui per codice in una discussione diversa.

Grazie dell'aiuto


11
2017-07-17 16:07


origine


risposte:


Inoltre la risposta di stribika, Trovo spesso più facile usare una connessione segnale / slot. È possibile specificare che dovrebbe essere una connessione accodata quando la si connette, per evitare problemi con i segnali del thread che si trovano nel contesto del proprio oggetto proprietario.

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

8
2017-07-17 20:51



stribika ha capito bene:

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

Tuttavia, cjhuitt ha ragione: di solito vuoi dichiarare un segnale sul thread e connetterlo al append() slot, per ottenere la gestione a vita dell'oggetto gratuitamente (beh, per il prezzo di un cambio di interfaccia minore). In un sidenote, l'argomento aggiuntivo:

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

dalla risposta di cjhuitt non è più necessario (era, in Qt <= 4.1), da allora connect() predefinito Qt::AutoConnection che ora (Qt> = 4.2) fa la cosa giusta e passa dalla modalità di connessione in coda e diretta basata su QThread::currentThread() e l'affinità del thread del ricevitore QObject a emettere tempo (invece di affinità di mittente e ricevente al momento della connessione).


13
2017-07-20 05:33



Devi usare QMetaObject :: invokeMethod. Per esempio:

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

(Il codice di cui sopra viene da qui: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)


5
2017-07-17 18:28



Non penso che tu sia autorizzato a chiamare direttamente cose che si traducono in eventi pittorici da parte di qualcuno altri thread rispetto al thread principale. Ciò si tradurrà in un incidente.

Penso che tu possa usare il ciclo degli eventi per chiamare le cose in modo asincrono, in modo che il thread dell'interfaccia principale si rialzi e poi esegua l'aggiornamento dal thread principale, che è ciò che suggerisce cjhuitt.


2
2017-07-18 00:15



Cosa succede se la nostra affinità di thread dice la GUI, ma non siamo nel thread della GUI, né in un QThread?

Quello che voglio dire è che un thread non-Qt (notifica) chiama un metodo di interfaccia di QObject, nel quale emettiamo un segnale AutoConnected. L'affinità di Thread di QObject è Main thread, ma la procedura viene effettivamente chiamata da un altro thread. Cosa farà il Qt qui?


2
2018-03-18 14:15