差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
fltk:widget-basic-menus [2025/05/30 17:33] – [Fl_Menu_クラス] Apply imagebox plugin freemikanfltk:widget-basic-menus [2025/06/14 12:25] (現在) – [Fl_Menu_Buttonクラス] Write body text freemikan
行 19: 行 19:
 具体的な用途によって、Fl_Menu_Barクラス、Fl_Menu_Buttonクラス、Fl_Choiceクラスが派生クラスとして提供されています。 具体的な用途によって、Fl_Menu_Barクラス、Fl_Menu_Buttonクラス、Fl_Choiceクラスが派生クラスとして提供されています。
  
 +[[https://www.fltk.org/doc-1.4/classFl__Menu__.html|{{ https://www.fltk.org/doc-1.4/classFl__Menu__.png |Fl_Menu_クラス前後の階層図}}]]
 +<WRAP centeralign>Fl_Menu_クラス前後の階層図</WRAP>
  
  
-[{{ https://www.fltk.org/doc-1.4/classFl__Menu__.png |Fl_Menuクラス前後の階層図}}]+==== Fl_Menu_Barクラス ==== 
 +[[https://www.fltk.org/doc-1.4/classFl__Menu__Bar.html|{{ https://www.fltk.org/doc-1.4/classFl__Menu__Bar.png | Fl_Menu_Barクラス前後の階層図}}]
 +<WRAP centeralign>Fl_Menu_Barクラス前後の階層図</WRAP>
  
 +
 +典型的なGUIアプリケーションで目にする、ウィンドウ最上部のメニューバーを実現するためのクラスです。
 +FLTKではメニューバーもやはりウィジェットです。
 +サイズや位置を設定することができるので、必ずしもウィンドウの最上部に配置しなければならないことはありません。
 +この自由度は一方であまり直感的とは言えない使い方が求められます。
 +例えば、次のようなことが考えられます。
 +
 +  * メニューバーの初期サイズにウィンドウのサイズと同じだけの幅とUIフォントのサイズを考慮した高さを与えることが必須である。
 +  * ユーザーがマウスでウィンドウの枠をドラッグしてサイズを変更したときにメニューバーが縦に拡大されることを回避するよう配慮しないといけない。
 +
 +次のサンプルプログラムでは、メニューバーの構築方法と、ウィンドウのサイズ変更に対して自然な振る舞いになるようにする方法を示しています。
 +
 +<code cpp>
 +#include <FL/Fl.H>
 +#include <FL/Fl_File_Chooser.H>
 +#include <FL/Fl_Group.H>
 +#include <FL/Fl_Menu_Bar.H>
 +#include <FL/Fl_Menu_Item.H>
 +#include <FL/Fl_Window.H>
 +#include <FL/fl_ask.H>
 +
 +#include <cstdio>
 +
 +void file_open_cb(Fl_Widget *w, void *data) {
 +  if (auto file_name = fl_file_chooser("select file", "*.cpp", "foo.cpp", 1)) {
 +    printf("Chosen file: %s\n", file_name);
 +  }
 +}
 +
 +void file_quit_cb(Fl_Widget *w, void *data) {
 +  if (fl_choice_n("Do you really want to quit?", "&No", "&Yes", nullptr) == 1) {
 +    Fl::hide_all_windows();
 +  }
 +}
 +
 +void edit_undo_cb(Fl_Widget *w, void *data) { /* TODO */ }
 +void edit_redo_cb(Fl_Widget *w, void *data) { /* TODO */ }
 +void edit_cut_cb(Fl_Widget *w, void *data) { /* TODO */ }
 +void edit_copy_cb(Fl_Widget *w, void *data) { /* TODO */ }
 +void edit_paste_cb(Fl_Widget *w, void *data) { /* TODO */ }
 +
 +void help_help_cb(Fl_Widget *w, void *data) {
 +  fl_message("I'm sorry, but I cannot help you now.");
 +}
 +
 +void help_about_cb(Fl_Widget *w, void *data) {
 +  fl_message("The purpose of this program is to demonstrate how to use Fl_Menu_Bar.");
 +}
 +
 +int main(int argc, char **argv) {
 +  auto window = new Fl_Window{400, 400, "Fl_Menu_Bar demo"};
 +
 +  auto menu_bar = new Fl_Menu_Bar{0, 0, window->w(), 30, "Menu"};
 +  menu_bar->add("ファイル(&F)/開く(&O)", FL_COMMAND + 'o', file_open_cb, nullptr, FL_MENU_DIVIDER);
 +  menu_bar->add("ファイル(&F)/終了(&Q)", FL_COMMAND + 'q', file_quit_cb);
 +  menu_bar->add("編集(&E)/元に戻す(&U)", "^z", edit_undo_cb);
 +  menu_bar->add("編集(&E)/やり直し(&R)", "^Z", edit_redo_cb, nullptr, FL_MENU_DIVIDER);
 +  menu_bar->add("編集(&E)/切り取り(&X)", "^x", edit_cut_cb);
 +  menu_bar->add("編集(&E)/コピー(&C)", "^c", edit_copy_cb);
 +  menu_bar->add("編集(&E)/貼り付け(&P)", "^v", edit_paste_cb);
 +  menu_bar->add("編集(&E)/削除(&D)");
 +  menu_bar->add("編集(&E)/すべて選択(&A)", "^a", edit_paste_cb);
 +  menu_bar->add("ヘルプ(&H)/ヘルプ(&H)", FL_F + 1, help_help_cb);
 +  menu_bar->add("ヘルプ(&H)/このアプリケーションについて...(&A)", FL_SHIFT + FL_F + 1, help_about_cb);
 +  menu_bar->menu_end();
 +
 +  // マウスでドラッグしてウィンドウのサイズを変更できるようにする
 +  // ただし、メニューバーの高さは変化しないようにする
 +  // メニューバーの領域を含めないことがポイント
 +  auto group = new Fl_Group{0, menu_bar->h(), window->w(), window->h() - menu_bar->h()};
 +  group->end();
 +  window->resizable(group);
 +
 +  window->end();
 +  window->show(argc, argv);
 +
 +  // https://www.fltk.org/doc-1.4/classFl__Menu__.html#a8db18d83b2166eaba3b4b465ef0373a0
 +  for (int t = 0; t < menu_bar->size(); t++) {       // walk array of items
 +    const Fl_Menu_Item &item = menu_bar->menu()[t];  // get each item
 +    fprintf(stderr, "item #%d -- label=%s,\tvalue=%s,\ttype=%s\n", t,
 +            item.label() ? item.label() : "(Null)",           // menu terminators have NULL labels
 +            (item.flags & FL_MENU_VALUE) ? "set" : "clear",   // value of toggle or radio items
 +            (item.flags & FL_SUBMENU) ? "Submenu" : "Item");  // see if item is a submenu or actual item
 +  }
 +
 +  return Fl::run();
 +}
 +</code>
 +
 +==== Fl_Menu_Buttonクラス ====
 +[[https://www.fltk.org/doc-1.4/classFl__Menu__Button.html|{{ https://www.fltk.org/doc-1.4/classFl__Menu__Button.png | Fl_Menu_Buttonクラス前後の階層図}}]]
 +<WRAP centeralign>Fl_Menu_Buttonクラス前後の階層図</WRAP>
 +
 +Fl_Menu_Buttonクラスのウィジェットは、クリックすると選択項目が表示されるドロップダウン形式のボタンです。
 +また、メンバ関数type()でポップアップのタイプを設定することによってポップアップメニューとして利用できます。
 +これによって、多くのGUIアプリケーションやウィンドウシステムが採用している典型的な右クリックメニューを実現できます。
 +
 +<code cpp>
 +#include <FL/Fl.H>
 +#include <FL/Fl_Menu_Button.H>
 +#include <FL/Fl_Menu_Item.H>
 +#include <FL/Fl_Window.H>
 +
 +#include <cstdio>
 +
 +// ダミーのコールバック
 +void the_cb(Fl_Widget *w, void *data) {}
 +void strange_cb(Fl_Widget *w, void *data) {}
 +void charm_cb(Fl_Widget *w, void *data) {}
 +void truth_cb(Fl_Widget *w, void *data) {}
 +void beauty_cb(Fl_Widget *w, void *data) {}
 +
 +int main(int argc, char **argv) {
 +  auto window = new Fl_Window{400, 400, "Fl_Menu_Button demo"};
 +
 +  // https://www.fltk.org/doc-1.4/structFl__Menu__Item.html#details
 +  Fl_Menu_Item menu_table[] = {{"&alpha", FL_ALT + 'a', the_cb, (void *)1},
 +                               {"&beta", FL_ALT + 'b', the_cb, (void *)2},
 +                               {"gamma", FL_ALT + 'c', the_cb, (void *)3, FL_MENU_DIVIDER},
 +                               {"&strange", 0, strange_cb},
 +                               {"&charm", 0, charm_cb},
 +                               {"&truth", 0, truth_cb},
 +                               {"b&eauty", 0, beauty_cb},
 +                               {"sub&menu", 0, 0, 0, FL_SUBMENU},
 +                               {"one"},
 +                               {"two"},
 +                               {"three"},
 +                               {0},
 +                               {"inactive", FL_ALT + 'i', 0, 0, FL_MENU_INACTIVE | FL_MENU_DIVIDER},
 +                               {"invisible", FL_ALT + 'i', 0, 0, FL_MENU_INVISIBLE},
 +                               {"check", FL_ALT + 'i', 0, 0, FL_MENU_TOGGLE | FL_MENU_VALUE},
 +                               {"box", FL_ALT + 'i', 0, 0, FL_MENU_TOGGLE},
 +                               {0}};
 +
 +  // ドロップダウンタイプのボタン
 +  auto menu_button = new Fl_Menu_Button{10, 10, 150, 30, "&Menu Button"};
 +  menu_button->menu(menu_table);
 +
 +  // 右クリックで表示されるポップアップメニュー
 +  // ボタンの位置とサイズがクリックの有効範囲となる
 +  auto menu_popup = new Fl_Menu_Button{0, 0, window->w(), window->h(), "&Popup"};
 +  menu_popup->menu(menu_table);
 +  menu_popup->type(Fl_Menu_Button::POPUP3);
 +
 +  window->end();
 +  window->show(argc, argv);
 +
 +  // https://www.fltk.org/doc-1.4/classFl__Menu__.html#a8db18d83b2166eaba3b4b465ef0373a0
 +  for (int t = 0; t < menu_button->size(); t++) {       // walk array of items
 +    const Fl_Menu_Item &item = menu_button->menu()[t];  // get each item
 +    fprintf(stderr, "item #%d -- label=%s,\tvalue=%s,\ttype=%s\n", t,
 +            item.label() ? item.label() : "(Null)",           // menu terminators have NULL labels
 +            (item.flags & FL_MENU_VALUE) ? "set" : "clear",   // value of toggle or radio items
 +            (item.flags & FL_SUBMENU) ? "Submenu" : "Item");  // see if item is a submenu or actual item
 +  }
 +
 +  return Fl::run();
 +}
 +</code>
  
文書の先頭へ