다음 이전 차례

7. 버튼 widget

7.1 보통의 버튼

우리는 버튼widget에 대해서는 거의 보아왔다. 그것은 상당히 간단하다. 그런데 버튼을 만드는데는 두가지 방법이 있다. 우리는 라벨이 있는 버튼을 만들기 위해 gtk_button_new_with_labe()을 이용할 수 있고, 빈 버튼을 만들기 위해 gtk_button_new()를 이용할 수도 있다. 그런 다음 그것에 라벨을 붙이든지 픽스맵을 붙이든지 하는 것은 여러분에게 달려있다. 그렇게 하려면 새로운 박스를 만들고 gtk_box_pack_start로써 이 박스 안에 우리의 object를 패킹하며, 그 다음엔 gtk_container_add로써 그 박스를 버튼 안으로 패킹하면 된다.

이 예제는 gtk_button_new를 이용하여 그림과 라벨이 있는 버튼을 만든다. 박스를 만드는 코드가 다른 것들로부터 떨어져 나와 있으며 여러분의 프로그램 에서 그것을 이용할 수 있을 것이다.

/* buttons.c */

#include <gtk/gtk.h>

/* 이미지와 그것에 패킹된 라벨을 가지고 있는 hbox를 하나 만든다.
 * 그리고 그 박스를 리턴한다. */

GtkWidget *xpm_label_box (GtkWidget *parent, gchar *xpm_filename, gchar *label_text)
{
                GtkWidget *box1;
                GtkWidget *label;
                GtkWidget *pixmapwid;
                GdkPixmap *pixmap;
                GdkBitmap *mask;
                GtkStyle *style;

                /* xpm과 라벨을 위한 박스를 만든다. */
                box1 = gtk_hbox_new (FALSE, 0);
                gtk_container_border_width (GTK_CONTAINER (box1), 2);

                /* 버튼의 스타일을 취한다.. background 색깔을 취하는 것 같은데,
                 * 아니라면 누군가 나에게 정정해 주길 바란다. */
                style = gtk_widget_get_style(parent);

                /* xpm 파일로부터 픽스맵을 만든다. */
                pixmap = gdk_pixmap_create_from_xpm (parent->window, &mask,
                                             &style->bg[GTK_STATE_NORMAL],
                                             xpm_filename);
                pixmapwid = gtk_pixmap_new (pixmap, mask);

                /* 버튼을 위한 라벨을 만든다. */
                label = gtk_label_new (label_text);

                /* 박스 안으로 픽스맵과 라벨을 패킹해 넣는다. */
                gtk_box_pack_start (GTK_BOX (box1),
                                                        pixmapwid, FALSE, FALSE, 3);

                gtk_box_pack_start (GTK_BOX (box1), label, FALSE, FALSE, 3);

                gtk_widget_show(pixmapwid);
                gtk_widget_show(label);

                return (box1);
}

/* 우리의 전형적인 callback 함수다. */
void callback (GtkWidget *widget, gpointer data)
{
                g_print ("Hello again - %s was pressed\n", (char *) data);
}

int main (int argc, char *argv[])
{
                /* GtkWidget은 widget들을 위한 기억장소 종류다. */
                GtkWidget *window;
                GtkWidget *button;
                GtkWidget *box1;

                gtk_init (&argc, &argv);

                /* 윈도를 하나 만든다. */
                window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

                gtk_window_set_title (GTK_WINDOW (window), "Pixmap'd Buttons!");

                /* 모든 윈도들에 대해 이렇게 해주는 것이 좋을 것이다. */
                gtk_signal_connect (GTK_OBJECT (window), "destroy",
                            GTK_SIGNAL_FUNC (gtk_exit), NULL);

                /* 윈도의 border width를 세팅한다. */
                gtk_container_border_width (GTK_CONTAINER (window), 10);

                /* 새로운 버튼을 하나 만든다. */
                button = gtk_button_new ();

                /* 이쯤에서 이 함수를 쓰는 것을 기억하라. */
                gtk_signal_connect (GTK_OBJECT (button), "clicked",
                            GTK_SIGNAL_FUNC (callback), (gpointer) "cool button");

                /* 박스를 만드는 함수다. */
                box1 = xpm_label_box(window, "info.xpm", "cool button");

                /* 우리 widget들을 패킹하고, 보여준다. */
                gtk_widget_show(box1);

                gtk_container_add (GTK_CONTAINER (button), box1);

                gtk_widget_show(button);

                gtk_container_add (GTK_CONTAINER (window), button);

                gtk_widget_show (window);

                /* 여기서부터는 뭔가 재미있는 일이 시작될 때까지 무작정 기다린다. */
                gtk_main ();

                return 0;
}

