2016-06-15 1 views
1

J'ai créé un pour exécuter une fonction classe QThread qui est dans une autre classe, mais cette autre classe a un pointeur vers une QWidget (QwtPlot), et je je reçois ce message dans la sortie de l'application:Impossible d'envoyer affiché des événements pour les objets dans un autre thread - Qt

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

Je l'ai déjà lu dans un autre sujets que qthreads ne fonctionne pas avec QWidgets (les widgets de l'interface utilisateur doit être dans le thread principal), mais la sortie dans mon application semble être correct. Est-ce que quelqu'un peut m'expliquer pourquoi ce message apparaît? Et que peut-il se passer si je laisse le code tel quel?

Note: Désolés, je ne peux pas poster le code.

Merci à l'avance

+0

Avez-vous essayé de connecter des signaux et des emplacements en utilisant ['Qt :: QueuedConnection'] (http://doc.qt.io/qt-5/qt.html#ConnectionType-enum) ?. En outre, vous ne devez pas utiliser le pointeur sur un QWidget. Utilisez les slots et les signaux pour communiquer le widget entre les threads (encore une fois, pas de pointeurs). Voir l'exemple de [mandelbrot] (http://doc.qt.io/qt-5/qtcore-threads-mandelbrot-example.html) –

Répondre

5

J'ai déjà lu dans un autre sujets que qthreads ne fonctionne pas avec QWidgets [...] mais la sortie dans mon application semble être correcte.

Ce n'est pas correct, sinon vous ne le demanderiez pas, n'est-ce pas? Un QWidget doit être dans le fil principal. Et c'est probablement le cas. Mais vous invoquez ses méthodes à partir d'un autre thread, et les méthodes que vous invoquez ne sont pas sécurisées par les threads. Ne fais pas ça. Il existe d'autres façons d'invoquer des méthodes en toute sécurité à travers les threads. Utilisez-les à la place. Par exemple, en supposant que vous souhaitez appeler QWidget::resize, vous pouvez utiliser postToThread de this answer:

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

Si vous voulez être plus bavard, ou doivent maintenir une base de code Qt 4, vous pouvez le faire à la place:

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

Les emplacements _d sont appelés dans le thread du widget. C'est la beauté des connexions automatiques: vous pouvez appeler le signal dans n'importe quel thread, et le slot sera appelé dans le thread de l'objet cible seulement. Comme l'adaptateur est un enfant du widget, il se trouve dans le thread du widget - qui est appliqué par Qt.