-
Notifications
You must be signed in to change notification settings - Fork 12
First Button
To create a button we must once again utilize a JUCE base class: the Button
class. In the case of GUI elements we don't directly inherit from the Button
class but from a member of Button
called Listener
. The Listener
implements callback functions for all actions performed on or with the Button
. We change the inheritance of the AudioProcessorEditor
class to look like this:
class GrrnlrrAudioProcessorEditor : public AudioProcessorEditor,
public Thread,
private Button::Listener
The function implementing the callback buttonClicked(Button* button)
has to be declared and implemented in the header and .cpp files respectively. Also we declare the variable TextButton openButton
in the header file.
For the button to be displayed and functional we have to initialize a few values in the constructor of the AudioProcessorEditor
class:
GrrnlrrAudioProcessorEditor::GrrnlrrAudioProcessorEditor (GrrnlrrAudioProcessor& p)
: AudioProcessorEditor (&p), Thread("sample loading thread"), processor (p)
{
addAndMakeVisible(openButton);
openButton.setButtonText("Open...");
openButton.addListener(this);
formatManager.registerBasicFormats();
startThread();
setSize (400, 300);
}
The first function, addAndMakeVisible
adds the GUI component that is supplied as an argument to the window of the Plugin. The second function sets the text to display on the button. The third function addListener
registers the current AudioProcessorEditor
object this
1 as the receiver of the callbacks from the button. The effect of this is that the buttonClicked
function is called every time we click on the button.
Before we take a closer look at the buttonClicked
function we should make our button actually show up on the GUI. In addition to calling addAndMakeVisible
we have to also give our button a position and a size. This is done in the resized
function of the AudioProcessorEditor
:
openButton.setBounds(10, 10, 120, 20);
At this point we can also delete everything in the function body of the draw
function except g.fillAll(Colours::White)
. After compilation our plugin should look something like this:
Now let's have a closer look at the buttonClicked
function. The first thing I always try when implementing a new feature is first making sure the function is actually called by outputting some text:
void GrrnlrrAudioProcessorEditor::buttonClicked(Button* button)
{
std::cout << "a button has been clicked!" << std::endl;
}
If we compile now and click the button the text a button has been clicked
should appear in your console. Once we are sure that the button is working we add a function void openButtonClicked()
to the AudioProcessorEditor
class. Then we rewrite buttonClicked
to call openButtonClicked
when that specific button has been pressed:
void GrrnlrrAudioProcessorEditor::buttonClicked(Button* button)
{
if(button == &openButton) openButtonClicked();
}
Finally we add the code for the file dialog to openButtonClicked
:
void GrrnlrrAudioProcessorEditor::openButtonClicked()
{
FileChooser chooser ("Select a File to open...", // 1
File::nonexistent,
"*.wav", "*.aif", "*.aiff");
if(chooser.browseForFileToOpen()){ // 2
const File file (chooser.getResult());
String path (file.getFullPathName());
swapVariables (chosenPath, path);
notify(); // 3
}
}
-
FileChooser
is a class for creating dialogues for opening and saving files. Additionally the class provides methods for checking if a file was selected and returning a reference to the selected file. The constructor ofFileChooser
takes three arguements: - A title for the file dialogue.
- A reference to a File object from which to derive a path as the default path for the dialogue. If an empty file (
File::nonexsistent
) is supplied then a suitable path is taken according to the OS the plugin is running on. Usually this is the "home" or "User" folder. - A list of file extensions the dilalogue should allow the user to select.
- The function
browseForFileToOpen
creates the dialogue and once the dialogue has been closed returns a bool signifying if the user has chosen a file or not. If the user has chosen a file we first create aFile
object that holds the result ofFileChooser
dialogue. Then we copy the full path into aString
variable named 'path'. Lastly we swap the values ofchosenPath
andpath
.path
now holding an empty string andchosenPath
holding the path to the file the user selected. - Finally we wake up the background thread with a call to the function
notify
. This executes therun
function and results in the loading of the file at the path we selected by pressing the open button.
When we compile the plugin now we should be able to load sound files via a file dialogue. Additionally we have learned valuable techniques for extending our program.
In the next chapter we will implement a basic scheduling algorithm for triggering multiple grains.
<<< last Chapter next Chapter >>>
1: The function addListener
expects a pointer to an object of type ButtonListener
as an argument. The keyword this
denotes a reference to the object from which this
is called. In our case this
is our AudioProcessorEditor
object. Since AudioProcessorEditor
inherits from Button::Listener
AudioProcessorEditor
is now of type ButtonListener
. In this way the Button
object is bound to our AudioProcessorEditor
object.