第2章 ウィジェットの配置  第2章と第3章ではWindowsのダイアログボックスを使ったプログラムを作成し、それと 同等の機能を持つGTK+のプログラムを作成していきます。 §ダイアログボックス  Windowsにはダイアログボックスというものがあります。Windowsでは通常のウインド ウとダイアログボックスは異なるものだと考えられています。使うAPIも通常のウインド ウとダイアログボックスは異なります。  GTK+にはダイアログボックスというものはありません。GtkWindowウィジェットがダイ アログボックスのような役割をします。GTK+ではGtkWindowウィジェットに描画できませ んし、GTK+のGtkWindowウィジェットはWindowsの通常のウインドウに対応させて考える よりも、Windowsのダイアログボックスに対応させて考える方が適切かも知れません。  Windowsではダイアログボックスはリソースエディタでダイアログボックスをデザイン します。ダイアログボックスのレイアウトは実行可能ファイルのリソース領域に格納さ れ、実行時に読み出されます。しかしGTK+にはWindowsのリソースのようなものはありま せん(GTK+にもリソースというものはありますが、Windowsのリソース対応するようなも のではありません)。基本的にすべてのウィジェットをAPIを呼び出して作成し、配置し ていきます。  win0201.cはWindowsのダイアログボックスの例です。ダイアログボックスではプログ ラムはウインドウの内容を描画する必要はありません。プログラムはダイアログボック スに配置したコントロールから送られてくるメッセージに応答します。  win0201.cはハンバーガーとドリンクなどを購入するプログラムです。win0201.cには リストボックス、コンボボックス、ラジオボタン、チェックボックス、エディトコント ロール、スタティック、ボタンがあります。ハンバーガーは各種1つだけ購入できます。 飲み物は1つだけ購入できます。ポテトはスモール、ミディアム、ラージのいずれかを購 入します。ナゲットを購入することもできます。  これらのコントロールが変化すると、エディトコントロールに入力された所持金と比 較され、購入可能ならばボタンが有効になります。差額はスタティックに表示されま す。 win0201.c---------------------------------------------------------------------- #include #include #include "win0201.h" #define APPLICATION _T("WIN0201") typedef struct tagMCITEM { int nPrice; LPTSTR lpszName; } MCITEM, *LPMCITEM; static BOOL CALLBACK DlgProc (HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { int i, nIndex; MCITEM mciBurger[] = { { 80, _T("ハンバーガー")}, {120, _T("チーズバーガー")}, {150, _T("フランクバーガー")}, {190, _T("ベーコンレタスバーガー")}, {190, _T("フィレオフィッシュ")}, {190, _T("てりやきバーガー")}, {220, _T("スターバーガー")}, {220, _T("ダブルチーズバーガー")}, {250, _T("チキンタツタ")}, {250, _T("ビックバーガー")}, { 0, NULL}}; MCITEM mciDrink[] = { {160, _T("コーラ")}, {160, _T("ニッキ水")}, {160, _T("炭酸入り麦茶")}, {160, _T("グレープジュース")}, {160, _T("緑茶")}, {160, _T("オレンジジュース")}, {160, _T("アイスコーヒー")}, {160, _T("アイスティー")}, {160, _T("牛乳")}, {180, _T("アイスカフェオレ")}, {180, _T("コーヒー")}, {180, _T("コーンポタージュスープ")}, {180, _T("ココア")}, {180, _T("紅茶")}, { 0, NULL}}; /* リストボックスの設定 */ for (i = 0; mciBurger[i].nPrice > 0; i++) { nIndex = SendDlgItemMessage (hDlg, IDC_LISTBOX, LB_ADDSTRING, 0, (LPARAM)mciBurger[i].lpszName); SendDlgItemMessage (hDlg, IDC_LISTBOX, LB_SETITEMDATA, nIndex, mciBurger[i].nPrice); } /* コンボボックスの設定 */ for (i = 0; mciDrink[i].nPrice > 0; i++) { nIndex = SendDlgItemMessage (hDlg, IDC_COMBOBOX, CB_ADDSTRING, 0, (LPARAM)mciDrink[i].lpszName); SendDlgItemMessage (hDlg, IDC_COMBOBOX, CB_SETITEMDATA, nIndex, mciDrink[i].nPrice); } SendDlgItemMessage (hDlg, IDC_COMBOBOX, CB_SETCURSEL, 0, 0); /* ラジオボタンの設定 */ CheckRadioButton (hDlg, IDC_RADIOBUTTON1, IDC_RADIOBUTTON3, IDC_RADIOBUTTON1); /* チェックボックスの設定 */ CheckDlgButton (hDlg, IDC_CHECKBOX, BST_CHECKED); /* エディトコントロールの設定 */ SetDlgItemText (hDlg, IDC_EDIT, _T("0")); } return TRUE; case WM_COMMAND: switch (LOWORD (wParam)) { case IDOK: case IDCANCEL: if (!EndDialog (hDlg, LOWORD (wParam))) MessageBox (hDlg, _T("EndDialog"), APPLICATION, MB_OK | MB_ICONEXCLAMATION); return TRUE; case IDC_LISTBOX: if (HIWORD (wParam) == LBN_SELCHANGE) goto loop; break; case IDC_COMBOBOX: if (HIWORD (wParam) == CBN_SELCHANGE) goto loop; break; case IDC_EDIT: if (HIWORD (wParam) == EN_CHANGE) goto loop; break; case IDC_RADIOBUTTON1: case IDC_RADIOBUTTON2: case IDC_RADIOBUTTON3: case IDC_CHECKBOX: loop: { int i, nIndex, nItems, nPrice = 0, nMoney; INT list[10]; TCHAR szText[512]; HWND hWnd; /* リストボックスで選択されている項目を取得 */ nItems = SendDlgItemMessage(hDlg, IDC_LISTBOX, LB_GETSELITEMS, 10, (LPARAM)list); for (i = 0; i < nItems; i++) nPrice += SendDlgItemMessage (hDlg, IDC_LISTBOX, LB_GETITEMDATA, list[i], 0); /* コンボボックスで選択されている項目を取得 */ nIndex = SendDlgItemMessage (hDlg, IDC_COMBOBOX, CB_GETCURSEL, 0, 0); nPrice += SendDlgItemMessage (hDlg, IDC_COMBOBOX, CB_GETITEMDATA, nIndex, 0); /* 選択されているラジオボタンを取得 */ if (IsDlgButtonChecked (hDlg, IDC_RADIOBUTTON1) == BST_CHECKED) nPrice += 150; if (IsDlgButtonChecked (hDlg, IDC_RADIOBUTTON2) == BST_CHECKED) nPrice += 240; if (IsDlgButtonChecked (hDlg, IDC_RADIOBUTTON3) == BST_CHECKED) nPrice += 290; /* チェックボックスがチェックされているか調べる */ if (IsDlgButtonChecked (hDlg, IDC_CHECKBOX) == BST_CHECKED) nPrice += 190; /* エディトコントロールから所持金を取得する */ nMoney = GetDlgItemInt (hDlg, IDC_EDIT, NULL, TRUE); /* 所持金が多ければ購入ができる */ hWnd = GetDlgItem (hDlg, IDOK); EnableWindow (hWnd, nMoney >= nPrice); /* 価格と残金を表示する */ wsprintf (szText, _T("-%d=%d"), nPrice, nMoney - nPrice); SetDlgItemText (hDlg, IDC_STATIC, szText); } } return TRUE; } return FALSE; } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { return DialogBox (hInstance, MAKEINTRESOURCE (DIALOG_1), HWND_DESKTOP, DlgProc); } -------------------------------------------------------------------------------  win0201.cと同じ動作をするプログラムをGTK+で作りたいと思います。 §ウィジェットの配置  gtk0102.cで、1つのウィジェットをGtkWindowウィジェットにgtk_container_addで加 えることはできました。しかしGtkWindowウィジェットにgtk_container_addで複数の ウィジェットを加えることはできません。  そこで複数のウィジェットをもつことができるウィジェットを使います。具体的には GtkHBoxヴィジェットとGtkVBoxヴィジェットです。GtkHBoxヴィジェットは子ウィジェッ トを横に並べ、GtkVBoxヴィジェットは子ウィジェットを縦に並べます。GtkHBoxヴィ ジェットやGtkVBoxヴィジェットにGtkHBoxヴィジェットやGtkVBoxヴィジェットを入れる こともできます。この2つのウィジェットがあれば、どんなレイアウトも可能です。  そうは言ってもいきなりwin0201.cのようなウインドウを作るのは困難です。そこでま ずは右中のラジオボタンが3つ並んでいるところから作ります。 gtk0201.c---------------------------------------------------------------------- #include int main (int argc, char *argv[]) { GtkWidget *window, *radio1, *radio2, *radio3, *hbox; /* 初期化 */ gtk_set_locale (); gtk_init (&argc, &argv); /* ウインドウを作る */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); /* ラジオボタンを作る */ radio1 = gtk_radio_button_new_with_label (NULL, "スモール"); radio2 = gtk_radio_button_new_with_label (NULL, "ミディアム"); radio3 = gtk_radio_button_new_with_label (NULL, "ラージ"); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスにラジオボタンを入れる */ gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio2, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio3, FALSE, FALSE, 0); /* ウインドウに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (window), hbox); /* ウインドウを表示する */ gtk_widget_show_all (window); /* イベントループ */ gtk_main (); return 0; } -------------------------------------------------------------------------------  gtk_box_pack_startはGtkHBoxヴィジェットならば左から、GtkVBoxヴィジェットなら ば上から順番にヴィジェットを入れます。gtk_box_pack_endというAPIもあり、これは gtk_box_pack_startの反対、GtkHBoxヴィジェットならば右から、GtkVBoxヴィジェット ならば上から順番にヴィジェットを入れます。各ヴィジェットは適切な位置に配置さ れ、必要最小のサイズになります。  Windowsではダイアログボックスを作るときにはコントロールの位置とサイズを指定し ました。Windowsでは位置とサイズで間違った値を指定すると、文字がコントロール内に 収まりきれずに欠けてしまったり、コントロール同士が重なってしまうことがありま す。  GTK+では各ヴィジェットの位置関係を指定します。座標で位置を管理することはあり ません(そうすることもできますが)。絶対的な位置とサイズでダイアログをデザインし ていくWindowsに対して、GTK+では相対的な位置関係を決めることでウインドウをデザイ ンしていきます。WindowsプログラマはGTK+とWindowsの文化の違いに戸惑うかも知れま せん。  win0201.cではラジオボタンは枠で囲まれていました。GTK+ではGtkFrameウィジェット を使います。ラジオボタンを枠で囲ってみます。 gtk0202.c---------------------------------------------------------------------- #include int main (int argc, char *argv[]) { GtkWidget *window, *radio1, *radio2, *radio3, *frame, *hbox; /* 初期化 */ gtk_set_locale (); gtk_init (&argc, &argv); /* ウインドウを作る */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); /* ラジオボタンを作る */ radio1 = gtk_radio_button_new_with_label (NULL, "スモール"); radio2 = gtk_radio_button_new_with_label (NULL, "ミディアム"); radio3 = gtk_radio_button_new_with_label (NULL, "ラージ"); /* 水平ボックス */ hbox = gtk_hbox_new(FALSE,0); /* 水平ボックスにラジオボタンを入れる */ gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio2, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio3, FALSE, FALSE, 0); /* フレームを作る */ frame = gtk_frame_new ("ポテト"); /* フレームに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (frame), hbox); /* ウインドウにフレームを入れる */ gtk_container_add (GTK_CONTAINER (window), frame); /* ウインドウを表示する */ gtk_widget_show_all (window); /* イベントループ */ gtk_main (); return 0; } -------------------------------------------------------------------------------  win0201.cではこのフレームの上にはコンボボックスがあり、このフレームの下には チェックボックスとエディトコントロール、スタティック、ボタンがありました。右下 のエディトコントロール、スタティック、ボタンは横に並んでいます。GtkRadioButton ウィジェットを並べたときと同じように、これらをGtkHBoxウィジェットに入れることが できそうです。そして、そのGtkHBoxウィジェットとGtkComboウィジェットとGtkFrame ウィジェット、GtkCheckButtonウィジェットを縦に並べればwin0201.cの右側が作れそう です。  GTK+-2.4以降ではGtkComboBoxウィジェットがあります。GTK+-2.4以降ならば GtkComboBoxウィジェットを使うことが推奨されます。GTK_CHECK_VERSIONはバージョン を判定するマクロです。指定したバージョン以降ならば真になります。  gtk0203.cではwin0201.cの右側に相当する部分を作ります。 gtk0203.c---------------------------------------------------------------------- #include int main (int argc, char *argv[]) { GtkWidget *button, *check, *combo, *entry, *frame, *label, *hbox; GtkWidget *radio1, *radio2, *radio3, *vbox, *window; /* 初期化 */ gtk_set_locale (); gtk_init (&argc, &argv); /* ウインドウを作る */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); /* コンボボックスを作る */ #if GTK_CHECK_VERSION(2,4,0) combo = gtk_combo_box_new (); #else /* not GTK_CHECK_VERSION(2,4,0) */ combo = gtk_combo_new (); #endif /* not GTK_CHECK_VERSION(2,4,0) */ /* ラジオボタンを作る */ radio1 = gtk_radio_button_new_with_label (NULL, "スモール"); radio2 = gtk_radio_button_new_with_label (NULL, "ミディアム"); radio3 = gtk_radio_button_new_with_label (NULL, "ラージ"); /* チェックボタンを作る */ check = gtk_check_button_new_with_label ("ナゲット"); /* エントリーを作る */ entry = gtk_entry_new (); /* ラベルを作る */ label = gtk_label_new ("Label"); /* ボタンを作る */ button = gtk_button_new_with_label ("購入"); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスにラジオボタンを入れる */ gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio2, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio3, FALSE, FALSE, 0); /* フレームを作る */ frame = gtk_frame_new ("ポテト"); /* フレームに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (frame), hbox); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスに右下の3つのウィジェットを入れる */ gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); /* 垂直ボックス */ vbox = gtk_vbox_new (FALSE, 0); /* コンボボックス、 フレーム(ラジオボタンが3つ入っている)、チェックボックス、 水平ボックス(右下の3つのウィジェットが入っている)を入れる */ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); /* ウインドウに垂直ボックスを入れる */ gtk_container_add (GTK_CONTAINER (window), vbox); /* ウインドウを表示する */ gtk_widget_show_all (window); /* イベントループ */ gtk_main (); return 0; } -------------------------------------------------------------------------------  もう残っているのは1つだけです。GtkTreeViewウィジェットはWindowsのリストボック スに対応する機能をもっています。GtkTreeViewウィジェットとこのGtkVBoxウィジェッ トを水平に並べれば完成です。GtkTreeViewウィジェットを加えます。 gtk0204.c---------------------------------------------------------------------- #include int main(int argc,char *argv[]) { GtkListStore *store; GtkWidget *button, *check, *combo, *entry, *frame, *label, *hbox; GtkWidget *list, *radio1, *radio2, *radio3, *vbox, *window; /* 初期化 */ gtk_set_locale (); gtk_init (&argc, &argv); /* ウインドウを作る */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); /* リストボックスを作る */ store = gtk_list_store_new (1, G_TYPE_STRING); list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref (store); /* リストボックスの最低サイズ リストボックスが空だとサイズが0になってしまい レイアウトを見れないので最低サイズを指定する */ gtk_widget_set_size_request (list, 80, 60); /* コンボボックスを作る */ #if GTK_CHECK_VERSION(2,4,0) combo = gtk_combo_box_new (); #else /* not GTK_CHECK_VERSION(2,4,0) */ combo = gtk_combo_new (); #endif /* not GTK_CHECK_VERSION(2,4,0) */ /* ラジオボタンを作る */ radio1 = gtk_radio_button_new_with_label (NULL, "スモール"); radio2 = gtk_radio_button_new_with_label (NULL, "ミディアム"); radio3 = gtk_radio_button_new_with_label (NULL, "ラージ"); /* チェックボタンを作る */ check = gtk_check_button_new_with_label ("ナゲット"); /* エントリーを作る */ entry = gtk_entry_new (); /* ラベルを作る */ label = gtk_label_new ("Label"); /* ボタンを作る */ button = gtk_button_new_with_label ("購入"); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスにラジオボタンを入れる */ gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio2, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio3, FALSE, FALSE, 0); /* フレームを作る */ frame =gtk_frame_new ("ポテト"); /* フレームに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (frame), hbox); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスに右下の3つのウィジェットを入れる */ gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); /* 垂直ボックス */ vbox = gtk_vbox_new (FALSE, 0); /* コンボボックス、 フレーム(ラジオボタンが3つ入っている)、チェックボックス、 水平ボックス(右下の3つのウィジェットが入っている)を入れる */ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスにリストと 垂直ボックス(右側のウィジェットが入っている)を入れる */ gtk_box_pack_start (GTK_BOX (hbox), list, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); /* ウインドウに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (window), hbox); /* ウインドウを表示する */ gtk_widget_show_all (window); /* イベントループ */ gtk_main (); return 0; } -------------------------------------------------------------------------------  Windowsの場合、リソースエディタなどで平面的なダイアログボックスにコントロール を一気に配置してデザインします。同じようにGTK+で1度にすべてのウィジェットの配置 を考えようとすると破綻します。GTK+では小さいまとまりから順番にウィジェットの配 置を考えていったほうが上手くできると思います。 §ウィジェットの配置設定一覧  gtk0204.cで一応の形にはなりましたが、各ウィジェットが隙間なく配置されているの で見栄えが良くありません。win0201.cのように各ウィジェットの間に隙間を入れたいと 思います。  gtk_hbox_newまたはgtk_vbox_newには2つの引数があります。 GtkWidget* gtk_hbox_new (gboolean homogeneous, gint spacing);  homogeneousがTRUEならば子ウィジェットのサイズはすべて同じになり、FALSEならば 子ウィジェットのサイズは異なります。spacingは各子ウィジェットの間のピクセル数で す。  gtk_box_pack_start(あるいはgtk_box_pack_end)には4つの引数があります。 void gtk_box_pack_start (GtkBox *box, GtkWidget *child, gboolean expand, gboolean fill, guint padding);  expandがTRUEならば適当な間隔でウィジェットが表示され、FALSEならばウィジェット は左または上(gtk_box_pack_endならば右または下)に詰めて表示されます。 fillがTRUEならばウィジェットは拡大されますが、FALSEならばウィジェットは必要最小 のサイズのままです。expandがFALSEならばfillの値は無効になります。paddingはその ウィジェットと隣のウィジェットの隙間のピクセル数です。  複雑なので実際にどうなるか見たほうが早いと思います。gtk0205.cを実行すればすべ てのパターン(32通り)を表示します。(gtk0205.cの解説はありません) §ウィジェットの配置を整える  まずGtkRadioButtonウィジェットに注目します。各GtkRadioButtonウィジェットの間 隔が無いので、GtkRadioButtonウィジェットを入れるGtkHBoxウィジェットのspacingを8 にします。expandをTRUEにしてGtkRadioButtonウィジェットが均等に配置されるように します。またGtkRadioButtonウィジェットとその周りのGtkFrameウィジェットの間隔も ありません。その理由はGtkHBoxウィジェットとGtkFrameウィジェットの間隔が無いから です。GtkHBoxウィジェットとGtkFrameウィジェットの間隔をとるためにGtkHBoxウィ ジェットをもう1度paddingを8にしてGtkHBoxウィジェットとGtkVBoxウィジェットに入れ てからGtkFrameウィジェットに入れます。これでGtkFrameウィジェットの内部について は解決します。  右下のGtkEntryウィジェット、GtkLabelウィジェット、GtkButtonウィジェットの間隔 は現状で問題ありません。GtkButtonウィジェットだけはexpandをFALSEにして必要最小 のサイズにしますが、GtkEntryウィジェットとGtkLabelウィジェットはexpandとfillを TRUEにして拡大されるようにします。  右側のGtkComboウィジェット、GtkFrameウィジェット、GtkCheckButtonウィジェッ ト、GtkHBoxウィジェットを入れるGtkVBoxウィジェットはspacingを8にして間隔をとり ます。GtkHBoxウィジェットはgtk_box_pack_endで入れることでウインドウのに付くよう にします。  GtkListウィジェットと右側のGtkVBoxウィジェットを入れるGtkHBoxウィジェットも spacingを8にして間隔をとります。expandとfillをTRUEにして拡大されるようにしま す。このGtkHBoxウィジェットとウインドウの枠との間隔をとるために、GtkFrameウィ ジェットにGtkHBoxウィジェットを入れたときのように、GtkHBoxウィジェットをpadding を8にしてGtkHBoxウィジェットとGtkVBoxウィジェットに入れます。 gtk0206.c---------------------------------------------------------------------- #include #define SPACING 8 int main (int argc, char *argv[]) { GtkListStore *store; GtkWidget *button, *check, *combo, *entry, *frame, *label, *hbox; GtkWidget *list, *radio1, *radio2, *radio3, *vbox, *window; /* 初期化 */ gtk_set_locale (); gtk_init (&argc, &argv); /* ウインドウを作る */ window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL); /* リストボックスを作る */ store = gtk_list_store_new (1, G_TYPE_STRING); list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); g_object_unref (store); /* リストボックスの最低サイズ リストボックスが空だとサイズが0になってしまい レイアウトを見れないので最低サイズを指定する */ gtk_widget_set_size_request (list, 80, 60); /* コンボボックスを作る */ #if GTK_CHECK_VERSION(2,4,0) combo = gtk_combo_box_new (); #else /* not GTK_CHECK_VERSION(2,4,0) */ combo = gtk_combo_new (); #endif /* not GTK_CHECK_VERSION(2,4,0) */ /* ラジオボタンを作る */ radio1 = gtk_radio_button_new_with_label (NULL, "スモール"); radio2 = gtk_radio_button_new_with_label (NULL, "ミディアム"); radio3 = gtk_radio_button_new_with_label (NULL, "ラージ"); /* チェックボタンを作る */ check = gtk_check_button_new_with_label ("ナゲット"); /* エントリーを作る */ entry = gtk_entry_new (); /* ラベルを作る */ label = gtk_label_new ("Label"); /* ボタンを作る */ button = gtk_button_new_with_label ("購入"); /***** 配置 *****/ /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, SPACING); /* 水平ボックスにラジオボタンを入れる */ gtk_box_pack_start (GTK_BOX (hbox), radio1, TRUE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio2, TRUE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), radio3, TRUE, FALSE, 0); /* 垂直ボックスと水平ボックス */ vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, SPACING); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, SPACING); /* フレームを作る */ frame = gtk_frame_new ("ポテト"); /* フレームに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (frame), hbox); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, 0); /* 水平ボックスに右下の3つのウィジェットを入れる */ gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); /* 垂直ボックス */ vbox = gtk_vbox_new (FALSE, SPACING); /* コンボボックス、 フレーム(ラジオボタンが3つ入っている)、チェックボックス、 水平ボックス(右下の3つのウィジェットが入っている)を入れる */ gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); /* 水平ボックス */ hbox = gtk_hbox_new (FALSE, SPACING); /* 水平ボックスにリストと 垂直ボックス(右側のウィジェットが入っている)を入れる */ gtk_box_pack_start (GTK_BOX (hbox), list, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0); /* 垂直ボックスと水平ボックス */ vbox = gtk_vbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, SPACING); hbox = gtk_hbox_new (FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, SPACING); /* ウインドウに水平ボックスを入れる */ gtk_container_add (GTK_CONTAINER (window), hbox); /* ウインドウを表示する */ gtk_widget_show_all (window); /* イベントループ */ gtk_main (); return 0; } -------------------------------------------------------------------------------