※ Introducer가 제공하는 Hello World Example을 실행시켜 보겠습니다.
예제 실행
1. Introducer를 실행시키고 GUI Application버튼을 클릭합니다.
2. 프로젝트를 생성하고 ( JUCE Library 설치 및 프로젝트 생성 쪽을 참고하시기 바랍니다.) 자신이 사용하는 IDE(개발툴)을 이용하여 열어 컴파일합니다.
3. 실행 결과를 확인합니다.
분석
※저의 분석이 잘못된 정보를 포함하고 있을 수 있습니다. 참고하시고 봐주세요.
어떤 하나의 윈도우가 화면에 보여지기 위해서는 프로그램을 시작시켜 주는 어떠한 함수나 윈도우에 필요한 기본적인 정보(윈도우 창 이름, 크기, 버전 정보 등등)가 필요합니다.( 우리가 알고 있는 main함수나 기타 등등) 그 역활을 하는 것이 JUCEApplication 클래스, START_JUCE_APPLICATION 메크로입니다.
1. JUCEApplication 클래스
JUCEApplication 클래스는 구조적으로 윈도우 구성에 필요한 특정 초기화함수와 종료코드가 포함이 되어있습니다. JUCEApplication클래스는 JUCEApplicationBase클래스와 ApplicationCommandTarget 클래스를 상속받아 구현되어 있습니다. 클래스안에 구성되어 있는 함수는 아래와 같습니다.
JUCEApplication 클래스에 대한 정보는 http://www.juce.com/api/classJUCEApplication.html 에 있습니다.
JUCEApplication 클래스를 상속받고 자신의 목적에 맡게 필요한 함수를 오버라이드해서 사용하시면 되는데 Introducer 프로그램으로 생성한 Hello World Example 프로젝트에서는 getApplicationName(), getApplicationVersion(), initialise(), shutdown(), systemRequestQuit(), anotherInstanceStarted()가 오버라이딩 되어 있습니다. 제 개인적인 견해로는 혹여 다른 구현을 위해 가능하다면 모든 함수를 오버라이딩 시켜놓고 내용을 비워두시면 나중에 찾을 필요 없고 편할것 같습니다. JUCEApplication 클래스에 구현되어 있는 함수의 기능을 풀이하면 아래와 같습니다.
virtual const String getApplicationName() / 어플리케이션 이름을 리턴합니다.(이 부분을 구현하면 타이틀 이름이 바뀝니다.)
virtual const String getApplicationVersion() / 어플리케이션 버전을 리턴합니다. (이 부분을 구현하면 어플리케이션의 버전 정보가 바뀝니다.)
bool moreThanOneInstanceAllowed() / 이것은 제가 사용해보지 않아서 정확하게는 모르겠지만 추측하건데 여러 윈도우를 팝업시킬때 , multiple instance app을 구현시 그 사용여부를 결정하는 함수 같습니다. Hello World Example 코드에서는 true로 리턴하도록 구현되어 있습니다.
void anotherInstanceStarted(const String &commandLine) / 이것 또한 정체를 알 수 없으나 사용자가 다른 어플리케이션 인스턴스를 실행하려 할때 호출된다고 설명되어 있습니다. (Indicates that the user has tried to start up another instance of the app)
void systemRequestedQuit() / OS가 application을 종료하려고 할때 호출된다고 합니다.
void suspended() / OS에 의해 프로그램이 background mode 상태로 바뀔때 호출된다고 합니다.
void resumed() / OS에 의해 프로그램이 background mode에서 동작 상태로 바뀔때 호출된다고 합니다.
void unhandledExeption(const std::exception *e, const String &sourceFilename, int lineNumber )/ 메시지 루프에서 예외가 발생했을때 호출되는데 이 함수를 이용해서 로그를 보거나 예외처리를 할수 있다고 하는군요.
ApplicationCommandTarget * getNextCommandTarget() / 아직 정체 파악이 안됨....
void getCommandInfo(CommandID, ApplicationCommandInfo & ) / 아직 정체 파악이 안됨...
void getAllCommands(Array<CommandID> &) / 아직 정체 파악이 안됨...
bool perform(const InvocationInfo &) / 아직 정체 파악이 안됨...
Hello World Example의 일부 코드 (Main.cpp) 를 보시면 main함수가 보이지 않는다는 것을 알 수 있습니다.
//////////////////////////// Main.cpp /////////////////////////////////////////////////////////////////////////////////
/*
==============================================================================
This file was auto-generated by the Introjucer!
It contains the basic startup code for a Juce application.
==============================================================================
*/
#include "../JuceLibraryCode/JuceHeader.h"
#include "MainComponent.h"
//==============================================================================
class HelloWorldApplication : public JUCEApplication
{
public:
//==============================================================================
HelloWorldApplication() {}
const String getApplicationName() override { return ProjectInfo::projectName; }
const String getApplicationVersion() override { return ProjectInfo::versionString; }
bool moreThanOneInstanceAllowed() override { return true; }
//==============================================================================
void initialise (const String& commandLine) override
{
// This method is where you should put your application's initialisation code..
mainWindow = new MainWindow (getApplicationName());
}
void shutdown() override
{
// Add your application's shutdown code here..
mainWindow = nullptr; // (deletes our window)
}
//==============================================================================
void systemRequestedQuit() override
{
// This is called when the app is being asked to quit: you can ignore this
// request and let the app carry on running, or call quit() to allow the app to close.
quit();
}
void anotherInstanceStarted (const String& commandLine) override
{
// When another instance of the app is launched while this one is running,
// this method is invoked, and the commandLine parameter tells you what
// the other instance's command-line arguments were.
}
//==============================================================================
/*
This class implements the desktop window that contains an instance of
our MainContentComponent class.
*/
class MainWindow : public DocumentWindow
{
public:
MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
setUsingNativeTitleBar (true);
setContentOwned (new MainContentComponent(), true);
centreWithSize (getWidth(), getHeight());
setVisible (true);
}
void closeButtonPressed() override
{
// This is called when the user tries to close this window. Here, we'll just
// ask the app to quit when this happens, but you can change this to do
// whatever you need.
JUCEApplication::getInstance()->systemRequestedQuit();
}
/* Note: Be careful if you override any DocumentWindow methods - the base
class uses a lot of them, so by overriding you might break its functionality.
It's best to do all your work in your content component instead, but if
you really have to override any DocumentWindow methods, make sure your
subclass also calls the superclass's method.
*/
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
};
private:
ScopedPointer<MainWindow> mainWindow;
};
//==============================================================================
// This macro generates the main() routine that launches the app.
START_JUCE_APPLICATION (HelloWorldApplication)
//////////////////////////// Main.cpp /////////////////////////////////////////////////////////////////////////////////
그 이유는 START_JUCE_APPLICATION () 이라는 메크로 함수가 메인 함수가 포함된 코드를 생성시켜주기 때문입니다. START_JUCE_APPLICATION() 함수의 인자로 상속받은 클래스의 이름을 넣음으로써 main루틴이 생성이 됩니다.
예제 소스에서는 JUCEApplication 를 상속받은 클래스가 있는 소스파일 제일 아래 부분에 메크로를 호출하고 있습니다. START_JUCE_APPLICATION() 메크로 함수의 내용은 아래와 같습니다.
실제로 저희 눈으로는 보이지 않지만 프로그램이 빌드되는 과정에서 프리프로세서에 의해 메인함수가 포함된 코드로 바뀝니다.
2. DocumentWindow 클래스
JUCEApplication클래스가 윈도우 초기화와 어플리케이션의 시작을 도와주는 역활이라면 DocumentWindow클래스는 실질적인 Window 클래스이다. ( 이러한 Window 클래스는 종류가 많은데 DialogWindow, DocumentWindow, 등등, 추후 따로 정리해서 글로 올리겠습니다. ) DocumentWindow는 Api Document에 의하면 최대화, 최소화, 종료버튼을 가지고 있는 크기 조절이 가능한 윈도우이다. 아래는 DocumentWindow클래스 내부에 있는 멤버함수 목록이다.
(API 정보는 http://www.juce.com/api/classDocumentWindow.html 에 있습니다.)
Hello World Example 소스코드에서는 이 클래스를 JUCEApplication 클래스를 상속받은 HelloWorldApplication 클래스가 내부 클로스로 상속받아 사용하고 있습니다.(Main.cpp 소스파일을 참고) 내부 클래스는 아래와 같습니다.
class MainWindow : public DocumentWindow
{
public:
MainWindow (String name) : DocumentWindow (name,
Colours::lightgrey,
DocumentWindow::allButtons)
{
setUsingNativeTitleBar (true);
setContentOwned (new MainContentComponent(), true);
centreWithSize (getWidth(), getHeight());
setVisible (true);
}
void closeButtonPressed() override
{
// This is called when the user tries to close this window. Here, we'll just
// ask the app to quit when this happens, but you can change this to do
// whatever you need.
JUCEApplication::getInstance()->systemRequestedQuit();
}
/* Note: Be careful if you override any DocumentWindow methods - the base
class uses a lot of them, so by overriding you might break its functionality.
It's best to do all your work in your content component instead, but if
you really have to override any DocumentWindow methods, make sure your
subclass also calls the superclass's method.
*/
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainWindow)
};
윈도우에서 보여지는 컨텐츠는 setContentOwned함수에 의해 결정됩니다. setContentOwned 함수의 매개변수로는 Component 클래스를 상속받은 클래스를 받을 수 있습니다.