thecoder
thecoder

Reputation: 55

Update Scene from Thread?

I need to update a QGraphicsView with a QGraphicsScene from a thread.

Below is some pseudo'ish code example of what I am doing which is causing me issues (runtime errors).

What am I doing wrong, and how should I be doing it?

Main App:

void Main::startThread()
{
  view = new QGraphicsView(...);
  thread = new MyThread(...);
  connect(thread, SIGNAL(doSceneUpdate(QGraphicsScene*)), this, SLOT(updateScene(QGraphicsScene*)));
  thread->start();
}

void Main::updateScene(QGraphicsScene *scene)
{
  view->SetScene(scene);
  view->show();
  repaint();
}

The Thread:

void MyThread::run()
{
  QGraphicsScene *scene = new QGraphicsScene(...);
  while(1)
  {
    //draw stuff on the scene
    emit doSceneUpdate(scene);
    //some delay
  }

Thanks in advance!!!

[edit] The error is:

ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread
3e53c0. Receiver '' (of type 'QGraphicsScene') was created in thread 1476cd18", file c:\Qt\qt-everywhere-opensource-src-4.8.2\src\corelib\kernel\qcoreapplication.cpp, line 501

Upvotes: 0

Views: 1964

Answers (3)

Jeremy Friesner
Jeremy Friesner

Reputation: 73081

What am I doing wrong, and how should I be doing it?

I think the canonical answer is here -- in a nutshell, the article states that you shouldn't be subclassing QThread, but rather you should use a "bare" (i.e. not-subclassed) QThread object and connect its started() signal to a slot that will then be run in the context of that thread, after the thread starts. That way the object-thread-ownership issues are handled automatically for you.

Note also that threads other than the main Qt thread are generally not allowed to create or interact directly with GUI objects like QGraphicsScene, since doing that would introduce race conditions due to the operations going on simultaneously behind the scenes in Qt's GUI event loop. If you want to use a separate thread, you'll need to keep it away from your GUI objects, and instead just have it emit asynchronous signals and/or send Events to the main/GUI thread to get the main/GUI thread to do the GUI-object updates on its behalf.

Upvotes: 1

DeepBlack
DeepBlack

Reputation: 310

in

void MyThread::run()
{
  QGraphicsScene *scene = new QGraphicsScene(...);
  ...

}

do you pass this to the constructor of QGraphicsScene()?

That could be one cause of error, since now you are passing a child of MyThread to Main

Try creating a QGraphicsScene object on the stack or with the parent as NULL ( new QGraphicsScene(0) )

Upvotes: 1

Nejat
Nejat

Reputation: 32645

The problem is with your connection line. You are connecting a slot to a signal which does not make sense. You should connect the signal from the thread to the slot :

connect(thread, SIGNAL(doSceneUpdate(QGraphicsScene*)),this, SLOT(updateScene(QGraphicsScene*)));

Upvotes: 1

Related Questions