2016-06-15 2 views
1

Ich habe eine QThread Klasse erstellt eine Funktion, die in einer anderen Klasse, aber diese andere Klasse hat einen Zeiger auf eine QWidget (QwtPlot) laufen, und ich empfange diese Meldung in der Anwendung Ausgabe:kann nicht in einem anderen Thread geschrieben Ereignisse für Objekte senden - Qt

QCoreApplication::sendPostedEvents: Cannot send posted events for objects in another thread 

ich bereits in einem anderen Themen lesen, die QThreads nicht mit QWidgets (die UI-Widgets im Hauptthread sein muss) nicht funktioniert, aber die Ausgabe in meiner Anwendung scheint sei richtig.

Kann mir jemand erklären, warum diese Nachricht erscheint? Und was kann passieren, wenn ich den Code so lasse?

Hinweis: Entschuldigung, ich kann den Code nicht veröffentlichen.

Vielen Dank im Voraus

+0

Haben Sie versucht, Signale und Steckplätze mithilfe von ['Qt :: QueuedConnection'] (http://doc.qt.io/qt-5/qt.html#ConnectionType-enum) zu verbinden ?. Außerdem sollten Sie den Zeiger nicht auf ein QWidget verwenden. Verwenden Sie Slots und Signale, um das Widget zwischen Threads zu kommunizieren (auch hier keine Zeiger). Siehe das [Mandelbrot-Beispiel] (http://doc.qt.io/qt-5/qtcore-threads-mandelbrot-example.html) –

Antwort

5

ich in einem anderen Themen schon gelesen, dass QThreads nicht mit QWidgets funktioniert [...] aber die Ausgabe in meiner Anwendung scheint korrekt zu sein.

Es ist nicht korrekt, sonst würden Sie nicht fragen, oder?

Ein QWidget muss im Hauptthread sein. Und wahrscheinlich ist es das auch. Aber Sie rufen seine Methoden aus einem anderen Thread auf, und die Methoden, die Sie aufrufen, sind nicht Thread-sicher. Tu das nicht. Es gibt andere Möglichkeiten, Methoden sicher über Threads hinweg aufzurufen. Benutze sie stattdessen. Wenn zum Beispiel angenommen, dass Sie wünschen QWidget::resize rufen Sie postToThread von this answer verwenden:

QWidget* widget; 
QSize size; 
Q_ASSERT_X(widget->thread() == qApp->thread(), "widget", 
      "The widget must live in the main thread."); 
postToThread([=]{ widget->resize(size); }, widget); 

Wenn Sie ausführlichere sein wollen oder müssen, um einen Qt 4-Code halten Basis, könnten Sie diese stattdessen tun:

class TSWidgetAdapter : public QObject { 
    Q_OBJECT 
    QWidget * widget() const { return qobject_cast<QWidget*>(parent()); } 
    Q_SLOT void resize_d(const QSize & size) { widget()->resize(size); } 
public: 
    explicit TSWidgetAdapter(QWidget * parent) : QObject(parent) { 
    Q_ASSERT_X(parent->thread() == qApp->thread(), "TSWidgetAdapter()", 
       "The widget must live in the main thread."); 
    connect(this, SIGNAL(resize(QSize)), this, SLOT(resize_d(QSize))); 
    } 
    Q_SIGNAL void resize(const QSize & size); 
}; 

QWidget* widget; 
QSize size; 
TSWidgetAdapter widget_ts(widget); 
widget_ts.resize(size); 

Die _d Slots werden im Thread des Widgets aufgerufen. Das ist das Schöne an automatischen Verbindungen: Sie können das Signal in einem beliebigen Thread aufrufen, und der Slot wird nur im Thread des Zielobjekts aufgerufen. Da der Adapter ein Kind des Widgets ist, befindet es sich im Thread des Widgets - das wird von Qt erzwungen.

Verwandte Themen