6

I am wondering if sending a signal to the same object in Qt is considered bad-practice and an anti-pattern, or if that is just fine.

I am in a situation where I would like to do something like this:

QObject::connect (this, &MyFoo::ready,
                  this, &MyFoo::execute, 
                  Qt::ConnectionType::QueuedConnection);

Then from inside execute I would like to emit ready. The motivation for this is to avoid deep recursions. My alternative approach would be to just recursively call execute from execute.

lanoxx
  • 12,249
  • 13
  • 87
  • 142
  • In my opinion it is not an anti-pattern but I cannot see any use case for this that could not be made simpler on the design level. Why do you want to queue your calls to execute ? A simple loop does not fit your needs ? If not, you can do exactly the same as your example without a signal using `[static] bool QMetaObject::invokeMethod` – ymoreau Jun 22 '17 at 12:18
  • Just consider the option of having the signal (`MyFoo::ready`) and the slot (`MyFoo::ready`) in separate classes. If they can belong to different classes, you may end up in a better design. If your objective is only to queue the slot call, you may want to take a look at this [answer](https://stackoverflow.com/a/41910566/2666212). – Mike Jun 22 '17 at 12:22

1 Answers1

2

AFAIK, there is nothing in Qt documentation that says this is a bad practice.

I did this many times, specially in cases where my object gets notified something happened from a thread (listening a COM port, or a bluetooth connection) and a GUI update is needed:

MyObject::MyObject()
{
    connect( this, SIGNAL(dataReceived(QString)), this, SLOT(showData(QString)), Qt::ConnectionType::QueuedConnection );
}

void MyObject::receiveSomeData( QString data )
{
    // a worked thread called this function...
    // we are not in the main thread here, it's unsafe to update the GUI,
    // calling showData(data) will lead most likely lead to crashs or Qt warnings
    // so let's delay it's execution by emitting dataReceived!
    emit dataReceived( data );
}

void MyObject::showData( QString data )
{
    // now it's safe to update the GUI...we are back to main thread
    m_ui.label->setText( data );
}

Also did this kind of tricks in Qt-based class constructors where you need to wait for the widget to be actually visible before you can do some GUI operations (needing to access widget's size for instance...in your constructor, layout is not yet considered as a constraint to size the widget). Then I had to emit a signal from the widget constructor, and this signal was connected to a slot of the same widget class that would do the initialization, and Qt::ConnectionType::QueuedConnection makes the initialization function be executed after the widget actually went visible.

And there may be other situations where this is relevant...

Note: As ymoreau commented the OP, this can also be adressed by using QMetaObject::invokeMethod which most likely ends up doing the same thing.

jpo38
  • 20,821
  • 10
  • 70
  • 151