GTKmm (3.0) と glade によるアプリ (7) - ツールバーの表示、非表示切り替えとaboutダイアログの表示
今回は、前回の" GTKmm (3.0) と glade によるアプリ (6) - (Qtでも使える)アプリケーションの多重起動の防止 v2 "で作成したプログラムをベースに、ツールバーの表示と表示/非表示の切り替え、そして AboutDialog ("このアプリケーションについて" で表示される) の表示の2つを行います。
最終的にこんな感じですね。
今回設置したツールバーは、アプリケーションの終了ボタンだけ設置しました。
ソースコードは最後に両方の機能を含めたものを公開してます。
■ ツールバーの表示と表示/非表示の切り替え
この作業はメニューバーと同じです。
retiresaki.hatenablog.com
少し面倒なのが、galde のツールバーの設置ですが、すぐになれると思います。
表示だけなら glade で設定すれば表示されます。
1) ツールバーボタンのクリックイベント処理
● ツールバーの終了ボタンに関連したコード
〜 // get toolbar widget refBuilder->get_widget("toolBar", m_toolbar); refBuilder->get_widget("toolbar_quit", m_toolbar_quit); 〜 // toolbar signals m_toolbar_quit->signal_clicked().connect( sigc::mem_fun(*this, &MainWindow::on_btn1_clicked)); 〜
ツールバーボタンのクリックイベントは、普通のボタンのシグナル処理と同様に signal_clicked().connect() で行います。
今回は on_btn1_clicked() を呼び出しています。
2) ツールバーの表示/非表示の切り替え
これはメニューバーの処理と全く同じで、今回は btn3 のクリックイベント処理で切り替えています。
以下のコードをみれば、すぐに理解と思います。
● ツールバーの表示/非表示の切り替えに関連したコード
〜 void MainWindow::on_btn3_clicked() { if (m_toolbar->is_visible()){ m_toolbar->hide(); m_btn3->set_label("click to show toolbarr"); } else{ m_toolbar->show(); m_btn3->set_label("click to hide toolbar"); } } 〜
■ aboutダイアログの表示
今回は普通のアプリと同様にメニューの about から表示するようにします。
1) glade で新たに GTKAboutDialog を作成
特にボタンなど付けず、標準のままcopytightなどのテキストやアイコン指定を行いました。
尚、ソースコードは最後にまとまっています。
2) メニューのクリックイベントから AboutDialog を表示
2.1) AboutDialog に対応したクラスを作成
今回は、APP_AbouDialog.h を作成しました。
特に何かをすることないので、ヘッダーでクラス APP_AboutDialogを定義しただけです。
2.2) メニュー menu_about のクリックイベント処理で APP_AboutDialog を呼び出す
● AboutDialogの表示に関連したコード
〜 refBuilder->get_widget("menu_about", m_menuitem_about); 〜 m_menuitem_about->signal_activate().connect( sigc::mem_fun(*this, &MainWindow::on_app_about)); 〜 void MainWindow::on_app_about() { APP_AboutDialog *about_dialog = nullptr; refBuilder->get_widget_derived("aboutDialog", about_dialog); about_dialog->set_transient_for(*this); about_dialog->show_all(); }〜
メニューの about で on_app_about() を呼び出すところはいつもどおりです
起動時に読み込み済の Gtk::Builder から glade で定義した aboutDialog を get_widget_derived() で取得し。APP_AboutDialog クラスに割り当てます。
set_transient_for() で、AboutDialog の親 MainWindow の手前に表示させます。
show_all() で AboutDialog を表示させます。
glade で設置した GTKAboutDialog でボタンなど追加しない限り、実際に表示されるダイアログ内のクリック処理などは GTKAboutDialog が勝手にやってくれるので、glade やプログラムはどのように表示するか設定するかだけです。
以上です。
1つ1つはとてもシンプルで簡単でしたね。
■今回作成したソースコードとダウンロード
● 今回作成した APP_AboutDialog.h
#ifndef ABOUTDIALOG_H #define ABOUTDIALOG_H #include <gtkmm.h> class APP_AboutDialog : public Gtk::AboutDialog { public: APP_AboutDialog(BaseObjectType* obj, Glib::RefPtr<Gtk::Builder> const& m_builder_) : Gtk::AboutDialog(obj) , m_builder{m_builder_} { } virtual ~APP_AboutDialog() = default; protected: private: Glib::RefPtr<Gtk::Builder> m_builder; }; #endif
● 今回作成した MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <gtkmm.h> #include <glibmm.h> #include <giomm.h> #include <fstream> #include <iostream> #include <string> #include <glib.h> #include "APP_AboutDialog.h" #define ORG_APPICON "test_about.svg" #define CONF_FILE "application.conf" class MainWindow : public Gtk::ApplicationWindow { public: MainWindow(BaseObjectType* obj, Glib::RefPtr<Gtk::Builder> const& m_builder_) : Gtk::ApplicationWindow(obj) , m_builder{m_builder_} { setInit_display(); } virtual ~MainWindow() = default; protected: virtual void on_btn1_clicked(); virtual void on_btn2_clicked(); virtual void on_btn3_clicked(); Gtk::MenuBar *m_menu = nullptr; Gtk::MenuItem *m_menuitem_quit = nullptr; Gtk::MenuItem *m_menuitem_about = nullptr; Gtk::Toolbar *m_toolbar = nullptr; Gtk::ToolButton *m_toolbar_quit = nullptr; Gtk::Button *m_btn1 = nullptr; Gtk::Button *m_btn2 = nullptr; Gtk::Button *m_btn3 = nullptr; Gtk::Paned *m_paned1 = nullptr; Gtk::Paned *m_paned2 = nullptr; private: Glib::RefPtr<Gtk::Builder> m_builder; gchar *cstrInitPathFile; int nConf_MainWindow_posx; int nConf_MainWindow_posy; int nConf_MainWindow_width; int nConf_MainWindow_height; int nConf_Paned1_position; int nConf_Paned2_position; void set_AppIcon(); gchar * create_InitPath(); void load_InitDatas(); void save_InitDatas(); void setInit_display(); void on_hide_window() { save_InitDatas(); } void on_app_about(); }; #endif
● 今回作成した MainWindow.cc
#include "MainWindow.h" using namespace std; extern Glib::RefPtr<Gtk::Builder> refBuilder; void MainWindow::setInit_display() { cstrInitPathFile = create_InitPath(); load_InitDatas(); // get menu widget refBuilder->get_widget("menuBar", m_menu); refBuilder->get_widget("menu_quit", m_menuitem_quit); refBuilder->get_widget("menu_about", m_menuitem_about); // get toolbar widget refBuilder->get_widget("toolBar", m_toolbar); refBuilder->get_widget("toolbar_quit", m_toolbar_quit); // get widget refBuilder->get_widget("btn1", m_btn1); refBuilder->get_widget("btn2", m_btn2); refBuilder->get_widget("btn3", m_btn3); refBuilder->get_widget("paned1", m_paned1); refBuilder->get_widget("paned2", m_paned2); // connect signals // menu signals m_menuitem_quit->signal_activate().connect( sigc::mem_fun(*this, &MainWindow::on_btn1_clicked)); m_menuitem_about->signal_activate().connect( sigc::mem_fun(*this, &MainWindow::on_app_about)); // toolbar signals m_toolbar_quit->signal_clicked().connect( sigc::mem_fun(*this, &MainWindow::on_btn1_clicked)); // button signals m_btn1->signal_clicked().connect( sigc::mem_fun(*this, &MainWindow::on_btn1_clicked)); m_btn2->signal_clicked().connect( sigc::mem_fun(*this, &MainWindow::on_btn2_clicked)); m_btn3->signal_clicked().connect( sigc::mem_fun(*this, &MainWindow::on_btn3_clicked)); // hide signal this->signal_hide().connect( sigc::mem_fun(*this, &MainWindow::on_hide_window)); // set window titles & sizes set_title("test menu"); if (nConf_MainWindow_posx != -1*G_MAXINT && nConf_MainWindow_posy != -1*G_MAXINT) move(nConf_MainWindow_posx, nConf_MainWindow_posy);; set_default_size(nConf_MainWindow_width, nConf_MainWindow_height); //resize(nConf_MainWindow_width, nConf_MainWindow_height); // set paned position m_paned1->set_position(nConf_Paned1_position); m_paned2->set_position(nConf_Paned2_position); // set application icon set_AppIcon(); } /************************************************* ini functions *************************************************/ // set application icon void MainWindow::set_AppIcon() { std::string appname = Glib::get_application_name(); if ( Glib::file_test( ORG_APPICON, Glib::FILE_TEST_EXISTS )) { this->set_icon_from_file( ORG_APPICON ); return; } if ( Glib::file_test( appname+".png", Glib::FILE_TEST_EXISTS )) { this->set_icon_from_file( appname+".png" ); return; } std::vector<std::string> list_dirs = Glib::get_system_data_dirs(); for (string dir : list_dirs){ for (int ni=0; ni < 2; ni++){ string choice_file; if (ni==0) // set original name choice_file = Glib::build_filename( dir, "icons", ORG_APPICON); else // set applcation name choice_file = Glib::build_filename( dir, "icons", appname+".png" ); if ( Glib::file_test( choice_file, Glib::FILE_TEST_EXISTS )) { this->set_icon_from_file( choice_file ); break; } } } } // create ini-file pathfilename gchar * MainWindow::create_InitPath() { cstrInitPathFile = NULL; //g_autoptr(GError) error = NULL; GError *error = nullptr; // get application name const gchar *app_name; app_name = g_get_application_name(); if (!app_name) app_name = g_get_prgname(); // get config directory const gchar *user_config_dir = g_get_user_config_dir(); gchar *pathfile = g_build_filename(user_config_dir, app_name, CONF_FILE, NULL); if (g_file_test(pathfile, G_FILE_TEST_EXISTS)) { return pathfile; } // check exists derectory if (!g_file_test(g_build_filename(user_config_dir, app_name, NULL), G_FILE_TEST_EXISTS)) { // create directory GFile *file = g_file_new_build_filename(user_config_dir, app_name,NULL); if (!g_file_make_directory(file, NULL, &error)){ std::cout << "Error make application config directory :" << error->message << std::endl; g_clear_error(&error); return NULL; } } return pathfile; } // load ini-file void MainWindow::load_InitDatas() { // defalts nConf_MainWindow_posx=-1*G_MAXINT; nConf_MainWindow_posy=-1*G_MAXINT; nConf_MainWindow_width = 400; nConf_MainWindow_height = 300; nConf_Paned1_position = 150; nConf_Paned2_position = 50; if (cstrInitPathFile == NULL) return; // exists check key file if (!g_file_test(cstrInitPathFile, G_FILE_TEST_EXISTS)) return; //g_autoptr(GError) error = NULL; GError *error = nullptr; g_autoptr(GKeyFile) key_file = g_key_file_new (); if (!g_key_file_load_from_file (key_file, cstrInitPathFile, G_KEY_FILE_KEEP_COMMENTS, &error)) { if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) std::cout << "Error loading key file :" << error->message << std::endl; else std::cout << "Error loading key file :" << error->code << std::endl; g_clear_error(&error); g_key_file_free(key_file); return; } int nvalue; // main window error = NULL; nvalue = g_key_file_get_integer(key_file, "MAINWINDOW", "window_posx", &error); if (error == NULL) nConf_MainWindow_posx = nvalue; else g_clear_error(&error); error = NULL; nvalue = g_key_file_get_integer(key_file, "MAINWINDOW", "window_posy", &error); if (error == NULL) nConf_MainWindow_posy = nvalue; else g_clear_error(&error); error = NULL; nvalue = g_key_file_get_integer(key_file, "MAINWINDOW", "window_width", &error); if (error == NULL) nConf_MainWindow_width = nvalue; else g_clear_error(&error); error = NULL; nvalue = g_key_file_get_integer(key_file, "MAINWINDOW", "window_height", &error); if (error == NULL) nConf_MainWindow_height = nvalue; else g_clear_error(&error); // paned1 error = NULL; nvalue = g_key_file_get_integer(key_file, "MAINWINDOW", "paned1_divider_position", &error); if (error == NULL) nConf_Paned1_position = nvalue; else g_clear_error(&error); // paned2 error = NULL; nvalue = g_key_file_get_integer(key_file, "MAINWINDOW", "paned2_divider_position", &error); if (error == NULL) nConf_Paned2_position = nvalue; else g_clear_error(&error); g_key_file_free(key_file); } void MainWindow::save_InitDatas() { if (cstrInitPathFile == NULL) return; // get application position & size Gdk::Rectangle rect; get_window()->get_frame_extents(rect); int int_val_mw_posx = rect.get_x(); int int_val_mw_posy = rect.get_y(); int int_val_mw_width = 0; int int_val_mw_height = 0; get_size(int_val_mw_width, int_val_mw_height); // get paneds position gint int_val_paned1 = m_paned1->get_position(); gint int_val_paned2 = m_paned2->get_position(); // set key values GError *error = nullptr; g_autoptr(GKeyFile) key_file = g_key_file_new (); g_key_file_set_integer(key_file, "MAINWINDOW", "window_posx", int_val_mw_posx); g_key_file_set_integer(key_file, "MAINWINDOW", "window_posy", int_val_mw_posy); g_key_file_set_integer(key_file, "MAINWINDOW", "window_width", int_val_mw_width); g_key_file_set_integer(key_file, "MAINWINDOW", "window_height", int_val_mw_height); g_key_file_set_integer(key_file, "MAINWINDOW", "paned1_divider_position", int_val_paned1); g_key_file_set_integer(key_file, "MAINWINDOW", "paned2_divider_position", int_val_paned2); // write key file if (!g_key_file_save_to_file(key_file, cstrInitPathFile, &error)){ std::cout << "Error saving key file :" << error->message << std::endl; g_clear_error(&error); return; } g_key_file_free(key_file); } /************************************************* events *************************************************/ // btn1(close) event void MainWindow::on_btn1_clicked() { // confirm close Gtk::MessageDialog dialog(*this, "close this window ?", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_OK_CANCEL); dialog.set_title( "close this window" ); dialog.set_default_response(Gtk::RESPONSE_OK); if (dialog.run()==Gtk::RESPONSE_CANCEL) return; hide(); } void MainWindow::on_btn2_clicked() { if (m_menu->is_visible()){ m_menu->hide(); m_btn2->set_label("click to show menu-bar"); } else{ m_menu->show(); m_btn2->set_label("click to hide menu-bar"); } } void MainWindow::on_btn3_clicked() { if (m_toolbar->is_visible()){ m_toolbar->hide(); m_btn3->set_label("click to show toolbarr"); } else{ m_toolbar->show(); m_btn3->set_label("click to hide toolbar"); } } /************************************************* window or dialog *************************************************/ void MainWindow::on_app_about() { APP_AboutDialog *about_dialog = nullptr; refBuilder->get_widget_derived("aboutDialog", about_dialog); about_dialog->set_transient_for(*this); about_dialog->show_all(); }
● 今回作成した paned_test.glade
<?xml version="1.0" encoding="UTF-8"?> <!-- Generated with glade 3.22.1 --> <interface> <requires lib="gtk+" version="3.20"/> <object class="GtkAboutDialog" id="aboutDialog"> <property name="name">aboutDialog</property> <property name="can_focus">False</property> <property name="window_position">center</property> <property name="destroy_with_parent">True</property> <property name="type_hint">dialog</property> <property name="skip_taskbar_hint">True</property> <property name="program_name">paned_test</property> <property name="version">0.0.0</property> <property name="copyright" translatable="yes">Copyright © 2018- retireSaki All rights reserved.</property> <property name="comments" translatable="yes">test program</property> <property name="website">https://retiresaki.hatenablog.com/</property> <property name="authors">retireSaki</property> <property name="documenters">retireSaki</property> <property name="logo">test_about.svg</property> <property name="license_type">gpl-3-0</property> <child> <placeholder/> </child> <child internal-child="vbox"> <object class="GtkBox"> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="spacing">2</property> <child internal-child="action_area"> <object class="GtkButtonBox"> <property name="can_focus">False</property> <property name="layout_style">end</property> <child> <placeholder/> </child> <child> <placeholder/> </child> </object> <packing> <property name="expand">False</property> <property name="fill">False</property> <property name="position">0</property> </packing> </child> <child> <placeholder/> </child> </object> </child> </object> <object class="GtkApplicationWindow" id="mainWindow"> <property name="name">mainWindow</property> <property name="can_focus">False</property> <child> <placeholder/> </child> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <child> <object class="GtkMenuBar" id="menuBar"> <property name="name">menuBar</property> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">ファイル(_F)</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-new</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-open</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-save</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-save-as</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkSeparatorMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> </object> </child> <child> <object class="GtkImageMenuItem" id="menu_quit"> <property name="label">gtk-quit</property> <property name="name">menu_quit</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">編集(_E)</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-cut</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-copy</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-paste</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> <child> <object class="GtkImageMenuItem"> <property name="label">gtk-delete</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">表示(_V)</property> <property name="use_underline">True</property> </object> </child> <child> <object class="GtkMenuItem"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">ヘルプ(_H)</property> <property name="use_underline">True</property> <child type="submenu"> <object class="GtkMenu"> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkImageMenuItem" id="menu_about"> <property name="label">gtk-about</property> <property name="name">menu_about</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="use_underline">True</property> <property name="use_stock">True</property> </object> </child> </object> </child> </object> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkToolbar" id="toolBar"> <property name="name">toolBar</property> <property name="visible">True</property> <property name="can_focus">False</property> <child> <object class="GtkToolButton" id="toolbar_quit"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="tooltip_text" translatable="yes">Exit this application</property> <property name="label" translatable="yes">Exit</property> <property name="use_underline">True</property> <property name="stock_id">gtk-quit</property> </object> <packing> <property name="expand">False</property> <property name="homogeneous">True</property> </packing> </child> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkPaned" id="paned1"> <property name="name">paned1</property> <property name="visible">True</property> <property name="can_focus">True</property> <child> <object class="GtkPaned" id="paned2"> <property name="name">paned2</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="orientation">vertical</property> <child> <object class="GtkButton" id="btn1"> <property name="label" translatable="yes">quit</property> <property name="name">btn1</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="resize">False</property> <property name="shrink">True</property> </packing> </child> <child> <object class="GtkButton" id="btn2"> <property name="label" translatable="yes">hide menubar</property> <property name="name">btn2</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="resize">True</property> <property name="shrink">True</property> </packing> </child> </object> <packing> <property name="resize">True</property> <property name="shrink">True</property> </packing> </child> <child> <object class="GtkBox"> <property name="visible">True</property> <property name="can_focus">False</property> <property name="orientation">vertical</property> <property name="homogeneous">True</property> <child> <object class="GtkButton" id="btn3"> <property name="label" translatable="yes">hide toolbar</property> <property name="name">btn3</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">0</property> </packing> </child> <child> <object class="GtkButton" id="btn4"> <property name="label" translatable="yes">4</property> <property name="name">btn4</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">1</property> </packing> </child> <child> <object class="GtkButton" id="btn5"> <property name="label" translatable="yes">5</property> <property name="name">btn5</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">True</property> </object> <packing> <property name="expand">False</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> </object> <packing> <property name="resize">True</property> <property name="shrink">True</property> </packing> </child> </object> <packing> <property name="expand">True</property> <property name="fill">True</property> <property name="position">2</property> </packing> </child> </object> </child> </object> </interface>
● ソースコードのダウンロード
- 作者: ToshioCP
- 発売日: 2017/06/06
- メディア: Kindle版
- この商品を含むブログを見る
GTK+とGladeで作るLinuxプログラミング超入門―かっこいいアプリを自分で作ろう! (CompuBooks)
- 作者: 鈴木哲哉
- 出版社/メーカー: すばる舎
- 発売日: 2000/06
- メディア: 単行本
- クリック: 25回
- この商品を含むブログ (1件) を見る