오늘은 Menu를 수동적으로 만들어 보겠습니다. menu를 만드는 방법은 두가지가 있습니다. 두가지 방법은 menu factory를 사용하는 방법과 고전적인 방법이 있습니다. 고전적인 방법을 먼저 알아보는 것이 공부하는데 도움이 되겠죠? ^ ^;
그렇다고 menu factory를 사용하다고 나쁘다는 것은 아닙니다. 두가지 방법은 장단점이 있으니까 사용하실때는 그때 그때 상황에 맞는 장점을 이용하는 것이 좋겠지요?
수동적인 방법으로 몇 가지 wrapper 함수들을 써 가며 메뉴를 만드는 것이 유용성에 있어서 훨씬 유리함에도 불구하고, menufactory를 이용하는 방법은 훨씬 사용하기 쉽고 또 새로운 메뉴를 추가하기도 쉽습니다. Menufactory를 이용하게 되면, 메뉴에 이미지라든가 '/'를 쓰는 것이 불가능해집니다.
위에 말씀 드렸듯이, 오늘은 수동적으로 menu를 만드는 방법을 선보이겠습니다.
메뉴바와 하위메뉴(submenu)들를 만드는데 쓰는 세가지 widget이 있습니다.
메뉴 아이템(menu item) : 사용자가 선택하는 것. (예: 'Save')
메뉴(menu) : 메뉴 아이템들의 컨테이너.
메뉴바(menubar) : 각각의 메뉴들을 포함하는 컨테이너.
메뉴 아이템 widget이 두가지 다른 용도로 쓰일 수 있다는 점때문에 약간 복잡한 면이 있습니다. 메뉴 아이템은 단순히 메뉴 위에 놓일 수도 있고 또는 메뉴바 위에 놓여서 선택되었을 때 특정 메뉴를 활성화시키도록 쓰일 수도 있습니다.
메뉴와 메뉴바를 만들기 위해 쓰이는 함수들을 살펴보자. 이 첫번째 함수는 새로운 메뉴바를 만들기 위해 쓰입니다.
GtkWidget *gtk_menu_bar_new()
이것은 이름 그대로 새로운 메뉴바를 만듭니다. 버튼과 마찬가지로, 우리는 이것을 윈도에 패킹하기 위해 gtk_container_add를 이용할수도 있고, 또는 박스에 패킹하기 위해 box_pack 함수들을 이용할 수 있습니다. 즉, 버튼과 같다고 보면 됩니다.
GtkWidget *gtk_menu_new();
이 함수는 새로운 메뉴를 향한 포인터를 리턴하는데, 이것은 실제로 보여지지는 않고(gtk_widget_show를 통해) 다만 메뉴 아이템들을 가지고만 있습니다. 이 아래에 나오는 예제를 보며 더 명확히 이해하기를 바랍니다.
이번의 두 함수는 메뉴나 메뉴바 안으로 패킹되는 메뉴 아이템을 만들기 위해 쓰입니다.
GtkWidget *gtk_menu_item_new()
GtkWidget *gtk_menu_item_new_with_label(const char *label)
이 함수들은 보여지기 위한 메뉴를 만들 때 쓰입니다. gtk_menu_new로써 만들어지는 "메뉴"와 gtk_menu_item_new로써 만들어지는 "메뉴 아이템"을 꼭 구별해야 합니다. 메뉴 아이템은 연결된 동작이 있는 실제의 버튼이 될 것이지만, 반면 메뉴는 이것들을 가지고 있는 컨테이너가 될 것입니다.
gtk_menu_new_with_label과 단순한 gtk_menu_new 함수는 여러분이 버튼에 대해 공부한 후에 짐작하는 그대로입니다. gtk_menu_new_with_label은 라벨이 이미 패킹되어 있는 메뉴 아이템을 만들고, gtk_menu_new는 비어있는 메뉴 아이템을 만듭니다.한번 메뉴 아이템을 만들면 반드시 이를 메뉴 안에 넣어야만 합니다. 이는 gtk_menu_append 함수를 이용해서 이루어집니다. 어떤 아이템이 사용자에 의해 선택되었을 때 이를 알아내어 처리하기 위해서는 activate 시그널을 통상적으로 하듯이 연결합니다. 그래서 만일 Open, Save, Quit 옵션을 가진 표준 File 메뉴를 만들고자 한다면 소스 코드는 다음과 같이 됩니다.
file_menu = gtk_menu_new(); /* 메뉴를 보여줄 필요는 없습니다. */
/* 메뉴 아이템들을 만듭니다. */
open_item = gtk_menu_item_new_with_label("Open");
save_item = gtk_menu_item_new_with_label("Save");
quit_item = gtk_menu_item_new_with_label("Quit");
/* 그것들을 메뉴에 붙입니다. */
gtk_menu_append( GTK_MENU(file_menu), open_item);
gtk_menu_append( GTK_MENU(file_menu), save_item);
gtk_menu_append( GTK_MENU(file_menu), quit_item);
/* "activate" 시그널과 callback 함수를 연결합니다. */
gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
/* Quit 메뉴 아이템에 exit 함수를 연결합니다. */
gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
/* 이제 메뉴 아이템들을 보여줘야 합니다. */
gtk_widget_show( open_item );
gtk_widget_show( save_item );
gtk_widget_show( quit_item );
여기까지하면 필요한 메뉴는 일단 만든 것입니다. 이제 지금까지 만든 메뉴를 붙일 File 메뉴 아이템과 메뉴바를 만들어야 합니다. 아이템과 메뉴바를 만든면 아래와 같이 됩니다.
menu_bar = gtk_menu_bar_new();
gtk_container_add( GTK_CONTAINER(window), menu_bar);
gtk_widget_show( menu_bar );
file_item = gtk_menu_item_new_with_label("File");
gtk_widget_show(file_item);
이제 file_item을 메뉴와 연결해야 합니다. 이것은 다음 함수를 통해 이루어집니다.
void gtk_menu_item_set_submenu( GtkMenuItem *menu_item, GtkWidget *submenu);
그래서 우리 예제는 다음 코드로 이어집니다.
gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu);
해야할 남은 모든 일은 메뉴를 메뉴바에 붙이는 일이다. 이는 다음 함수를 이용합니다.
void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
우리가 작성한 코드에서는 다음과 같이 됩니다.
gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
만일 메뉴들이 help 메뉴가 자주 그러는 것처럼 메뉴바의 오른쪽에 위치하게 하고 싶다면 메뉴바에 메뉴를 붙이기 전에 다음 함수를 쓰면 됩니다. (현재 예제라면 인자로 file_item을 주면 된다.)
void gtk_menu_item_right_justify (GtkMenuItem *menu_item);
메뉴들이 달려있는 메뉴바를 만드는 단계들을 간단히 정리해 보겠습니다.
gtk_menu_new()를 이용해서 새로운 메뉴를 만듭니다.
gtk_menu_item_new()를 여러번 이용해서 메뉴에 필요한 각각의 메뉴 아이템을 만든다. 그리고 gtk_menu_append()를 이용해서 새 아이템들을 메뉴에 넣습니다.
gtk_menu_item_new()를 사용해서 메뉴 아이템을 하나 만든다. 이 아이템은 자신의 텍스트가 메뉴바 위에 직접 나타나는 root 메뉴 아이템이 됩니다.
gtk_menu_item_set_submenu()를 사용해서 메뉴를 root 메뉴 아이템에 붙입니다.(바로 위 단계에서 만든 메뉴 아이템)
gtk_menu_bar_new()를 이용해서 새로운 메뉴바를 만듭니다. 이 단계는 한 메뉴바 위에 여러 일련의 메뉴를 만들었을 때 한번만 필요합니다.
gtk_menu_bar_append()를 이용해서 메뉴바 위에 root 메뉴를 놓습니다.
팝업메뉴를 만드는 것도 거의 같습니다. 다른 점이 있다면 메뉴는 메뉴바에 의해 자동적으로 붙여지는 것이 아니라, button_press 이벤트로부터 gtk_menu_popup() 함수를 호출함으로써 붙여진다는 것입니다. 이 과정을 따라 설명해보겠습니다.
이벤트 핸들링 함수를 만듭니다. 이것은 아래와 같은 원형을 가져야 합니다.
static gint handler(GtkWidget *widget, GdkEvent *event);
그리고 이것은 메뉴를 팝업시킬 곳을 찾기 위해 이벤트를 이용할 것입니다.
이벤트 핸들러에서는, 만약 이벤트가 마우스 버튼을 누르는 것이라면, 이벤트를 버튼 이벤트로 다루고, gtk_menu_popup()에 정보를 넘겨줍니다.
이 함수를 이용하여 이벤트 핸들러를 widget에 결합시킵니다.
gtk_signal_connect_object(GTK_OBJECT(widget), "event", GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
여기서 widget 인자는 우리가 바인딩할 widget이고, handler 인자는 핸들링 함수입니다. 그리고 menu 인자는 gtk_menu_new()로써 만들어진 메뉴입니다. 예제 코드에서 보인대로, 이것은 메뉴바에 붙여져 있는 메뉴가 될 수도 있습니다.
어때요? 설명이 조금 많아서 어려워 보이지만, 따라해보면 금방 이해할 수 있습니다.
오늘은 Menu에 대한 설명을 하였습니다. 다음주에는 위의 내용을 이용하여 하나의 예제를 해보겠습니다.