2010-03-04 16 views
9

Ich habe einen Hintergrund-Thread und der Thread ruft einige Methoden, die die Benutzeroberfläche aktualisieren (um Fortschrittsbalken anzuzeigen und zusätzliche Informationen in Textbereichen anzuzeigen).Qt: Hintergrund Thread Aktualisierung UI-Thread

Wenn ich einige UI-Widget-Werte ändern, wird ein Assertion-Fehler "Keine Ereignisse an Objekte gesendet, die einem anderen Thread gehören" ausgelöst.

Mit Blick auf Foren, ich lese, dass ich QMetaObject :: invokeMethod Methode verwenden könnte, aber es funktioniert nur, wenn ich es das Qt :: DirectConnection-Flag übergeben, die tatsächlich den gleichen Fehler oben angezeigt wird.

Wenn ich Qt :: QueuedConnection oder Qt :: AutoConnection verwenden, gibt InvokeMethod false zurück.

Mein Code sieht ähnlich wie:

.h:

class A : public QMainWindow 
{ 
    Q_OBJECT 

    QProgressBar* pb; 

    public slots: 
    bool m(bool, int); 
}; 

class B 
{ 
    A* a; 

    public: 
    void handleEvent(); 
}; 


.cpp: 

bool A::m(bool x, int y) 
{ 
    pb->setValue(y); 
    return x; 
} 

void B::handleEvent() 
{ 
    //a->m(true, 12); //raises an assertion error 

    bool r; 
    //bool ret = QMetaObject::invokeMethod(a, "m", Qt::DirectConnection, Q_RETURN_ARG(bool, r), Q_ARG(bool, true), Q_ARG(int, 12)); //raises the same assertion error error 

    bool ret = QMetaObject::invokeMethod(a, "m", Qt::AutoConnection, Q_RETURN_ARG(bool, r), Q_ARG(bool, true), Q_ARG(int, 12)); //is ignored and ret contains false. 
} 

Sie wissen, was los ist oder was ich falsch mache? oder vielleicht, kann mir jemand einen anderen Ansatz vorschlagen, um mit meinem Anfängerproblem umzugehen?

Vielen Dank im Voraus,

Ernesto

Antwort

10

Ich habe invokeMethod() mich nicht verwendet, aber dies zu tun, ich in der Regel nur Signale und Slots verwenden. Zum Beispiel könnten Sie ein Signal als Mitglied der class B zu erstellen, die mit dem Schlitz in class A verbunden ist, um den Fortschritt aktualisiert:

class B : public QObject 
{ 
    Q_OBJECT 

    A* a; 

signals: 
    void update_signal(bool, int); 

public: 
    void handleEvent(); 
}; 

B::B() 
{ 
    //assuming a already points to the correct place... 
    connect(this, SIGNAL(update_signal(bool,int), 
      a, SLOT(m(bool,int)), Qt::QueuedConnection); 
} 

void B::handleEvent() 
{ 
    emit update_signal(true, 12); 
} 

A::m() ungültig in diesem Fall zurückkommen müssen, aber das ist kein Problem, denn wenn Wenn Sie eine Verbindung in der Warteschlange verwenden, können Sie sowieso keinen Rückgabewert erhalten, da der Aufruf asynchron ist (emit update_signal(true,12) kann zurückgegeben werden, bevor die Slot-Funktion aufgerufen wird, wodurch es unmöglich wird, einen Rückgabewert bereit zu halten).

Sie können diese Verbindung tatsächlich überall durchführen, solange Sie Zeiger auf ein Objekt vom Typ A und ein Objekt vom Typ B haben. Dies macht die Signale und Steckplätze sehr flexibel, da Sie A von B vollständig entkoppeln können, aber dennoch über Signale und Steckplätze kommunizieren können. Zum Beispiel:

class B : public QObject 
{ 
    Q_OBJECT 

signals: 
    void update_signal(bool, int); 

public: 
    void handleEvent(); 
}; 

void B::handleEvent() 
{ 
    emit update_signal(true, 12); 
} 

class A : public QMainWindow 
{ 
    Q_OBJECT 

    QProgressBar* pb; 

    public slots: 
     void m(bool, int); 
}; 

void A::m(bool x, int y) 
{ 
    pb->setValue(y); 
} 

int main() 
{ 
    A* a = new A(); 
    B* b = new B(); 

    QObject::connect(b, SIGNAL(update_signal(bool, int)), 
      a, SLOT(m(bool, int)), Qt::QueuedConnection); 

    //... 
} 

In diesem Fall b muss nicht einen Zeiger speichern oder etwas über a wissen doch können sie durch einen dünnen gut definierten Kanal kommunizieren.