[Qt] Cannot send events to object owned by a different thread



  • Hallo,
    ich habe das Problem vom Titel wie folgt versucht zu lösen:

    Header-Datei:

    //Haupt Klasse
    class MyClass : public QMainWindow {
        public slots:
            static void threadSetStylesheet(QWidget* widget, QString stylesheet);
            static void threadSetGeometry(QWidget* widget, int x, int y, int width, int height);
            //noch weitere....
    };
    

    CPP-Datei:

    void MyClass::threadSetStylesheet(QWidget* widget, QString stylesheet) {
        widget->setStyleSheet(stylesheet);
    }
    
    //....
    

    Nun habe ich eine weitere Klasse (Thread), welche mit dem nötigen initialisiert wird:

    class Load : public QThread {
        private:
            QVector<QWidget>* widgets;
    
        public:
            void init(QWidget* initWidgets) {
                //Die widgets innherhalb von 'initWidgets' wurden bereits in der Hauptklasse (MyClass) per 'new' erstellt
                widgets = initWidgets;
            }
    
        protected:
            run() {
                QString stylesheet = "";
                emit MyClass::threadSetGeometry(initWidgets[0], 0, 0, 100, 70); //Lässt sich problemlos aufrufen
                emit MyClass::threadSetStylesheet(initWidgets[0], stylesheet); //Fehler: cannot send events to object owned by a different thread         
            }
    };
    

    Nun, einige Funktionen lassen sich problemlos aufrufen, andere hingegen nicht. Warum?



  • Beim letzten Code-Abschnitt müsste die Variable 'initWidgets' natürlich auch vom Typ QVector<QWidget>** sein.



  • Du emittierst einen Slot?!

    Vermutlich wird der Slot "threadSetGeometry" einfach normal aufgerufen (ist nix anderes als eine Funktion), das emit also ignoriert.

    Du darfst nur im "Hauptthread" Dinge tun, die das user interface betreffen (also QWidget-Methoden aufrufen etc.).
    Aber das hast du vielleicht schon erkannt.

    Du müsstest in der Klasse "Load" also ein Signal definieren und emittieren und zuvor mit einem Slot in MyClass verbinden.

    Oder per QMetaObject::invokeMethod mit QueuedConnection:
    http://doc.qt.io/qt-5/qmetaobject.html#invokeMethod

    Generell:
    http://doc.qt.io/qt-5/signalsandslots.html
    http://doc.qt.io/qt-5/qobject.html#thread-affinity



  • Mit QMetaObject::invokeMethod funktionierts. Danke.



  • Hallo,
    ich habe genau dasselbe Problem und versuchte dies dann auch mit invokeMethod() zu lösen. Mein Problem ist jedoch, dass es die Funktion dann zwar aufruft jedoch wird bspw. der Text von einem QLabel dann nicht geändert.


Anmelden zum Antworten