This tutorial demonstrates how to create a minimal app with an application window, and how to customise the size and appearance of that window. This is critical for any JUCE GUI application.
Level: Beginner
Platforms: Windows , macOS , Linux
Classes: JUCEApplication, DocumentWindow, ResizableWindow
Launch the Projucer and create a new GUI application project with the name MainWindowTutorial . In the Files to Auto-Generate: field make sure you select Create a Main.cpp file only .
If you need help with this step, see Tutorial: Projucer Part 1: Getting started with the Projucer.
Modify the MainWindowTutorialApplication
class to include the following MainWindow
class as follows:
Add the following line to the initialise()
function:
Finally, add the following line to the shutdown()
function:
The demo project is a very minimal JUCE app that has only one source file: Main.cpp
. The only thing it does is to create and display an empty application window. This window should open when you run the app:
You can drag this window around, maximise and minimise it, and close it to quit the JUCE app.
The C++ code in this app is just about the minimum amount of code required for a working app. The application class itself (derived from the JUCEApplication class) will be covered in a later tutorial. For now, all the app is really doing is the single line of code in the app's MainWindowTutorialApplication::initialise()
function:
This creates a new instance of the MainWindow
class, which leads to the application window being shown.
initialise()
function will be executed as soon as the app starts.Now let's take a look at the implementation of this MainWindow
class. It derives from the JUCE DocumentWindow class, a resizable window with a title bar, and maximise, minimise, and close buttons. These are all of the elements you would expect from an application window.
The MainWindow
constructor is defined as follows:
First, the base class (DocumentWindow) is initialised, which requires three parameters:
Looking at the code in Main.cpp
, you may notice that the first parameter is actually passed to the MainWindow
constructor by the app's initialise()
function. This is simply the name of the app (and part of the information auto-generated by The Projucer when a project is created, along with the app's version number and and a few other things).
The next two arguments, the background colour and the buttons, are set directly in the MainWindow
constructor. Most common colours have predefined constants in JUCE and can be directly used like in this example. So you could replace the Colours::lightgrey constant with, for example, constants Colours::red or Colours::blue to quickly change the background colour of the whole app window. Of course, it is also possible to define your own custom colours. See Tutorial: Colours in JUCE for a more detailed introduction to colours in JUCE.
The third argument passed to the DocumentWindow base class constructor is the DocumentWindow::allButtons constant. It indicates that all three default buttons (maximise, minimise, and close) should be shown in the title bar. You can change this property by using the following other constants, defined in the enum
DocumentWindow::TitleBarButtons:
Using the C++ operator |
(the bitwise OR operator), you can define any other combination of the three possible buttons. For example, to show only the close and minimise buttons, you could type:
This approach to pass a combination of flags to a function is called a bitmask and is found in many other places in JUCE.
When the MainWindow
object is created, the constructor's body is executed. The first statement calls the Component::centreWithSize() function to set the window's position and size. The second statement, a call to the Component::setVisible() function, is always required for the window to be shown after it has been created.
Using the Component::centreWithSize() function, you can specify the initial width and height of the window in pixels. The function will set the size to the one specified, and then centre the component with respect to its parent component. The DocumentWindow class derives from the TopLevelWindow class, which does not have a parent component, so it will be centered with respect to the whole screen.
You may wish to specify another position for the window. The function Component::setBounds() offers more options in this case. To try this out, change the line containing the call to the centreWithSize()
function to this:
This will set the size to 800 x 600 pixels and position the window closer to the top left corner of the screen (50 pixels away from the screen edge).
The JUCE DocumentWindow class itself inherits from the ResizableWindow class. This base class adds the functionality to make the window resizable by the user. This can be enabled with the function ResizableWindow::setResizable().
Add the following line to the MainWindow
constructor:
Take a look at the documentation for the ResizableWindow::setResizable() function to look up what its two boolean arguments mean. The first one determines whether the window should be resizable at all. The second one lets you add a handle to the bottom right corner to resize the window. If this argument is false
, the window will instead be resizable by dragging with the mouse at any of the window's edges.
So far, we have been using the JUCE look-and-feel for the app's main window. Its main advantage is that will look and behave identically on every desktop operating system (Windows, Mac OS X, and Linux).
However, the JUCE DocumentWindow class allows you to let the window use the typical native window apperance for the operating system you run it on. This is achieved using the function DocumentWindow::setUsingNativeTitleBar(). Add the following line to the MainWindow
constructor:
Now the application's window will look like this:
Please note that this will adjust not only the appearance, but also the behaviour of the window to match that of a native operating system window. For example, now the useBottomRightCornerResizer
argument to the ResizableWindow::setResizable() function will not change the resizing behaviour of the window anymore. Instead, for resizing with the mouse, the window will adopt whatever behaviour is the native look-and-feel of the operating system you are running.
For most apps, the native look-and-feel is a better choice for the main app window, because this is the more familiar look-and-feel that a user will typically expect from a native app.
In this tutorial we have covered how to set the behaviour of a basic JUCE app's main window, such as: adjust its size, make it resizable, set its title and appearance, and define what buttons should appear in its title bar. We have also described how to switch to a native title bar to make the window feel more like a native window on the operating system it is running on.