Getting started: projects, applications, and windows
Set up a JUCE project, understand what the generated files do, and put a window and a main component on screen.
Level: Beginner
Choose a project type
| You want to build | CMake target | Starting point |
|---|---|---|
| A desktop or mobile app with a GUI | juce_add_gui_app | examples/CMake/GuiApp |
| A command-line tool with no GUI | juce_add_console_app | examples/CMake/ConsoleApp |
| An audio plug-in (VST3, AU, AUv3, AAX, LV2, ...) | juce_add_plugin | examples/CMake/AudioPlugin |
If you are unsure, start with a GUI app. The Projucer offers the same choices (plus audio, animated, and OpenGL app templates) and exports to Xcode, Visual Studio, and Linux Makefiles. Its templates only differ in which base class MainComponent derives from: Component for GUI apps, AudioAppComponent for audio apps (see Audio input, output, and playback), and AnimatedAppComponent for animation (see Graphics, layout, and animation).
Create a project with CMake
Make a new, empty folder for the project (for example HelloJuce) and create four files in it:
HelloJuce/
├── CMakeLists.txt # the build configuration (this section)
├── Main.cpp # the application class and window (next section)
├── MainComponent.h # the main component's declaration
└── MainComponent.cpp # the main component's implementationThe minimum a GUI app needs is Main.cpp and MainComponent.cpp, plus the header that lets Main.cpp see MainComponent. Put this in CMakeLists.txt, which is the file CMake reads when you run cmake -B build:
cmake_minimum_required(VERSION 3.22)
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "macOS architectures") # must come before project()
project(HELLO_JUCE VERSION 0.0.1)
file(REAL_PATH "~/JUCE" JUCE_DIR EXPAND_TILDE) # JUCE cloned to ~/JUCE; or use find_package (JUCE CONFIG REQUIRED)
add_subdirectory(${JUCE_DIR} JUCE)
juce_add_gui_app(HelloJuce PRODUCT_NAME "Hello JUCE")
target_sources(HelloJuce PRIVATE Main.cpp MainComponent.cpp)
target_compile_definitions(HelloJuce PRIVATE
JUCE_WEB_BROWSER=0
JUCE_USE_CURL=0
JUCE_APPLICATION_NAME_STRING="$<TARGET_PROPERTY:HelloJuce,JUCE_PRODUCT_NAME>"
JUCE_APPLICATION_VERSION_STRING="$<TARGET_PROPERTY:HelloJuce,JUCE_VERSION>")
target_link_libraries(HelloJuce
PRIVATE juce::juce_gui_extra
PUBLIC juce::juce_recommended_config_flags
juce::juce_recommended_warning_flags)The CMakeLists.txt above expects JUCE to be cloned to ~/JUCE. If yours is elsewhere, change the path on the file (REAL_PATH ...) line. The next two sections give you Main.cpp, MainComponent.h, and MainComponent.cpp; build and run once all four files exist.
The CMAKE_OSX_ARCHITECTURES line makes macOS builds target Apple Silicon (arm64) by default. It has no effect on other platforms. Pass -DCMAKE_OSX_ARCHITECTURES=x86_64 (or "arm64;x86_64" for a universal binary) when you configure to override it, and use a fresh build folder if you change it.
Each JUCE module you use is a juce::juce_<module> target to link against. See the CMake API for every option.
Projucer users: a Projucer project is a
.jucerfile plus aSourcefolder. Add source files and modules in the Projucer, choose an exporter per IDE, then save to regenerate the IDE project. Each module and configuration can be tuned in the project settings. The Projucer's GUI editor has been removed, so lay out interfaces in code.
The application class
Main.cpp contains a class derived from juce::JUCEApplication. It provides startup and shutdown hooks and is registered with START_JUCE_APPLICATION. The first line includes MainComponent.h, which in turn pulls in the JUCE headers:
#include "MainComponent.h"
class HelloJuceApplication final : public juce::JUCEApplication
{
public:
const juce::String getApplicationName() override { return JUCE_APPLICATION_NAME_STRING; }
const juce::String getApplicationVersion() override { return JUCE_APPLICATION_VERSION_STRING; }
void initialise (const juce::String&) override
{
mainWindow.reset (new MainWindow (getApplicationName()));
}
void shutdown() override { mainWindow = nullptr; } // deletes the window
void systemRequestedQuit() override { quit(); }
class MainWindow final : public juce::DocumentWindow
{
public:
explicit MainWindow (juce::String name)
: DocumentWindow (name, juce::Colours::lightgrey, allButtons)
{
setUsingNativeTitleBar (true);
setContentOwned (new MainComponent(), true);
setResizable (true, true);
centreWithSize (getWidth(), getHeight());
setVisible (true); // required, or the window never appears
}
void closeButtonPressed() override
{
juce::JUCEApplication::getInstance()->systemRequestedQuit();
}
};
private:
std::unique_ptr<MainWindow> mainWindow;
};
START_JUCE_APPLICATION (HelloJuceApplication)Points worth knowing:
JUCE_APPLICATION_NAME_STRINGandJUCE_APPLICATION_VERSION_STRINGare the compile definitions set inCMakeLists.txt, so the name and version are defined in one place.initialise()runs as soon as the app starts, andshutdown()is where you release everything that must die before JUCE does. Keeping the window in astd::unique_ptrmakes that a one-liner.DocumentWindowtakes a title, a background colour, and a bitmask of title bar buttons. CombineminimiseButton,maximiseButton, andcloseButtonwith|, or useallButtons.setUsingNativeTitleBar (true)gives the operating system's own window chrome and behaviour. Leave it off for an identical look on every platform.setResizable (allowed, useBottomRightCornerResizer): with the second argumentfalse, users resize by dragging any edge. Native title bars ignore it.centreWithSize (w, h)sets the size and centres on screen. UsesetBounds()orsetBoundsRelative()for explicit placement.- Multi-touch is off by default on Windows since JUCE 9; see BREAKING_CHANGES.md.
The main component
Component is the base class of every on-screen object. Your window's content is a component that draws itself in paint() and positions its children in resized():
Declare it in MainComponent.h:
#pragma once
#include <juce_gui_extra/juce_gui_extra.h>
class MainComponent final : public juce::Component
{
public:
MainComponent();
void paint (juce::Graphics& g) override;
void resized() override;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainComponent)
};and implement it in MainComponent.cpp:
#include "MainComponent.h"
MainComponent::MainComponent()
{
setSize (600, 400); // initial size, also the window's initial size
}
void MainComponent::paint (juce::Graphics& g)
{
g.fillAll (getLookAndFeel().findColour (juce::ResizableWindow::backgroundColourId));
g.setColour (juce::Colours::white);
g.setFont (20.0f);
g.drawText ("Hello, JUCE!", getLocalBounds(), juce::Justification::centred, true);
}
void MainComponent::resized()
{
// Position child components here using getLocalBounds()
}paint()is called by JUCE whenever the component needs redrawing. Never call it yourself; callrepaint()instead.resized()is called whenever the size changes, including once after the constructor'ssetSize(). Put all layout there so it adapts to resizing.- Pass
MainComponentto the window withsetContentOwned (..., true)and the window sizes itself to fit. - Use
getLocalBounds()(origin at 0, 0) rather thangetBounds()(position in the parent) when laying out children.
Build and run
With all four files in place, configure and build from the project folder:
cmake -B build
cmake --build buildRun the app
The build puts the finished app in build/HelloJuce_artefacts/. With CMake's default generator (Makefiles on macOS and Linux):
| Platform | Run it with |
|---|---|
| macOS | open "build/HelloJuce_artefacts/Hello JUCE.app" |
| Linux | ./build/HelloJuce_artefacts/Hello\ JUCE |
The Xcode generator is multi-config and adds a configuration folder, for example build/HelloJuce_artefacts/Debug/Hello JUCE.app; build with cmake --build build --config Debug.
"The application cannot be opened because its executable is missing"? CMake creates the empty
.appbundle at the start of the build and only fills in the executable when compiling and linking succeed. Ifcmake --build buildreported errors, fix them and build again, then re-runopen. Check that the last lines of the build output sayBuilt target HelloJuce.
"use of undeclared identifier 'juce'"? CMake projects have no
JuceHeader.h. Every source file must include the module headers it uses.MainComponent.hincludes<juce_gui_extra/juce_gui_extra.h>, andMain.cppincludesMainComponent.h. Leave out those includes and the compiler will not know whatjuce::,std::, orSTART_JUCE_APPLICATIONmean.
Sources
Condensed from the JUCE tutorials Projucer Part 1, getting started with the Projucer, Projucer Part 2, manage your Projucer projects, Projucer Part 3, choosing the right Projucer template for your application, The main component, and The application window, Copyright (c) Raw Material Software Limited, ISC licence. See the attribution notice.