GTKmm (3.0) と glade によるアプリ (4) - メニューバーの表示と表示切り替え
今回は、前回の"GTKmm (3.0) と glade によるアプリ (2) - メニューバーの表示と表示切り替え"で作成したプログラムをベースに、
(1) メニューバーの表示
(2) メニューバーの終了をフック
(3) ボタンクリックによるメニューの表示/非表示の切り替え機能
の3つの機能を付けます。
実際に動作させたときの画像です。
メニューバーの処理に関しては、アプリケーションの終了だけをフックしました。メニューの終了は、quit ボタンのクリック処理する関数をしようしました。
ここで ボタン2 をクリックするとメニューが非表示、さらにクリックするとメニューバーが表示されます。
左側がメニュー非表示
右側がメニュー表示
修正したソースは、MainWindow.cc と MainWindow.h だけです。
今回は先にソースから
作成した 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> #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(); Gtk::MenuBar *m_menu = nullptr; Gtk::MenuItem *m_menuitem_quit = nullptr; Gtk::Button *m_btn1 = nullptr; Gtk::Button *m_btn2 = 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; gchar * create_InitPath(); void load_InitDatas(); void save_InitDatas(); void setInit_display(); void on_hide_window() { save_InitDatas(); std::cout << "hide" << std::endl; } }; #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); // get widget refBuilder->get_widget("btn1", m_btn1); refBuilder->get_widget("btn2", m_btn2); 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)); // 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)); 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); } /************************************************* ini functions *************************************************/ // 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(GError) error = NULL; 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"); } }
1) メニューバーの表示
メニューバーは glade で追加します。
コンテナーの GtkMenuBar を追加しますが、GtkBoxを先に設置してから GtkMenuBar を貼り付けます。
今回は、menuBar という名称にしました。
さらに メニューバーのファイルから終了を選択し、menu_quit と名称に。
単にメニューバーを表示するだけなら glade の編集だけですみますが、これだけでは意味がありません。
そこで、終了のイベントをフックします。
2) メニューバーの終了のイベントをフック
まず、
refBuilder->get_widget()
を使って、menuBar および menu_quit を Gtk::Builder から取得。
メニューのイベントは
signal_activate()
を使います。
menu_quitメンバーから signal_activate を使い、btn1 のクリック処理関数を呼び出します。
m_menuitem_quit->signal_activate().connect(
sigc::mem_fun(*this, &MainWindow::on_btn1_clicked));
これで終了のイベントが呼び出せるようになります。
3) メニューバーの表示・非表示できるようにする
btn2 のクリックイベントの処理を定義します。
m_btn2->signal_clicked().connect(
sigc::mem_fun(*this, &MainWindow::on_btn2_clicked));
次に on_btn2_clicked 内の処理を作成。
(3.1) メニューバーが visible なら
menuBar を hide() 関数を使って非表示にし、
判りやすいように、btn2 のラベルを "click to show menu-bar" に。
(3.2) メニューバーが visible でないなら
menuBar を show() 関数を使って表示し、
判りやすいように、btn2 のラベルを "click to hide menu-bar" に。
以上で、今回の機能追加はできました。
最後に、全てのファイルを圧縮したファイル(zip)を載せます。
ソース一式
すべてのファイル(zip)をダウンロードする
www.mediafire.com
簡単でしたね!
基本的に Qt とさほど変わりません。
glade の作業で気づかれた方も多いと思いますが、デザイン上Qtとはメニューバーの取り扱い方が若干違っていますので、気をつけてください。
- 作者: ToshioCP
- 発売日: 2017/06/06
- メディア: Kindle版
- この商品を含むブログを見る