BeOS Programming 3
- BeOS 프로그래밍의 시작-Hello BeOS!
백성수 (rainbow@hnc.co.kr)
강좌 2 : "Hello BeOS"!
이미 첫 번째 강좌에서 우리는 BeOS프로그래밍을 경험했지만 완전한 것은 아니었다. 즉, 닫기 버튼을 누르면 프로그램을 끝내야하는데 그렇지 못했다. 이는 윈도우가 닫았다는 메시지를 받았을 때 그에 해당하는 작업(프로그램 종료)을 처리해 주어야하는 것을 의미한다. 자꾸 MS 프로그래밍 예를 들어서 안됐지만 그래도 이해가 빠를 것 같아서, WM_DESTORY메시지를 받았을 때 PostQuitMessage함수를 호출해서 프로그램을 종료할 수 있도록 처리한다.
그럼 우리도 종료할 수 있는 프로그램을 만들어 보자. BeOS 경우 사용자가 프로그램의 닫기 버튼을 누르면 윈도우의 가상 함수인 QuitRequested()를 호출한다. 따라서 이 함수를 재정의하므로서 간단히 윈도우를 종료시킬 수 있다. 먼저 BWindow에서 계승된 HelloWindow클래스를 만들자.
class HelloWindow : public BWindow
{
public:
HelloWindow(BRect frame);
virtual bool QuitRequested();
};
QuitRequested()함수를 재정의하기 위해서 클래스를 하나 더 만들었을 뿐 별다른 차이점이 없다. 새로 추가된 HelloWindow생성자를 보자.
HelloWindow::HelloWindow(BRect frame)
:BWindow(frame, "Hello",
B_TITLED_WINDOW,
B_NOT_RESIZABLE|B_NOT_ZOOMABLE)
{
Show();
}
HelloApp생성자에서 처리했던 BWindow의 멤버 함수인 Show()를 이곳에서 호출하는 것 외에는 특이할 만한 점을 찾을 수 없다.
그럼 지금부터 강좌1에서 다루었던 소스 코드를 확장해 보도록 하자.
class HelloApp : public BApplication
{
public:
HelloApp();
HelloWindow *pWindow; // BWindow *pWindow;
};
즉, HelloApp클래스의 윈도우 클래스를 BWindow에서 HelloWindow로 변경한다. 왜냐하면 프로그램을 종료하기 위해서 QuitRequested()함수를 재 정의해야 하기 때문이다. 그리고 QuitRequested()함수 내부를 보면
bool HelloWindow::QuitRequested()
{
be_app->PostMessage(B_QUIT_REQUESTED);
return true;
}
단지 B_QUIT_REQUESTED메시지를 application에게 보낸다. 기본적으로 BApplication개체가 이 메시지를 받으면 Run()함수를 끝낸다. 그런 다음 윈도우 종료 요구를 승인했다는 것을 알리는 true값을 넘긴다. QuitRequested()함수가 false를 가지고 돌아온다면, 무슨 이유든 간에 윈도우를 닫지 못했다는 것을 의미한다.
프로그램을 종료시키기 위한 마지막 수정 부분인 HelloApp생성자를 보자
HelloApp::HelloApp()
:BApplication("application/x-vnd.BeKrAge-Hello")
{
BRect frame;
frame.Set(100, 100, 300, 500);
pWindow = new HelloWindow(frame);
}
별다른 차이점은 없고 BWindow에서 직접 인스턴스를 생성했던 것을 HelloWindow클래스에서 처리하므로 몇몇 코드들이 줄어들었다. 다음은 수정된 프로그램을 종료할 수 있도록 추가된 코드다. 강좌1의 예제 프로그램과 잘 비교해 보기바란다.
#include
class HelloWindow : public BWindow
{
public:
HelloWindow(BRect frame);
virtual bool QuitRequested();
};
class HelloApp : public BApplication
{
public:
HelloApp();
HelloWindow *pWindow;
};
HelloWindow::HelloWindow()
:BWindow(frame, "Hello",
B_TITLED_WINDOW,
B_NOT_RESIZABLE|B_NOT_ZOOMABLE)
{
Show();
}
HelloApp::HelloApp()
:BApplication("application/x-vnd.BeKrAge-Hello")
{
BRect frame;
frame.Set(100, 100, 300, 500);
pWindow = new HelloWindow(frame);
}
void main(void)
{
HelloApp *theApp;
theApp = new HelloApp;
theApp->Run();
delete theApp;
}
이번 강좌의 요지인 "Hello BeOS"를 화면에 출력해 보도록 하자. MS 프로그래밍을 해 봤던 독자라면 여기까지 예제를 가지고 다음과 같이 짐작할 수 있을 것이다. 즉, 윈도우내에 화면출력함수(MS프로그래밍의 경우 TextOut/ExtTexOut등)를 이용해서 처리하면 될거라 생각할지 모른다. 그러나 BeOS의 경우는 화면의 어떤 내용을 출력하는 것은 윈도우 내에서는 처리할 수 없고 단지 뷰에서만 처리할 수 있도록 되어 있다. 따라서 간단한 원이나 선을 그릴 경우도 BView에서 계승된 사용자 뷰를 만들고, 이것을 윈도우에 차일드로 포함시키는 방법을 쓰고 있다. 그럼 BView에서 계승된 HelloView클래스를 보자.
class HelloView : public BView
{
public:
HelloView(BRect frame);
virtual void Draw(BRect updateRect);
};
HelloView클래스는 부모 클래스로부터 뷰의 크기를 가지고 오는 BRect를 포함한 생성자를 가지고 있다. 그리고 Draw()멤버 함수는 뷰의 내용이 업데이트 될 때 Application Server에 의해서 호출된다.
뷰의 생성자는 다음과 같다.
HelloView::HelloView(BRect frame)
: BView(frame, "HelloView", B_FOLLOW_ALL_SIDES,
B_WILL_DRAW)
{
}
이미 보았듯이 생성자내에서 아무 작업도 하지 않는다. 간단하게 Bview의 생성자만 만들고 뷰 영역인 frame인수만 넘긴다. 뷰의 이름은 "HelloView"이다. B_FOLLOW_ALL_SIDES상수는 윈도우에 따라서 뷰의 크기가 따라가도록 하는 것이다. 즉, 윈도우가 이동하거나 크기 조절을 할 때 뷰도 같이 종속된다는 것을 의미한다. B_WILL_DRAW상수는 업데이트를 위해 호출되어지는 함수인 Draw()함수를 구현했다고 Application Server에게 알려준다.
Application Server는 윈도우 내용이 갱신될 필요가 있을 때마다 Draw()함수를 호출한다. 다른 윈도우가 윈도우를 덮거나 윈도우가 초기화되서 다시그릴 필요가 있을때Application Server는 Draw()함수를 호출하는 일을 한다. 함수에 넘겨지는 BRect는 다시 그려야되는 뷰의 크기를 말한다.
void HelloView::Draw(BRect updateRect)
{
MovePenTo(BPoint(20,75)); // Move pen
DrawString("Hello, BeOS");
}
여기 예제에서는 업데이트될 뷰 크기인 updateRect변수를 무시한다. 펜 객체를 (20,75)위치로 설정해서 출력을 위한 초기 좌표를 설정한다. 즉, BPoint개체를 MovePenTo()함수의 인수로 넘겨서 문자열 출력 위치를 지정한다.
펜이 우리가 원하는 위치에 있을 때, DrawString()함수를 호출해서 뷰내에 "Hello, BeOS"문자열을 출력하면 만사 OK.
끝으로 AddChild()함수를 이용해서 HelloView를 윈도우에 차일드로 추가하기만 하면 된다. 즉, 위 전제 예제 코드에서 HelloWindow생성자를 다음과 같이 수정해서 넣으면 우리가 원하는 결과를 화면을 통해서 볼 수 있다.
HelloWindow::HelloWindow()
:BWindow(frame, "Hello",
B_TITLED_WINDOW,
B_NOT_RESIZABLE|B_NOT_ZOOMABLE)
{
Show();
AddChild( new HelloView(frame) );
}
참고로 new에 의해서 할당된 메모리 포인터는 그 사용자가 책임을 져야하지만, Application Kit의 경우 이들에 대한 책임도 같이 처리해 준다. 따라서 new HelloView(frame)라고 포인터를 생성한 경우 프로그램이 종료되는 시점인 HelloWindow파괴자가 호출될 때 자동으로 이들을 관리해 준다. 그러므로 사용자는 이들을 따로 관리하지 않아도 된다.
다음 강좌는 Application Kit의 클래스를 이용하여 텍스트 에디터를 만들어 보기로 하자.