노트북 widget은 서로 오버랩되며 다른 정보를 가지고 있는 '페이지들'의 모임이다. 이런 widget은 최근 GUI 프로그래밍에서 더 일반화되었고, 화면에서 비슷하지만 구별되어야 할 정보 블럭을 보이는 데 좋은 방법이다.
우리가 알아야 할 첫번째 함수는 예상한대로 새로운 노트북 widget을 만드는 것이다.
GtkWidget* gtk_notebook_new (void);
일단 노트북이 만들어지면, 그 노트북 widget을 다룰 12개의 함수가 있다. 그들 하나하나를 살펴보자.
우리가 먼저 할 일은 페이지 표시자의 위치를 어떻게 잡는지 알아보는 것이다. 이런 페이지 표시자 혹은 'tab'은, 네 가지 방법으로 잡아줄 수 있다. 즉 top, bottom, left, 또는 right이다.
void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);
GtkPositionType은 다음 중 하나이며, 상당히 직관적이다.
GTK_POS_TOP이 디폴트다.
다음으로 노트북에 어떻게 페이지를 넣는지 알아보자. 이렇게 하는 것에는 세가지 방법이 있다. 우선 서로 유사한 두가지를 먼저 살펴보자.
void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
이런 함수들은 노트북의 뒤에 삽입되던지(append), 또는 노트북의 앞에서 삽입되던지(prepend) 해서 페이지를 더해준다. *child는 노트북 페이지에 위치하는 widget이고, *tab_label은 더해질 페이지를 위한 라벨이다.
페이지를 더해주는 마지막 함수는 앞의 두가지가 가진 특성을 모두 가지고 있다. 하지만 이것은 우리가 노트북의 어느 위치에 페이지를 설정할 지를 정하도록 해준다.
void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);
position이라는 또 하나의 인자를 포함한다는 것만 빼고는, gtk_notebook_append_page 그리고 gtk_notebook_prepend_page와 인자가 같다. position 인자는 이 페이지가 어느 위치에 삽입될 것인지 지정해 준다.
이제 어떻게 페이지를 더하는지 알았으므로, 노트북에서 페이지를 어떻게 제거하는지를 알아보도록 하자.
void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);
이 함수는 page_num 인자로 주어진 페이지를 취해서, 그것을 *notebook이라는 widget에서 제거해준다.
현재의 페이지를 알아내기 위해서는 이 함수를 이용한다.
gint gtk_notebook_current_page (GtkNotebook *notebook);
여기 소개하는 두 함수는 노트북의 페이지를 앞뒤로 이동할 때 쓰는 간단한 함수들이다. 우리가 다룰 노트북 widget을 다루기 위해서 저마다의 함수를 주기만 하면 된다. 주의할 것은, 마지막 페이지에서 gtk_notebook_next_page가 호출되면 노트북이 첫번째 페이지로 돌아가 버린다는 사실이다. 마찬가지로 첫번째 페이지에서 gtk_notebook_prev_page가 호출되면 노트북의 마지막 페이지 로 가버린다.
void gtk_notebook_next_page (GtkNoteBook *notebook);
void gtk_notebook_prev_page (GtkNoteBook *notebook);
이번 함수는 'active', 즉 활성화된 페이지를 세팅한다. 예를들어 처음부터 5번 페이지로 노트북을 열려면 이 함수를 이용하면 될 것이다. 이것을 쓰지 않으면, 디폴트로 노트북은 첫번째 페이지에서 열리게 된다.
void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num);
이 두 함수는 각각 노트북의 페이지 tab과 경계를 더하거나 제거해준다.
void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gint show_tabs);
void gtk_notebook_set_show_border (GtkNotebook *notebook, gint show_border);
인자 show_tabs와 show_border는 TRUE/FALSE 중 하나가 될 수 있다.
이제 예제를 하나 보자. 이것은 GTK 배포본과 함께 있는 testgtk.c 프로그램 으로, 13개의 함수를 모두 보여준다. 이 작은 프로그램은 노트북과 여섯 개의 버튼을 가지고 있는 윈도를 만든다. 노트북은 세가지 다른 방법, 즉 append/ insert/prepend를 통해 더해진 11개 페이지를 가지고 있다. 버튼들은 tab의 위치를 순환시킬 수 있고, tab과 border를 더해주거나 지울수 있으며, 한 페이지 를 지울 수도 있다. 그리고 앞뒤 양방향으로 페이지를 바꿔주며, 프로그램을 끝낼 수도 있다.
/* notebook.c */
#include <gtk/gtk.h>
/* 이 함수는 tab의 위치를 로테이션 시킨다. */
void rotate_book (GtkButton *button, GtkNotebook *notebook)
{
gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4);
}
/* page tab과 border를 더하거나 삭제한다. */
void tabsborder_book (GtkButton *button, GtkNotebook *notebook)
{
gint tval = FALSE;
gint bval = FALSE;
if (notebook->show_tabs == 0)
tval = TRUE;
if (notebook->show_border == 0)
bval = TRUE;
gtk_notebook_set_show_tabs (notebook, tval);
gtk_notebook_set_show_border (notebook, bval);
}
/* 노트북에서 한 페이지를 제거한다. */
void remove_book (GtkButton *button, GtkNotebook *notebook)
{
gint page;
page = gtk_notebook_current_page(notebook);
gtk_notebook_remove_page (notebook, page);
/* Need to refresh the widget -
This forces the widget to redraw itself. */
gtk_widget_draw(GTK_WIDGET(notebook), NULL);
}
void delete (GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_main_quit ();
}
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *table;
GtkWidget *notebook;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *checkbutton;
int i;
char bufferf[32];
char bufferl[32];
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (delete), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
table = gtk_table_new(2,6,TRUE);
gtk_container_add (GTK_CONTAINER (window), table);
/* 새 노트북을 만들고, tab들의 위치를 설정한다. */
notebook = gtk_notebook_new ();
gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP);
gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1);
gtk_widget_show(notebook);
/* 노트북에 페이지들의 묶음을 추가한다. */
for (i=0; i < 5; i++) {
sprintf(bufferf, "Append Frame %d", i+1);
sprintf(bufferl, "Page %d", i+1);
frame = gtk_frame_new (bufferf);
gtk_container_border_width (GTK_CONTAINER (frame), 10);
gtk_widget_set_usize (frame, 100, 75);
gtk_widget_show (frame);
label = gtk_label_new (bufferf);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
label = gtk_label_new (bufferl);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label);
}
/* 지정한 곳으로 한 페이지를 더한다. */
checkbutton = gtk_check_button_new_with_label ("Check me please!");
gtk_widget_set_usize(checkbutton, 100, 75);
gtk_widget_show (checkbutton);
label = gtk_label_new ("Add spot");
gtk_container_add (GTK_CONTAINER (checkbutton), label);
gtk_widget_show (label);
label = gtk_label_new ("Add page");
gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2);
/* 이제 노트북의 선두에 페이지를 prepend한다. */
for (i=0; i < 5; i++) {
sprintf(bufferf, "Prepend Frame %d", i+1);
sprintf(bufferl, "PPage %d", i+1);
frame = gtk_frame_new (bufferf);
gtk_container_border_width (GTK_CONTAINER (frame), 10);
gtk_widget_set_usize (frame, 100, 75);
gtk_widget_show (frame);
label = gtk_label_new (bufferf);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (label);
label = gtk_label_new (bufferl);
gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label);
}
/* 시작할 페이지를 세팅한다(여기서는 page 4). */
gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3);
/* 버튼의 다발(bunch)을 하나 만든다. */
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (destroy), NULL);
gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("next page");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_notebook_next_page,
GTK_OBJECT (notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("prev page");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_notebook_prev_page,
GTK_OBJECT (notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("tab position");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) rotate_book, GTK_OBJECT(notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("tabs/border on/off");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) tabsborder_book,
GTK_OBJECT (notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2);
gtk_widget_show(button);
button = gtk_button_new_with_label ("remove page");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) remove_book,
GTK_OBJECT(notebook));
gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2);
gtk_widget_show(button);
gtk_widget_show(table);
gtk_widget_show(window);
gtk_main ();
return 0;
}
이것으로 여러분의 GTK 어플을 만들 때 노트북을 다루는 방법에 대한 도움이 되기를 바란다.
이것은 실제 윈도 내부에서 스크롤된 영역을 만들 때 쓰이는 것이다. 우리는 이런 스크롤된 영역에 어떤 종류의 widget이라도 삽입할 수 있고, 스크롤바를 이용하여 크기에 관계없이 접근할 수 있을 것이다.
이 함수는 새로운 스크롤 윈도를 만드는 것이다.
GtkWidget* gtk_scrolled_window_new (GtkAdjustment *hadjustment,
GtkAdjustment *vadjustment);
첫번째 인자는 수평방향을, 그리고 두번째 인자는 수직방향을 조절해 준다. 이것들은 대개 NULL로 세팅된다.
void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolled_window,
GtkPolicyType hscrollbar_policy,
GtkPolicyType vscrollbar_policy);
이것은 스크롤바들을 쓰는 방식을 설정한다. 첫번째 인자는 우리가 변화 시키고자 하는 스크롤 윈도다. 두번째와 세번째 인자들은 각각 수평 스크롤바와 수직 스크롤바의 방식을 세팅한다.
이 방식이란 것은 GTK_POLICY_AUTOMATIC 혹은 GTK_POLICY_ALWAYS 가 된다. GTK_POLICY_AUTOMATIC은 스크롤바가 필요할 때를 자동적으로 결정하고, 반면 GTK_POLICY_ALWAYS는 언제나 스크롤바를 만들어 둔다.
이 간단한 예제는 스크롤된 윈도에 100개의 토글 버튼을 패킹한다. 여기서의 주석은 여러분에게 생소할 부분에만 붙여질 것이다.
/* scrolledwin.c */
#include <gtk/gtk.h>
void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
int main (int argc, char *argv[])
{
static GtkWidget *window;
GtkWidget *scrolled_window;
GtkWidget *table;
GtkWidget *button;
char buffer[32];
int i, j;
gtk_init (&argc, &argv);
/* 스크롤된 윈도가 패킹되어 들어갈 dialog 윈도를 만든다.
* Dialog 윈도란 vbox와 그것에 패킹되어 들어갈 수평 seperator를 가지고
* 있다는 것만 빼고는 보통의 윈도와 동일한 것이다. 이것은 dialog를
* 만들게 되는 일종의 shortcut이다. */
window = gtk_dialog_new ();
gtk_signal_connect (GTK_OBJECT (window), "destroy",
(GtkSignalFunc) destroy, NULL);
gtk_window_set_title (GTK_WINDOW (window), "dialog");
gtk_container_border_width (GTK_CONTAINER (window), 0);
/* 스크롤된(scrolled) 윈도를 하나 만든다. */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_container_border_width (GTK_CONTAINER (scrolled_window), 10);
/* 여기서의 방식은 GTK_POLICY_AUTOMATIC 또는 GTK_POLICY_ALWAYS 중
* 하나이다. GTK_POLICY_AUTOMATIC은 스크롤바가 필요한지를 자동적으로
* 결정하고, 반면 GTK_POLICY_ALWAYS는 언제나 스크롤바를 가지게 한다.
* 첫번째는 수평방향의 스크롤바, 그리고 두번째는 수직방향의 것이다. */
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
/* vbox가 패킹되어 들어간 dialog 윈도를 하나 만든다. */
gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window,
TRUE, TRUE, 0);
gtk_widget_show (scrolled_window);
/* 10행 10열의 테이블을 만든다. */
table = gtk_table_new (10, 10, FALSE);
/* x와 y에 대해 10 만큼의 spacing을 세팅한다. */
gtk_table_set_row_spacings (GTK_TABLE (table), 10);
gtk_table_set_col_spacings (GTK_TABLE (table), 10);
/* 스크롤된 윈도에 테이블을 패킹한다. */
gtk_container_add (GTK_CONTAINER (scrolled_window), table);
gtk_widget_show (table);
/* 이것은 단순히 스크롤된 윈도를 보여주기 위해 테이블 위에
* 토글버튼들의 격자(grid)를 하나 만든다. */
for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++) {
sprintf (buffer, "button (%d,%d)\n", i, j);
button = gtk_toggle_button_new_with_label (buffer);
gtk_table_attach_defaults (GTK_TABLE (table), button,
i, i+1, j, j+1);
gtk_widget_show (button);
}
/* Dialog의 맨 아래쪽에 "close" 버튼을 추가한다. */
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
(GtkSignalFunc) gtk_widget_destroy,
GTK_OBJECT (window));
/* 이것을 디폴트 버튼으로 한다. */
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0);
/* 이 버튼이 디폴트 버튼으로 되도록 잡아챈다. 간단히 "Enter"를 치면
* 이 버튼을 활성화 시킬 것이다. */
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show (window);
gtk_main();
return(0);
}
윈도의 크기를 변하게 해보라. 스크롤바가 어떻게 반응하는지 알 수 있을 것이다. 우리는 또한 윈도나 다른 widget의 디폴트 크기를 세팅하기 위해 gtk_widget_set_usize() 함수를 이용할 수도 있을 것이다.
이 paned 윈도 widget은 한 영역을 사용자에 의해서 그 상대적인 크기를 마음대로 조절할 수 있는 두 영역으로 나누어 쓰고 싶을 때 사용한다. 두 영역 사이에는 handle이 달린 홈이 있고 이를 마우스로 드래그해서 사용자는 원하는 대로 두 영역의 비율을 바꿀 수 있다. 이러한 분할은 수평(HPaned)적이거나 수직(VPaned)적이 된다.
새 paned 윈도를 만들려면 다음중 하나를 부른다.
GtkWidget* gtk_hpaned_new (void)
GtkWidget* gtk_vpaned_new (void)
Paned 윈도 widget을 만든 다음에는 나누어진 양쪽에 자식 widget을 주어야 한다. 이는 다음 함수들을 이용해서 이루어진다.
void gtk_paned_add1 (GtkPaned *paned, GtkWidget *child)
void gtk_paned_add2 (GtkPaned *paned, GtkWidget *child)
gtk_paned_add1()
는 paned 윈도 widget의 왼쪽 혹은 윗쪽에 자식 widget을
더한다. gtk_paned_add2()
는 반대로 오른쪽 혹은 아랫쪽에 더한다.
한 에로 가상적인 email 프로그램의 사용자 인터페이스 일부를 만들어 보기로 한다.
윈도는 email 메세지들의 리스트를 표시하는 윗 부분과 메세지 자체를 표시하는
아랫 부분으로 나누어진다. 프로그래의 대부분은 무척 간단하다.
두가지 주의해야 할 점이 있다. 텍스트는 텍스트 widget에 이것이 realize되기
전에는 더해질 수 없다. 이는 gtk_widget_realize()
를 호출해서 이루어지지만
또 다른 방법으로 text를 더하기 위해 "realize" 시그널을 연결할 수도 있다.
또한, GTK_SHRINK
옵션을 text 윈도와 스크롤바를 포함하고 있는 테이블
내용 일부에 더해주는 것이 필요하다. 그래야만 아랫 부분을 작게 만들때
윈도의 바닥이 밀려나는 대신 원하던 부분이 줄어들게 된다.
/* paned.c */
#include <gtk/gtk.h>
/* "messages"의 리스트를 만든다 */
GtkWidget *
create_list (void)
{
GtkWidget *scrolled_window;
GtkWidget *list;
GtkWidget *list_item;
int i;
char buffer[16];
/* 스크롤바(필요할 때만)가 딸린 스크롤된 윈도를 만든다. */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
/* 새로운 리스트를 만들어 이를 스크롤된 윈도에 집어넣는다. */
list = gtk_list_new ();
gtk_container_add (GTK_CONTAINER(scrolled_window), list);
gtk_widget_show (list);
/* 윈도에 메시지 몇개를 더한다 */
for (i=0; i<10; i++) {
sprintf(buffer,"Message #%d",i);
list_item = gtk_list_item_new_with_label (buffer);
gtk_container_add (GTK_CONTAINER(list), list_item);
gtk_widget_show (list_item);
}
return scrolled_window;
}
/* 텍스트 몇개를 텍스트 widget에 더한다. - 아래 함수는 우리의 윈도가 realize 될
때 불리는 callback이다. gtk_widget_realize로 realize되도록 강제할 수도 있지만
그건 먼저 계층구조의 한 부분이 되어야 할 것이다.
*/
void
realize_text (GtkWidget *text, gpointer data)
{
gtk_text_freeze (GTK_TEXT (text));
gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
"From: pathfinder@nasa.gov\n"
"To: mom@nasa.gov\n"
"Subject: Made it!\n"
"\n"
"We just got in this morning. The weather has been\n"
"great - clear but cold, and there are lots of fun sights.\n"
"Sojourner says hi. See you soon.\n"
" -Path\n", -1);
gtk_text_thaw (GTK_TEXT (text));
}
/* "message"를 보여주는 스크롤된 텍스트 영역을 만든다. */
GtkWidget *
create_text (void)
{
GtkWidget *table;
GtkWidget *text;
GtkWidget *hscrollbar;
GtkWidget *vscrollbar;
/* 텍스트 위젯과 스크롤바를 갖는 테이블을 만든다 */
table = gtk_table_new (2, 2, FALSE);
/* 텍스트 위젯을 왼쪽 위에 놓는다. Y 축 방향으로 GTK_SHRINK가 쓰인 것을
* 주목할 것. */
text = gtk_text_new (NULL, NULL);
gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
GTK_FILL | GTK_EXPAND,
GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
gtk_widget_show (text);
/* HScrollbar를 왼쪽 아래에 놓는다. */
hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
gtk_widget_show (hscrollbar);
/* VScrollbar를 오른쪽 위에 놓는다. */
vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0);
gtk_widget_show (vscrollbar);
/* 텍스트 widget이 realize되었을 때 그 widget이 갖고 있는 메시지를
* 출력하여주는 시그널 핸들러를 더한다. */
gtk_signal_connect (GTK_OBJECT (text), "realize",
GTK_SIGNAL_FUNC (realize_text), NULL);
return table;
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vpaned;
GtkWidget *list;
GtkWidget *text;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Paned Windows");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* vpaned widget을 만들어서 toplevel 윈도에 더한다. */
vpaned = gtk_vpaned_new ();
gtk_container_add (GTK_CONTAINER(window), vpaned);
gtk_widget_show (vpaned);
/* 이제 윈도 두 부분의 내용을 만든다. */
list = create_list ();
gtk_paned_add1 (GTK_PANED(vpaned), list);
gtk_widget_show (list);
text = create_text ();
gtk_paned_add2 (GTK_PANED(vpaned), text);
gtk_widget_show (text);
gtk_widget_show (window);
gtk_main ();
return 0;
}
Aspect 프레임은 몇가지 특징을 빼면 프레임 widget과 비슷하다. 이 widget은 자식 widget의 aspect 비율(가로와 세로 비율)이 반드시 어떤 특정한 값이 되도록 때에 따라 여분의 공간을 더해서라도 강제한다. 이것은 예를 들면 상당히 큰 이미지의 미리보기를 보는 때 같은 경우 유용하다. 이 미리보기의 크기는 사용자가 윈도의 크기를 바꿀 때마다 달라지지만 가로세로 비율은 언제나 원래 이미지와 같아야만 한다.
새로운 aspect 프레임을 만드려면,
GtkWidget* gtk_aspect_frame_new (const gchar *label,
gfloat xalign,
gfloat yalign,
gfloat ratio,
gint obey_child)
xalign
와 yalign
은 Alignment widget에서처럼 widget의 alignment 값을
정한다.
만일 obey_child
값이 true면, 자식 widget의 가로세로 비율은
원래 만들어졌을 때의 이상적인 비율과 같게 된다. 반대로 false이면 그 비율은
ratio
로 직접 주어진다.
이미 존재하고 있는 aspect 프레임의 옵션을 바꾸려면 다음 함수를 이용한다.
void gtk_aspect_frame_set (GtkAspectFrame *aspect_frame,
gfloat xalign,
gfloat yalign,
gfloat ratio,
gint obey_child)
예제인 다음 프로그램은 사용자가 toplevel 윈도의 크기를 어떻게 바꾸든 언제나 가로세로 비율이 2:1인 drawing area를 표현하는데 AspectFrame을 쓰고 있다.
/* aspectframe.c */
#include <gtk/gtk.h>
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *aspect_frame;
GtkWidget *drawing_area;
gtk_init (&argc, &argv);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
gtk_container_border_width (GTK_CONTAINER (window), 10);
/* aspect_frame을 만들어 toplevel 윈도에 더한다 */
aspect_frame = gtk_aspect_frame_new ("2x1", /* 레이블 */
0.5, /* center x */
0.5, /* center y */
2, /* xsize/ysize = 2 */
FALSE /* 자식의 가로세로 비율 무시*/);
gtk_container_add (GTK_CONTAINER(window), aspect_frame);
gtk_widget_show (aspect_frame);
/* aspect frame에 더할 자식 widget을 만든다*/
drawing_area = gtk_drawing_area_new ();
/* 200x200 윈도를 요청했지만 AspectFrame은 2:1 비율을 강제하기 때문에
* 200x100 윈도를 준다. */
gtk_widget_set_usize (drawing_area, 200, 200);
gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area);
gtk_widget_show (drawing_area);
gtk_widget_show (window);
gtk_main ();
return 0;
}