다음 이전 차례

4. 앞으로 나아가며

4.1 자료형

앞서의 예제에서 주목했겠지만 설명이 필요한 것이 좀 있다. gint, gchar 등은 각각 int와 char에 대한 typedef들이다. 이것은 계산을 할 때 간단한 자료형들의 크기에 대한 지저분한 의존성을 피하기 위한 것이다. 64비트의 알파든 32비트의 인텔이든 "gint32"는 플랫폼에 관계없이 32비트 정수로 typedef되어 있는 것이 좋은 예가 될 것이다. 이 typedef은 상당히 직관적이다. 그들은 모두 glib/ glib.h에서 정의되어 있다(이것은 gtk.h에서 포함시키게 된다.). 당신은 또한 함수가 GtkObject를 부를 때 GtkWidget을 이용하는 것에도 주목할 것이다. GTK는 객체지향적으로 설계된 것이고, widget은 하나의 object이다.

4.2 시그널 핸들러에 대해 좀 더 알아보기

gtk_signal_connect의 선언을 또 다르게 살펴보자.

gint gtk_signal_connect (GtkObject *object, gchar *name,
                         GtkSignalFunc func, gpointer func_data);

gint형의 리턴값? 이것은 callback함수를 확인하기 위한 꼬리표다. 앞서 얘기했듯이 우리는 시그널과 object에 대해 필요한 만큼의 많은 callback을 가질 수 있고, 그것들은 붙여져 있는 순서대로 각각 실행될 것이다. 이 꼬리표는 우리가 리스트에서 이런 callback을 제거하도록 해준다.

void gtk_signal_disconnect (GtkObject *object,
                            gint id);

그래서, 핸들러로부터 제거하고자 하는 widget과 signal_connect함수로부터 리턴된그 widget의 꼬리표 혹은 id를 넘겨줌으로써 시그널 핸들러를 끊어줄 수 있다.

Object에서 모든 시그널 핸들러를 제거하는 또다른 함수는 이것이다.

gtk_signal_handlers_destroy (GtkObject *object);
이 호출은 보이는 그대로다. 이것은 첫번째 인자로 넘겨받은 object에서, 단지 현재 설정된 모든 시그널 핸들러를 제거해 준다.

4.3 향상된 Hello World 프로그램

Callback함수에 대한 더 나은 예제가 될 약간 개선된 hello world를 보자. 이것은 또한 우리의 다음 절에서의 주제인 패킹 widget을 소개할 것이다.

/* helloworld2.c */

#include <gtk/gtk.h>

/* 우리의 약간 개선된 callback.  이 함수로 전해진 데이터는 표준출력으로
 * 보여진다. */
void callback (GtkWidget *widget, gpointer data)
{
        g_print ("Hello again - %s was pressed\n", (char *) data);
}
/* 다른 callback */
void delete_event (GtkWidget *widget, GdkEvent *event, gpointer data)
{
        gtk_main_quit ();
}
int main (int argc, char *argv[])
{
        /* GtkWidget은 widget들을 위한 저장장소 타입이다. */ 
        GtkWidget *window;
        GtkWidget *button;
        GtkWidget *box1;
        /* 이것은 모든 GTK 어플에서 쓴다.  명령행에서 주어진 인자들은 이것을
         * 통과해서 어플에 전달된다. */
        gtk_init (&argc, &argv);
        /* 새로운 윈도를 만든다. */
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        /* 새로 접하는 함수로, 윈도에 "Hello Buttons!"라는 타이틀을 준다. */
        gtk_window_set_title (GTK_WINDOW (window), "Hello Buttons!");
        /* 여기서 우리는 GTK를 즉시 끝나게 하는 delete_event를 위한 핸들러를
         * 세팅한다. */
        gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                        GTK_SIGNAL_FUNC (delete_event), NULL);
        /* 윈도의 border width를 세팅한다. */
        gtk_container_border_width (GTK_CONTAINER (window), 10);
        /* widget들이 패킹될 박스를 만든다.  이것은 패킹에 대한 부분에서
         * 자세히 설명될 것이다.  박스는 실제로 보이는 건 아니며 단지
         * widget들을 정렬해 놓을 도구로서 쓰인다. */
        box1 = gtk_hbox_new(FALSE, 0);
        /* 박스를 윈도 안에 놓는다. */
        gtk_container_add (GTK_CONTAINER (window), box1);
        /* "Button 1"이란 라벨을 가진 새로운 버튼을 만든다. */
        button = gtk_button_new_with_label ("Button 1");
        /* 이제 버튼이 클릭되면 우리는 이 버튼에 대한 포인터를 인자로 가지는
         * "callback" 함수를 호출한다. */
        gtk_signal_connect (GTK_OBJECT (button), "clicked",
                        GTK_SIGNAL_FUNC (callback), (gpointer) "button 1");
        /* gtk_container_add 대신에, 우리는 이미 윈도에 패킹되어 있는 보이지
         * 않는 박스에 버튼을 패킹한다. */
        gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
        /* 이 순서를 꼭 기억하라.  여기서 버튼에 대한 세팅이 완전히 끝났음을
         * GTK에게 알리고, 따라서 그것은 이제 보여질 수 있다. */
        gtk_widget_show(button);
        /* 두번째 버튼을 만들기 위해 같은 절차를 거친다. */
        button = gtk_button_new_with_label ("Button 2");
        /* 같은 callback을 호출한다.  물론 인자는 "button 2"에 대한
         * 포인터다. */
        gtk_signal_connect (GTK_OBJECT (button), "clicked",
                        GTK_SIGNAL_FUNC (callback), (gpointer) "button 2");
        gtk_box_pack_start(GTK_BOX(box1), button, TRUE, TRUE, 0);
        /* 우리가 버튼을 먼저 보여줘야 하는 그 순서는 실제로 중요한 것은
         * 아니다.  하지만 나는 모든 것들이 한꺼번에 튀어 나오며 보여질 수
         * 있도록 윈도를 가장 나중에 보여줄 것을 권장한다. */
        gtk_widget_show(button);
        gtk_widget_show(box1);
        gtk_widget_show (window);
        /* 여기서 앞으로의 재미있는 것들을 기다리게 된다! */
        gtk_main ();
        return 0;
}

이 프로그램을 우리의 첫번째 예제와 같은 링크 인자를 주고 컴파일하자. 역시 우리는 이 프로그램을 종료하기 위해서 윈도매니저를 이용하거나 명령행에서 죽이는 것 말고는 다른 방법이 없다는 걸 알 것이다. 연습삼아 세번째로 "Quit" 버튼을 만들어 추가해 보는 것도 좋을 것이다. 또한 다음 절을 읽어보며 gtk_box_pack_start()에 옵션을 주어볼 수도 있다. 윈도의 크기를 바꾸려고 시도도 해보고, 동작을 관찰해 보라.

참고로, gtk_window_new()를 위한 또다른 유용한 define으로 GTK_WINDOW_DIALOG 도 있다. 이것은 윈도매니저와 약간 다른 방식으로 상호작용하며, 일시적인 윈도 들에 대해 쓰여져야 한다.


다음 이전 차례