[size=75]UPDATE: THIS IS VERY OLD SAMPLE CODE.[/size]
[size=50]
It is also redundant, as the Introjucer can auto-generate a shell app to suit this purpose just fine.
Therefore, don’t bother using this! Just create a new app with a main window using the introjucer!
I’m leaving the post below for historical purposes
[/size]
I’ve still not got any new web hosting yet, so I’ve not got anywhere to upload any files. I still get regular emails asking about my tutorial files, and how to fix them etc… as they’re out of date. Well, in the mean time, I thought I’d copy/paste the code from the updated starting point files to keep newcomers happy. Thus…
[size=150]Starting Point guide[/size]
Here is a guide to creating your own blank project for juce, along with the starting point code to get you up and running. This guide in particular is for Visual C++ Express Edition, although the code (at the end) doesn’t care about that (if that’s all you’re after).
First of all, follow the instructions in the juce readme docs to make sure you’ve got your compiler directories all configured properly.
[size=150]Creating a suitable blank Juce project in VC++e[/size]
Create a new project, choosing ‘Win32 Console application’ and giving it an appropriate name. Click ‘OK’.
In the next window, click ‘Application Settings’ on the left hand side, and then make the following changes:
- Select ‘Windows application’
- Enable the ‘Empty project’ option
Then, click ‘Finish’.
You now have a blank project with no files in it. It’s not quite ready for linking up with Juce yet, so you need to also make some adjustments to the run-time library settings. However, VC++e doesn’t make this setting available until it knows your project is using the C++ language; you need to first add a C++ code file to the project.
Your blank project starts with three ‘filters’ (folders) visible in the ‘solution explorer’ on the left hand side. These help you organise your code files in the project, they don’t correspond to the actual directory structure. Personally, I don’t really like those ones (header, resource and source files), so I delete them and create more appropriate ones. You may wish to use them as they are.
I’m going to give you some ‘starting point’ code here. Each code section below should belong in a separate file, with the files named as indicated.
Before I give you the code though, I’ll just explain how to add a new file to the project…
[size=150]Adding a new file…[/size]
To add a new file to the project, right-click on where you want it to go in the solution explorer (either on a filter or on the project above them), and select “Add->New item”.
Choose ‘Code’ on the left, then the type of file you want (.cpp or .h). Give it a name (and choose a specific location if you like - I make a subdirectory called ‘src’ out of habit) and click ‘Add’. Your new (blank) file will now be ready to edit, and will appear in the solution explorer.
Note that if you left the default filters in, and the item you right-clicked on was the project itself, the file will automatically be placed into the relevant filter (i.e. header or source).
Now you know how to add new files, create four new files with the following names:
ApplicationStartup.cpp
MainAppWindow.cpp
MainAppWindow.h
MainComponent.h
These will be the ‘starting point’ files.
Now that VC++e knows what language you’re using, you can make the required adjustments to the project properties…
[size=150]Configuring the project’s Runtime Library[/size]
Go to the ‘Project’ menu at the top, and click ‘Properties’.
In the left hand side, you need to locate the following item:
Configuration Properties->C/C+±>Code Generation
You need to change the ‘Runtime library’ item to the ‘non-DLL’ version of whatever is selected for both DEBUG and RELEASE configurations.
At the top-left, there is a ‘Configuration’ combo-box, which chooses the configuration you’re adjusting. Make the following changes:
For ‘DEBUG’ config, set Runtime Library to “MultiThreaded Debug”. Click 'Apply’
For ‘RELEASE’ config, set Runtime Library to “MultiThreaded”. Click ‘Apply’ (and then of course ‘Ok’).
Now your project is correctly configured, you can paste the following code blocks into their corresponding files.
[size=150]Starting point code[/size]
ApplicationStartup.cpp
/*
==============================================================================
JUCE library : Starting point code, v1.26
Copyright 2005 by Julian Storer. [edited by haydxn, 3rd April 2007]
------------------------------------------------------------------------------
ApplicationStartup.cpp :
This file describes how the application will be brought to life within the
operating system. The basic order of things is...
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The [OS] creates the 'AppClass', which is a shell for the program,
and is responsible for bringing everything to life...
... the [AppClass] creates the MainAppWindow and puts it on the screen...
... the [MainAppWindow] is a visible base for the program, and it
creates the program's MainComponent upon itself...
... the [MainComponent] then 'does' the main 'program stuff'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you're only writing simple applications, there's very little that you'd need
to do in here, as the app shell is only really responsible for creating the window
and getting everything running.
You will, however, probably want to set the size of the window to something suitable.
This is done in the initialise function, after the window has been created.
------------------------------------------------------------------------------
Please feel free to do whatever you like with this code, bearing in mind that
it's not guaranteed to be bug-free!
==============================================================================
*/
#include "MainAppWindow.h"
//==============================================================================
class AppClass : public JUCEApplication
{
/* Important! NEVER embed objects directly inside your JUCEApplication class! Use
ONLY pointers to objects, which you should create during the initialise() method
(NOT in the constructor!) and delete in the shutdown() method (NOT in the
destructor!)
This is because the application object gets created before Juce has been properly
initialised, so any embedded objects would also get constructed too soon.
*/
MainAppWindow* theMainWindow;
public:
//==============================================================================
AppClass()
: theMainWindow (0)
{
// This is where the application itself is created. It's a bit like a shell, which
// all your real app stuff gets born into. At this point (where the app pops into
// being), Juce doesn't really 'exist' yet, so we can't do anything with it here.
// Once this application shell has been established, Juce will be awake so we can
// create instances of its classes willy-nilly.
// [Jules says...]
// NEVER do anything in here that could involve any Juce function being called
// - leave all your startup tasks until the initialise() method.
}
~AppClass()
{
// This is where the application body is destroyed, and making any Juce calls in
// here could be very dangerous.
// Just as Juce wasn't awake when the shell was created, by this stage it's been
// tidied away and put to sleep. This is the bit that happens AFTER your program
// code has ended (and hopefully put all its toys away).
// [Jules says...]
// Your shutdown() method should already have done all the things necessary to
// clean up this app object, so you should never need to put anything in
// the destructor.
}
//==============================================================================
void initialise (const String& commandLine)
{
// This is called automatically when the application is ready to launch.
// So far, it just exists in memory as an empty pocket of potential waiting
// to burst into life as a program. Nothing yet exists to act or be displayed.
// All we want to do here is create the main window. This instantiates an object
// of 'MainAppWindow' - which we have defined in MainAppWindow(.h/.cpp). The app's
// behaviour comes from that, so all we need is to bring it to life...
theMainWindow = new MainAppWindow();
// ... and plonk it onto the display...
theMainWindow->centreWithSize (300, 300); // [*] (see below for a tip on this)
// ... (of course making sure that it is visible!)
theMainWindow->setVisible (true);
// That's all we have to do here. Once this function has ended, the Juce
// application will start firing its event loop. This is basically the
// engine that powers the Juce app classes (giving life to the Component
// and messaging model), and is something that will just happen by itself.
// The event dispatch loop will keep the app alive until something calls
// JUCEApplication::quit() - which could be windows closing the application,
// or the user clicking the window's close button.
// [*] When you set the size of the window, there is something important to bear
// in mind: The dimensions you set here are for the window component itself.
// If this is a DocumentWindow (which is the most obvious thing for it to be),
// then it will have a titlebar and a border. The content component sits inside
// this arrangement of parts - which means that your program's main component
// dimensions will actually be slightly smaller than the values you set here.
// This only matters if you're relying on positioning your program's various
// widgets using constant values instead of calculating relative positions from
// the available dimensions (i.e. saying 'this button is 50 pixels wide' instead
// of 'this button is 1/3 of the width of its parent component').
}
void shutdown()
{
// This gets called when the application is ready to shut down.
// Anything that we created in the initialise() function should be destroyed,
// so that nothing is left hanging around when the app shell ceases to exist.
// All we need to do here is delete the MainAppWindow we created...
deleteAndZero (theMainWindow);
}
//==============================================================================
const String getApplicationName()
{
// The name for the application
return T("Juce tutorial application");
}
const String getApplicationVersion()
{
// Here we can give a 'version' indicator, to distinguish one build from
// another. If you update your program, it's a good idea to also update
// the string returned here.
return T("0.0");
}
bool moreThanOneInstanceAllowed()
{
// We can prevent multiple instances of the application here by returning false.
return true;
}
void anotherInstanceStarted (const String& commandLine)
{
// This will get called if the user launches another copy of the application.
}
};
//==============================================================================
// This macro creates the application's main() function..
START_JUCE_APPLICATION(AppClass)
MainAppWindow.cpp
/*
==============================================================================
JUCE library : Starting point code, v1.26
Copyright 2005 by Julian Storer. [edited by haydxn, 3rd April 2007]
------------------------------------------------------------------------------
MainAppWindow.cpp :
This file defines the configuration of the main application window, which
is the class MainAppWindow.
The JUCE class 'DocumentWindow' is the base for this class, so examine the
documentation for any functions that you may wish to use, or any other
configuration options you may wish to change.
The 'window' is the main bit that the program sits within. That means 'the
bit with the title bar and the overall size/shape of the program, but without
the actual program on it yet'. Your program lives in the 'MainComponent' class,
and is added to this window as the 'content component'.
------------------------------------------------------------------------------
Please feel free to do whatever you like with this code, bearing in mind that
it's not guaranteed to be bug-free!
==============================================================================
*/
#include "MainAppWindow.h"
#include "MainComponent.h"
//==============================================================================
MainAppWindow::MainAppWindow()
:
// Initialise the base 'DocumentWindow'...
DocumentWindow (
T("Tutorial app"), // Set the text to use for the title
Colours::azure, // Set the colour of the window
DocumentWindow::allButtons, // Set which buttons are displayed
true // This window should be added to the desktop
)
{
setResizable (true, false); // resizability is a property of ResizableWindow, which is
// a parent class of DocumentWindow (which is our base class),
// so we have access to this setting here.
setTitleBarHeight (20); // Set the height of the titlebar on our window.
// create the main component, which is described in MainComponent.h
MainComponent* contentComponent = new MainComponent ();
// This sets the main content component for the window to be whatever MainComponent
// is. The nature of DocumentWindow means that the contentComponent will fill the main
// area of the window, and will be deleted automatically when the window is deleted.
setContentComponent (contentComponent);
}
MainAppWindow::~MainAppWindow()
{
// Our 'content component' will get deleted by the destructor in the DialogWindow
// base class, and that will, in turn (assuming the MainComponent has been coded
// properly), clean up the other components contained inside it. Therefore, we have
// nothing much to do here!
}
void MainAppWindow::closeButtonPressed()
{
// This is a virtual function provided by the DocumentWindow class, allowing us
// to define the action taken when the window's 'close' button is pressed.
// The correct thing to do when you want the app to quit is to call the
// JUCEApplication::systemRequestedQuit() method.
// That means that requests to quit that come from your own UI, or from other
// OS-specific sources (e.g. the dock menu on the mac) all get handled in the
// same way.
// So, here, we get the application instance (from the static getInstance()
// function in JUCEApplication), and call the function we need from it...
JUCEApplication::getInstance()->systemRequestedQuit();
}
MainAppWindow.h
/*
==============================================================================
JUCE library : Starting point code, v1.26
Copyright 2005 by Julian Storer. [edited by haydxn, 3rd April 2007]
------------------------------------------------------------------------------
MainAppWindow.h :
This file is just a declaration of the MainAppWindow class. For more
detailed information of its purpose, examine the MainAppWindow.cpp
file.
Having it as a separate header file may seem pointless, but it could
save a bit of effort should you be embarking on a complex project and
wish to still use this fileset as a starting point.
------------------------------------------------------------------------------
Please feel free to do whatever you like with this code, bearing in mind that
it's not guaranteed to be bug-free!
==============================================================================
*/
#ifndef _MainAppWindow_H__
#define _MainAppWindow_H__
#include "juce.h"
//==============================================================================
class MainAppWindow : public DocumentWindow
{
public:
//==============================================================================
MainAppWindow();
~MainAppWindow();
//==============================================================================
// called when the close button is pressed or esc is pushed
void closeButtonPressed();
// It is most likely that your program will be happy thinking of the window's
// content component as the 'base' level of the application; it can be responsible
// for storing and maintaining anything considered crucial to the running of the
// program.
// However, if you want to have anything live above even that, you may
// want to put it here. You may even wish to step further outside of things and keep
// some higher management system within the JUCEApplication class that drives the
// whole shebang, but that's probably not necessary, and can be tricky to maintain!
};
#endif
MainComponent.h
/*
==============================================================================
JUCE library : Starting point code, v1.26
Copyright 2005 by Julian Storer. [edited by haydxn, 3rd April 2007]
------------------------------------------------------------------------------
MainComponent.h :
This file defines the behaviour of the application. The main part of the
program that the user interacts with IS this MainComponent object. It is
placed within the MainAppWindow instance, and so exists at whatever size
the window provides in its content area.
All of the widgets and controls that your main program window will display
will be on this component (either directly or somewhere down the children
hierarchy).
------------------------------------------------------------------------------
Please feel free to do whatever you like with this code, bearing in mind that
it's not guaranteed to be bug-free!
==============================================================================
*/
#ifndef _MAINCOMPONENT_H_
#define _MAINCOMPONENT_H_
#include "juce.h"
class MainComponent : public Component // Here we specify any base classes that
// give this type predefined characteristics.
// Naturally, this is a Component, but we could
// also inherit other qualities. For example, if
// we want to respond to button presses, we can
// inherit 'ButtonListener', by changing it thus:
// e.g.
// public Component,
// public ButtonListener
// (Notice that they're separated by a comma, and nothing comes after the
// final one in the list - i.e. no semicolon, because the next character
// must be the '{' denoting the start of the class body).
// We can inherit many different classes from Juce (or classes we make
// ourselves), but be aware that some base classes require you to define
// some function bodies before it will allow your app to compile. These
// functions are called 'pure virtual' functions - an example would be
// 'buttonClicked' in ButtonListener. Some base classes will provide many
// other virtual functions - not just pure virtual ones - which you can
// define if you choose, but you do not have to do so.
{
private:
//==============================================================================
// Here are some members that are useful to have in any application...
TooltipWindow tooltipWindow; // To add tooltips to an application, you
// just need to create one of these and leave it
// there to do its work.
// Your app will obviously have some kind of member variables, and so this
// is the place you can declare them. For example, if you wanted to have a
// widget or some component you've made, you'd have a pointer for it here;
// you'd then instantiate the object in the constructor, and use the pointer
// to access it elsewhere (e.g. to position it, update it, or respond to it).
// e.g.
// TextButton* myButton;
public:
//==============================================================================
MainComponent ()
{
// This is where the main component is created, so we initialise and
// configure it according to our needs.
// One thing that covers is creating any widgets and components we want to
// display. Also, if any widgets will need responding to, we must hook them up
// to their listeners here too (and it's likely that this class itself will be
// the listener in question, providing we've inherited the appropriate class!)
// Create and add the rest of your components here!
// e.g.
//myButton = new TextButton (T("my button"), T("Click me!"));
//addAndMakeVisible (myButton);
}
~MainComponent ()
{
// Be sure to destroy any objects you've created using 'new' here. If your objects
// are on the stack (i.e. they were created without pointers or the 'new' operator,
// then they die automatically. If you've created them
// manually on the heap (for example, if you've got a pointer and you've created a new
// object for it) then it must be deleted.
// However, juce has a nice neat function that will destroy all Components that have
// been added to a Component...
deleteAllChildren(); // This will remove all the contained components, and delete
// the objects for you.
}
//==============================================================================
void resized ()
{
// This is called whenever this component's size changes. We could respond
// to this in a number of ways, but the most obvious thing to do is reposition
// all our widgets, using their 'setBounds()' function.
// It's nice to position them relative to the size of this Component. That means
// making use of the 'getWidth()' and 'getHeight()' functions to determine where
// to put them and how big they should be.
}
void paint (Graphics& g)
{
// This does any drawing required on this Component's face. You can simply
// call functions on the provided Graphics object - although you may want to
// make use of 'getWidth()' and 'getHeight()' (members of this Component) to
// make sure you're drawing in the right place!
}
//==============================================================================
};
#endif//_MAINCOMPONENT_H_
You’ll notice that the code is chock-full of comments; this is to help explain what each part is for, as well as provide an overview of the basic structure of a Juce application.
Once you’ve got all this code pasted into your files (and saved them) you should be able to compile the project.
If all goes smoothly, you should have a nice blank boring window come up. If so, congratulations! You can copy this project’s folder somewhere as a template if you like. Rather than set up a new project each time, you can just make a copy of your template project folder, open the project from the copy and rename it. If you do that, you might want to strip the detailed comments out first in your template.
And that’s about it! I hope this is useful to newcomers.