PDA

View Full Version : Broadcasting a signal ?



squidge
15th November 2009, 18:18
I have two widgets, one of which is in a few levels of classes and one which is only 2 levels deep. I'd like the second widget to do some action depending on something happening on the first widget, but neither knows of the others existence, nor could they get a pointer to it very easily (I'd have to make a public variable in each layer of classes to get the pointer. Yeuck)

Is it possible for one widget to 'broadcast' a signal which the secondary widget can pickup ?

I really don't want to pass a pointer to the secondary widget through the various constructors to get to the first widget so it can perform a connect() call as I want them to remain completely self contained.

I've thought about Qt Event system, but that requires a pointer to the object to send the message to, and neither widget knows the pointer to the other.

I keep thinking of a global class accessible by both where one can register as a listener with a unique id, and the other sends a signal using that same id, but this seem nasty, and too much like signals and slots already implemented.

wysota
15th November 2009, 23:37
I would probably reemit the signal from each parent class until it reaches a place where you can connect it to a slot. On the other hand I have strong doubts whether such coupling is a good design at all. If you explained the situation maybe we could find a better solution.

aamer4yu
16th November 2009, 04:38
I guess socket communication or any other IPC would be better for your case

wysota
16th November 2009, 08:04
From what I understood this is not interprocess but rather intraprocess. Sockets would be an overkill here. I have a better solution waiting but I want to know the usecase first.

squidge
16th November 2009, 16:19
There were several use cases, but I've since redesigned most of them around other ideas which make more sense.

The other is that there can be a few widgets that are all self contained, all of which that currently have Activated() and Deactivated() signals. Both signals are connected from every widget in that group to each other. So with 2 widgets there are 4 signals, and for 3 widgets there are 12 signals, and so on. Here I think a broadcast signal from each to all would be better than all thrse signals flying around.

wysota
16th November 2009, 18:41
Have a singleton object that emits activated and deactivated signals and connect your objects to that object. As it is a singleton, you can access it from any place in your application thus making it emit proper signals becomes easy.

squidge
16th November 2009, 20:06
So instead of each widget talking to each other, they talk to the singleton which will in turn talk to the others? I suppose the singleton would require the use of the sender() method else otherwise it would include the sender in its redistribution of the signals, which would be bad.

It would also require pre-registration with the singleton to know who to send the signals to, although that wouldn't be too bad, as it could do it when the objects connect() to its signals if Qt has a way of detecting such?

Or are you thinking something different?

wysota
16th November 2009, 21:06
So instead of each widget talking to each other, they talk to the singleton which will in turn talk to the others?
Yes.

I suppose the singleton would require the use of the sender() method else otherwise it would include the sender in its redistribution of the signals, which would be bad.
Why? If the sender is already disabled, trying to disable it again shouldn't have any effect.
Besides, instead of disabling the sender in the first place, make it (or the thing that is to disable the object) call the singleton directly and it will emit the signal and effectively disable the object.


It would also require pre-registration with the singleton to know who to send the signals to
connect() statement is such a registration. Try this:


class Controller : public QObject {
Q_OBJECT;
public:
Controller(){
m_instance = this;
m_active = true;
}
static Controller *instance() { return m_instance; }
bool isActive() const { return m_active; }
public slots:
void setActive(bool v){
if(v==m_active) return;
m_active = v;
emit activeChanged(v);
}
signals:
void activeChanged(bool)
private:
bool m_active;
static Controller *m_instance;
};

Controller* Controller::m_instance = 0;

// ...

class MyObject : public QObject {
Q_OBJECT
public:
MyObject() : QObject(){
m_active = Controller::instance()->isActive();
connect(Controller::instance(), SIGNAL(activeChanged(bool)), this, SLOT(setActive(bool)));
connect(this, SIGNAL(activeChanged(bool)), Controller::instance(), SLOT(setActive(bool)));
}
public slots:
void setActive(bool v) {
if(m_active==v) return;
m_active = v;
emit activeChanged(v);
}
signals:
void activeChanged(bool);
private:
bool m_active;
}

#include "main.moc"

int main(int argc, char **argv){
QApplication app(argc, argv);
Controller c;
MyObject obj1, obj2;
// effectively these are equivalent:
obj1.setActive(false);
// or
obj2.setActive(false);
// or
c.setActive(false);
// or
QCheckBox cb;
QObject::connect(&cb, SIGNAL(toggled(bool)), Controller::instance(), SLOT(setActive(bool)));
cb.show();
return app.exec();
}

squidge
16th November 2009, 23:07
Why? If the sender is already disabled, trying to disable it again shouldn't have any effect.
Thanks, having activeChanged is much better than seperate Activated and Deactivated signals. I'll have a play with it tomorrow.