I hope it is not a silly question but i thing I don’t get the broad/listen concept.
I have looked into the demo to see how it works but.
I am trying to use the boadcaster/listener methods in the following way…
I have got a main components which holds several different components (comms_panel, info_panel, buttons_panel).
For example if I press i button at buttons_panel, its name appears at info_panel and comms_panel.
I have thought of using the broadcaster/listener classes to keep a component informed about events in other components.
The juce demo use ONE main listener to listen to SEVERAL broadcasters(events from child components -> balls in the demo)
In my case I want SEVERAL listeners to listen to ONE broadcaster…so for example I press a button in a component, its name appear at the listeners. I can do it although I am not really sure if this is the concepts.
also changeListenerCallback(ChangeBroadcaster* source) receives the source, so if broadcasters belong to the listener is easy to write: if(source==child_A) or whatever, but when components are defined at different files and they are added in a main component, i don’t know how to find out who the trigger was.
Any advise?I would like to be sure of how to use it before writing a lot useless code
I’m very much still learning, but I’m sure more experienced folk will chime in and correct any mistakes. Here’s what I (think I) know about the listener broadcaster system in JUCE…
JUCE follows the observer pattern (i.e. a broadcaster object maintains a list of listeners and when its state changes, notifies each listener by calling one of the listener’s methods).
A broadcaster will:
Have a data member ListenerList<Broadcaster::Listener> listeners (or similar) - thats the list of listeners it maintains as per the observer pattern
Contain a Broadcaster::Listener class which has virtual callback methods for each possible change of state (to be inherited from & implemented by each Listener object)
Have a void addListener (Broadcaster::Listener* listener) method to add listeners to the ListenerList
Have a void removeListener (Broadcaster::Listener* listener) method to remove listeners from the ListenerList
Call the appropriate callback method on all the listeners in its ListenerList whenever it undergoes a state change. In its simplest form that will look something like this:
(Note the this: the broadcaster object sends a pointer to itself to the listener, so that when the callback is received, the listener can check the pointer’s address to determine which broadcaster object the callback has come from)
A Listener:
Must inherit from Broadcaster::Listener
Must implement all pure virtual callback methods in Broadcaster::Listener
May implement any non-pure virtual callback methods in Broadcaster::Listener
Must call Broadcaster::addListener (this) in order to register itself with the Broadcaster’s ListenerList before it can receive listener callbacks
Will now have its callback methods invoked by the Broadcaster when the Broadcaster’s state changes and can use the Broadcaster* it receives as an argument to determine which broadcaster object the callback has come from
Must call Broadcaster::removeListener (this) in its destructor so as to avoid leaving a dangling pointer to itself in the Broadcaster’s ListenerList
In order for your listener object to call Broadcaster.addListener (this) to register itself with the broadcaster, it needs to have a pointer or reference to the broadcaster object; so you just keep this reference/ pointer as a private member of the listener object and later check if the pointer received from the broadcaster when it calls the listener object’s callback methods matches the pointer / reference stored earlier by the listener.
You can do that, but there is also a way without keeping pointers, in case they are changing often:
In the case when the listener is not the owner of a broadcaster/slider/anything, I usually use the componentID, that way no raw pointer is involved.
Sure you can argue that the comparism to the raw pointer is more performant than the string of componentID. But I try to avoid raw pointers, where the lifetime is not well defined. That way I am not tempted to use that raw pointer for other things than compare for a sender (and not getting into hells kitchen for that). So I decide for each situation differently which to use…
like this:
static String paramGain ("GainSlider");
ScopedPointer<Slider> slider = new Slider();
slider->setComponentID (paramGain);
slider->addListener (myListener);
void Listener::sliderValueChanged (Slider* s)
{
if (s->getComponentID() == paramGain)
{
// do something
}
}
I think that’s OK for component/events callbacks. But in the case of a listener, it receives the broadcaster object but no the component pointer in itself, so if the listener doesn’t own the broadcaster i can’t know how to figure out who the trigger was.
The example is simple. I have got a main component which contains several panels…so i want to trigger events between panels sharing some info regarding the event. Therefore I didn’t understand the message callback from the listener to the broadcaster, because i find useful to send some info from the broadcaster to inform about the event. And if the listener owns the broadcaster I could easily write any method to send from the listener to the broadcaster.
Or maybe there is a better way of doing it and I am confuse of it.
I guess I can program something with pointers and so, but i thought there would be a juce class as broad/listen to perform something like that.
Regards and thanks for your answers!!
Because the ChangeBroadcaster is an interface, you can use the vtable and dynamic_cast:
if (Component* c = dynamic_cast<Component*> (broadcaster)) {
if (c->getComponentID() == "gainSlider") {
// and so on
}
else if (c->getComponentID() == "another") {
// another thing
}
}
else if (AudioDeviceManager* manager = dynamic_cast<AudioDeviceManager*> (broadcaster)) {
// change came from device manager
}
an ID for ChangeBroadcaster would be a nice addition, but I think you can live without.
It is a good idea, i missed it is an interface.
However I am trying but I’ve got nothing from the ID. like “”. empty field. Of course I have asigned an ID to the trigger.
Maybe because the broadcaster and listener are different classes/files that belong to a main comonent.
Main.c/.h contains A(located at A.h/A.c file) and B(located at B.h/B.c file): i am performing the event straigh from A to B by no means of main.
In that case the received broadcaster pointer wouldn’t be Foo but the generic ChangeBroadcaster.
Sorry, that was probably obvious to you, I just wanted to point to possible erors…