xpm_label_box 함수는 컨테이너가 될 수 있는 어떤 widget에라도 픽스맵과 라벨을 패킹하기 위하여 쓰여질 수 있을 것이다.

7.2 토글 버튼

토글버튼은 클릭에 의해 택일되는 두가지 중 어느 한 상태에 있어야 한다는 점만 뺀다면 보통 버튼과 매우 유사하다. 그것은 눌려진 상태로 있다가도, 우리가 다시 클릭해 주면 다시 튀어나오게 될 수 있다. 또 클릭하면 그것은 다시 눌러져 들어갈 것이다.

토글버튼에 쓰이는 많은 함수들이 라디오와 체크 버튼에 의해 상속되어 쓰이듯이, 토글버튼은 체크버튼과 라디오버튼의 기반이 된다. 이것들을 접하게 되면 이 점을 다시 지적할 것이다.

새로운 토글버튼을 만들려면 이것을 이용한다.

GtkWidget* gtk_toggle_button_new (void);

GtkWidget* gtk_toggle_button_new_with_label (gchar *label);

추측할 수 있겠지만, 이것은 보통버튼 widget의 호출과 똑같이 작용한다. 첫번째 것은 빈 토글버튼을, 그리고 두번째 것은 이미 라벨widget이 패킹되어 있는 버튼을 만든다.

토글버튼과 라디오버튼, 체크버튼의 상태를 되돌리기 위해, 우리는 아래의 예제에서 보여질 매크로를 이용한다. 이것은 어떤 callback에서 토글의 상태를 테스트한다. 토글버튼에 의해 발생하는 시그널은 (토글/체크/라디오 버튼 widget들) "toggled" 시그널이다. 이 버튼들의 상태를 체크하려면 이 toggled 시그널을 잡아내도록 시그널 핸들러를 셋업하고, 그것의 상태를 결정하기 위한 매크로를 이용한다. 그 callback은 이런 모양의 것이다.

void toggle_button_callback (GtkWidget *widget, gpointer   data)
{
    if (GTK_TOGGLE_BUTTON (widget)->active)
    {
        /* 컨트롤이 여기로 오면, 토글버튼의 상태는 up이다. */

    } else {

        /* 토글버튼은 down이다. */
    }
}

void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
                                  gint state);

위의 호출은 토글버튼과, 그것에서 파생되는 라디오와 체크버튼의 상태를 세팅하기 위해 쓰일 수 있다. 첫번째 인자로 우리가 만든 버튼을 넘겨주고, 그리고 그것이 눌린 상태인지 아닌지를 구별하기 위해 두번째 인자를 TRUE 또는 FALSE로 넘겨준다. 디폴트는 안 눌러진 상태, 즉 FALSE이다.

우리가 gtk_toggle_button_set_state()함수를 쓰면 버튼에서 "clicked"시그널이 발생해서 버튼의 상태가 실제로 변하게 됨을 기억하자.

void    gtk_toggle_button_toggled (GtkToggleButton *toggle_button);

이것은 간단히 버튼을 토글하고, "toggled"시그널을 발생시킨다.

7.3 체크버튼

체크버튼은 위에 있는 토글버튼에서 많은 특성과 함수들을 상속받았지만 다소 다르게 보인다. 이것은 버튼과 그 안의 텍스트로 있다기보다는, 텍스트 옆에 있는 작은 사각형이라고 할 수 있다. 이들은 어떤 어플에서 토글되는 옵션으로서 많이 봤을 것이다.

이것을 만드는 두가지 함수는 보통버튼에서와 마찬가지다.

