Skip to content

First Button

passivist edited this page Jan 20, 2017 · 6 revisions

First Button

Setup

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 this1 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:

Open Button

Button Interaction

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
    }
}
  1. 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 of FileChooser takes three arguements:
  2. A title for the file dialogue.
  3. 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.
  4. A list of file extensions the dilalogue should allow the user to select.
  5. 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 a File object that holds the result of FileChooser dialogue. Then we copy the full path into a String variable named 'path'. Lastly we swap the values of chosenPath and path. path now holding an empty string and chosenPath holding the path to the file the user selected.
  6. Finally we wake up the background thread with a call to the function notify. This executes the run 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.

Clone this wiki locally