Juce interaction with TextEditorListener class

Following up on my previous Juce walkthrough, I wanted to cover the basics of event handling in Juce. Juce uses a concept of listener classes, where you create callback functions that will be executed when events occur that the listeners are listening for.

We’ll use the TextEditorListener class as an example: https://www.juce.com/api/classTextEditor_1_1Listener.html

Here’s a video to walk through it all:

The following instructions will follow just a slightly different order of events from the video but the details are all the same.

What we’re creating

So we’re creating this super powerful app to convert string based user input in one TextEditor component to lowercase via another TextEditor. Brilliant eh?

Here’s a completed example: https://github.com/Ugotsta/juce-lowercaser-example

Creating the app

First off, I’ve created the app exactly the same as in my previous tutorial, using Introjucer. I’ve named it “Lowercaser” this time, and the GUI component is aptly named “GUI”. And this time around, we’ll remove all the Juce modules that we won’t be using.

Simply go to the Config tab and right-click, then select “Remove this Module” for the modules we don’t need.

Introjucer - Remove module

Do that for the following: juce_audio_basics, juce_audio_devices, juce_audio_formats, juce_audio_processors, juce_cryptography, juce_opengl, juce_video.

It should then look like this:

Introjucer - Remaining modules

Those remaining modules are as follows:

  • juce_core
  • juce_data_structures
  • juce_events
  • juce_graphics
  • juce_gui_basics
  • juce_gui_extra

Following that previous tutorial the rest of the way, we should have the app setup with a GUI component (named “GUI”) that we can interact with. In the Files tab, click gui.cpp, then click the Class tab.

The parent class setting should read “public Component”. We’ll add a listener class there.

Introjucer - Add public texteditorlistener reference

You can simply change it so it reads like so:

public Component, public TextEditorListener

On to the code

Now let’s click the Code tab for that same gui.cpp component. We’ll add some initial code to get started.

Introjucer - Add code in commented section

Scroll down the code just a bit til you see the following commented tags:


Introjucer uses those tags to provide a way for you to safely add code so that you can still continue using the GUI builder and other Introjucer features. Anything between those tags will remain when any changes occur in Introjucer, such as when GUI components are edited or added. We’ll add some code there.

Simply edit those tags so it reads like so:


That’ll do two things:

  1. The first command will set the text of toEditor to the text of the fromEditor, only in lowercase.
  2. The second command just adds the listener to fromEditor.

Now let’s add the callback function.

Introjucer - Add callback function

Going further down in the code, you’ll see a few more helpful commented tags:

//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...

Those tags are for adding extra methods such as callback functions, like the callback function we’ll be adding. Edit that so it reads like this:

//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
 void GUI::textEditorTextChanged (TextEditor &editor)

That’s a callback for whenever any changes occur within a TextEditor component. In this case, we’ve added a listener to the fromEditor above, so any changes in that will trigger this callback function and the single line of code which changes the text of toEditor to a lowercase version of fromEditor.

You’ll see that’s the same line of code we used to change the toEditor text previously as well.

Lastly, let’s add a reference to that callback function in our header file.

Introjucer - Add callback reference in gui.h

In the Files dialog, click the gui.h file. You’ll see a few more helpful tags as follows:

//[UserMethods] -- You can add your own custom methods in this section.

Let’s change that like so:

//[UserMethods] -- You can add your own custom methods in this section.
 void textEditorTextChanged (TextEditor &editor);

That’s it!

We’re done. We can simply go to File > Save All and then File > Save Project to ensure our code is all saved. And we can then use the build process from the “Get started” tutorial to build the executable file.

When run, we should see something like so:

Lowercaser compiled app

Just to mention again, Juce is cross-platform, available for Mac, Windows and Linux. And the toolkit supports Android, iOS and I believe Arm-based apps so that apps utilizing the toolkit can work across those platforms too. I’ll need to give those other platforms a try myself, maybe for a future video. 🙂

I hope that helps. I suspect I’ve missed some things so please feel free to ask questions.

Juce interaction with TextEditorListener class

7 thoughts on “Juce interaction with TextEditorListener class

  1. babazaroni says:

    I ran this demo on El-Cap. The text editor does not accept keyboard input. Maybe the component needs to be enabled now.

    1. Grief, I can’t believe I missed this comment! So sorry for that. I take it you were using a Mac (El Capitan)? If it’s still an issue, could you let me know if you tried compiling the example project? Just wondering if maybe you ticked an option to disable input in your own project?

  2. I’m trying this tutorial, but I get a bunch of horrible compile errors. Pretty sure that I copied the instruction word for word. Any ideas?

    In file included from ../../Source/caseGUI.cpp:23:0:
    ../../Source/caseGUI.h:38:1: error: expected class-name before ‘{’ token
    ../../Source/caseGUI.cpp: In constructor ‘caseGUI::caseGUI()’:
    ../../Source/caseGUI.cpp:63:30: error: no matching function for call to ‘juce::TextEditor::addListener(caseGUI*)’
    In file included from /home/liam/Desktop/JUCE/modules/juce_gui_basics/juce_gui_basics.h:231:0,
    from ../../Source/../JuceLibraryCode/JuceHeader.h:21,
    from ../../Source/caseGUI.h:23,
    from ../../Source/caseGUI.cpp:23:
    /home/liam/Desktop/JUCE/modules/juce_gui_basics/widgets/juce_TextEditor.h:316:10: note: candidate: void juce::TextEditor::addListener(juce::TextEditor::Listener*)
    void addListener (Listener* newListener);
    /home/liam/Desktop/JUCE/modules/juce_gui_basics/widgets/juce_TextEditor.h:316:10: note: no known conversion for argument 1 from ‘caseGUI*’ to ‘juce::TextEditor::Listener*’
    ../../Source/caseGUI.cpp: At global scope:
    ../../Source/caseGUI.cpp:111:7: error: ‘GUI’ has not been declared
    void GUI::textEditorTextChanged (TextEditor &editor)
    ../../Source/caseGUI.cpp: In function ‘void textEditorTextChanged(juce::TextEditor&)’:
    ../../Source/caseGUI.cpp:113:5: error: ‘toEditor’ was not declared in this scope
    ../../Source/caseGUI.cpp:113:5: note: suggested alternative: ‘editor’
    ../../Source/caseGUI.cpp:113:23: error: ‘fromEditor’ was not declared in this scope
    ../../Source/caseGUI.cpp:113:23: note: suggested alternative: ‘editor’
    Makefile:92: recipe for target ‘build/intermediate/Debug/caseGUI_9cd946ec.o’ failed
    make: *** [build/intermediate/Debug/caseGUI_9cd946ec.o] Error 1

    1. Hi @LGOODACRE,

      Sorry you’ve had trouble with it. Since I don’t know the exact structure of your caseGUI files, I can’t quite tell what’s happening. But I think this should be solvable

      Could you try downloading and compiling the example project?

      Any errors you see with that, I can easily see the respective code.

      I’d be proactive and re-compile that using Projucer now but I’m having trouble with the latest version (it requires some dependencies that are a bit of an issue on my Kubuntu system). If you can let me know any resulting errors from compiling the example on your end though, I’ll have a reference to troubleshoot it.

      Just another note, I compiled this without trouble on the past version of Juce and Introjucer that was available when I wrote this all up. Changes have occurred since then and I’m not sure how well it works with the current version. Incidentally, I’ve been learning Rust recently because it helps avoid the mess of dependencies I’ve just described.

      Rant over. 🙂 Hoping we can get this sorted fast, looking forward to further word from you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s