Table of Contents
This tutorial introduces a key concept in JUCE: the listener and broadcaster system.
We look at this through implementing simple actions in response to button clicks.
Platforms: Windows, Mac OS X, Linux, iOS, Android
Download the demo project for this tutorial here: tutorial_listeners_and_broadcasters.zip. Unzip the project and open it in your IDE.
If you need help with this step, see Tutorial: Getting started with the Projucer.
The demo project for this tutorial presents a simple user interface with a single button and a single label. The interface should look similar to the following screenshot:
The interface doesn't do anything in the state provided. We are going to add some code to make a click of the button cause the label to display the current date and time.
MainContentComponent class comprises two child components: a TextButton object and a Label object. A TextButton object can display a button containing some specific text, and a Label object can display a piece of text.
- The TextButton class implements one type of button. There are many types of Button class available in JUCE. See the API reference documentation for the ToggleButton, ShapeButton, ImageButton, DrawableButton, and ArrowButton classes for more information.
The declaration (in the
MainComponent.h file) for the
MainContentComponent class is as follows:
The button and the label are added to the
MainContentComponent object and made visible in the
Here we set the button text and configure a specific appearance for the label. This so that the label shows white text on a black background. By default, the label will not show any text.
In JUCE, buttons, sliders, and many other types of controls that may need to inform other objects about a change in their state are a type of broadcaster object. In order to respond to changes in a broadcaster object, other classes need to be a listener for that specific type of broadcaster. Listeners also need to be registered with at least one specific broadcaster object of that type. (The broadcaster-listener system in JUCE follows the observer pattern.) Many broadcaster objects contain a nested
Listener class, from which we can inherit, in order to become a listener for that type of broadcaster. For example, the Button class contains a nested class Button::Listener for this purpose.
- The Button::Listener class can be used to listen to any of the different button types including instances of the TextButton class as shown here.
Custom classes can become listeners to different types of broadcaster by adding more listener base classes in the same way.
Each listener class has at least one pure virtual function. This is the function that will be called as a callback when the broadcaster object needs to broadcast its change. We must override this in order for the code to compile, and for us to use it.
- Listener classes often contain other virtual functions that may be overridden, but these are optional as they are needed in fewer cases. See the documentation for the Slider::Listener class for an example.
Now, let's implement the
MainContentComponent::buttonClicked() function. Here, we are passed a pointer to the object that has broadcasted the change. We can then compare this pointer with other objects to determine which object it was:
- : Here we compare the pointer passed to the function with the address of our button, to see if it matches. You should do this even if you have only one button, as we do here. It is safe to compare the pointer to the base Button class passed to the function with instances of Button subclasses, such as the TextButton class as shown here.
- : This uses the Time class to get the current time from the operating system.
- : This converts the Time object to a readable string. The two
boolvalues allow some customisation of the output (see the documentation for the Time::toString() function for more information).
- : Here we update the text displayed within the label.
dontSendNotificationargument  prevents the label from broadcasting this change to its listeners, should it have any. (Label objects can have listeners since they can be used to edit text, too.) In this case we know that it can't have any listeners (as it is our own private member) but it is good practice to be specific.
In order to receive the messages that are broadcast, we need to register our listener object with one or more broadcaster objects. In this case, we need to register with the TextButton object. Typically, this would be done within the constructor of the listener subclass :
- Most broadcaster objects have an
addListener()function for this purpose (the ChangeBroadcaster object is an exception, it has the ChangeBroadcaster::addChangeListener() function instead).
Broadcasters will also have a
removeListener() function, too. For example, see the Button::removeListener() function. Since our button is owned by the same class that is performing the listening we don't really need to remove the listener as the button will be destroyed at the same time as the listener. For completeness, we could add this to our destructor:
- Removing listeners appropriately is important if you set up more complex broadcaster-listener systems.
Build and run the application now. When you click the button it should display the time within the label.
- The completed code for this section can be found in the
MainComponent_02.hfile within the
Sourcedirectory of the demo project for this tutorial.
- Try changing the format of the text displayed. You can do this by changing the arguments passed to the Time::toString() function. You could also change the code such that the label displays the number of milliseconds between button clicks, rather than the absolute time.
An example implementation of the code for the final exercise can be found in the files
MainComponent_03.cpp within the
Source directory of the demo project for this tutorial.
In this tutorial we have introduced the basics of the broadcaster-listener system in JUCE. While we have focused on buttons in this tutorial, the same techniques can be applied to many areas of JUCE code. In particular we have learned:
- How to make one of our custom classes a listener-type object.
- How to add the listener callback function.
- How to register and deregister as a listener with a broadcaster object.
- How to access the current time using the Time class.
Generated on Fri Jan 12 2018 09:51:15 for JUCE by 1.8.13