GtkWidget* gtk_check_button_new (void);

GtkWidget* gtk_check_button_new_with_label (gchar *label);

new_with_label함수는 옆에 텍스트 라벨을 가지고 있는 체크버튼을 만든다.

체크버튼의 상태를 체크하는 것은 토글버튼에서와 같다.

7.4 라디오버튼

라디오버튼은 그들이 그룹화되어 있어서 한 번에 오직 하나씩만 선택/복귀될 수 있다는 점만 빼고는 체크버튼과 유사하다. 이것은 어플이 옵션의 리스트에서 하나를 선택하도록 하는 경우에 쓰이면 좋을 것이다.

새로운 라디오버튼을 만드는 데 쓰는 함수들이다.

GtkWidget* gtk_radio_button_new (GSList *group);

GtkWidget* gtk_radio_button_new_with_label (GSList *group,
                                            gchar *label);

이 호출들에는 다소 다른 인자가 있다는 것을 눈여겨 보자. 이들은 적절히 임무를 수행할 그룹을 필요로 한다. 첫번째 함수는 첫번째 인자로 NULL을 넘겨 줘야 한다. 그리고 우리는 이것을 이용하여 그룹을 만든다.

GSList* gtk_radio_button_group (GtkRadioButton *radio_button);

그리고는 이 그룹을 gtk_radio_button_new 또는 gtk_radio_button_new_with_ label에 첫번째 인자로 넘겨준다. 다음을 이용해서 어떤 버튼이 디폴트로 눌러지게 되는지를 분명히 해두는 것도 좋은 생각이다.

void gtk_toggle_button_set_state (GtkToggleButton *toggle_button,
                                  gint state);

이것은 토글버튼에 대한 부분에서 설명되었으며, 정확히 같은 방법을 따른다.

다음 예는 세개의 버튼으로 이루어진 그룹을 만든다.

/* radiobuttons.c */

#include <gtk/gtk.h>
#include <glib.h>

void close_application( GtkWidget *widget, gpointer data ) {
  gtk_main_quit();
}

main(int argc,char *argv[])
{
  static GtkWidget *window = NULL;
  GtkWidget *box1;
  GtkWidget *box2;
  GtkWidget *button;
  GtkWidget *separator;
  GSList *group;
  
  gtk_init(&argc,&argv);          
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  
  gtk_signal_connect (GTK_OBJECT (window), "delete_event",
                      GTK_SIGNAL_FUNC(close_application),
                      NULL);

  gtk_window_set_title (GTK_WINDOW (window), "radio buttons");
  gtk_container_border_width (GTK_CONTAINER (window), 0);

  box1 = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (window), box1);
  gtk_widget_show (box1);

  box2 = gtk_vbox_new (FALSE, 10);
  gtk_container_border_width (GTK_CONTAINER (box2), 10);
  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
  gtk_widget_show (box2);

  button = gtk_radio_button_new_with_label (NULL, "button1");
  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
  gtk_widget_show (button);

  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  button = gtk_radio_button_new_with_label(group, "button2");
  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button), TRUE);
  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
  gtk_widget_show (button);

  group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  button = gtk_radio_button_new_with_label(group, "button3");
  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
  gtk_widget_show (button);

  separator = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
  gtk_widget_show (separator);

  box2 = gtk_vbox_new (FALSE, 10);
  gtk_container_border_width (GTK_CONTAINER (box2), 10);
  gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
  gtk_widget_show (box2);

  button = gtk_button_new_with_label ("close");
  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
                             GTK_SIGNAL_FUNC(close_application),
                             GTK_OBJECT (window));
  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  gtk_widget_grab_default (button);
  gtk_widget_show (button);
  gtk_widget_show (window);
     
  gtk_main();
  return(0);
}

다음 문장과 같은 식으로 어떤 변수 하나가 버튼들의 리스트를 가지고 있어야할 필요가 없도록 줄여 쓸 수도 있다.

     button2 = gtk_radio_button_new_with_label(
                 gtk_radio_button_group (GTK_RADIO_BUTTON (button1)),
                 "button2");


다음 이전 차례