Glade環境を使用したGTK + / gtkmmアプリケーションの構築

この投稿は、記事「Glade環境を使用したGTK +アプリケーションの作成」に追加されます。 私がそれを読み始めて、例がC ++であるという言葉につまずいたとき、私は事前に喜んでいました、その時、Gladeとgtkmm-GTK +のラッパーC ++ライブラリのリンクの例を探していたからです。 著者が、私には知られていない理由で、GTK + APIを使用するCコードが「.cpp」ファイルに入れて、C ++の例を呼び出したことが判明したときの失望を想像してください。 その結果、C ++の記事からシステム例を独立して変換することにしました。 結果は読者に提示されます。



読者はGTK +ライブラリの基本概念に精通していることを前提としています。 また、この記事では繰り返さないので、読む前に、元の記事の内容を読むことをお勧めします。



コンポーネントのインストール



C ++を使用するには、GTK +ライブラリのラッパーであるgtkmmライブラリが必要です。 インストール中に、それ自体が依存関係をプルします。たとえば、cairommライブラリも必要になります。cairommライブラリは、たとえばcairoライブラリのC ++ラッパーです(2Dグラフィックのレンダリング)。 Debianベースのディストリビューションの場合、インストールは次のコマンドで実行されます。

sudo apt-get install libgtkmm-2.4-dev
      
      





バージョン番号は、ディストリビューションによって異なる場合があります。



ソースコード



以下は、プログラムの完全なソースコードです。機能面では、元の例と完全に一致していますが、C ++で記述されています。 次に、コードの一部を個別に説明します。



 #include <gtkmm.h> #include <cairomm/cairomm.h> /** Main window class. */ class MainWindow: public Gtk::Window { private: /** Subclass for drawing area. */ class CDrawingArea: public Gtk::DrawingArea { public: typedef enum { SHAPE_RECTANGLE, SHAPE_ELLIPSE, SHAPE_TRIANGLE } shape_t; private: shape_t _curShape = SHAPE_RECTANGLE; /** Drawing event handler. */ virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { switch (_curShape) { case SHAPE_RECTANGLE: cr->rectangle(20, 20, 200, 100); cr->set_source_rgb(0, 0.8, 0); cr->fill_preserve(); break; case SHAPE_ELLIPSE: cr->arc(150, 100, 90, 0, 2 * 3.14); cr->set_source_rgb(0.8, 0, 0); cr->fill_preserve(); break; case SHAPE_TRIANGLE: cr->move_to(40, 40); cr->line_to(200, 40); cr->line_to(120, 160); cr->line_to(40, 40); cr->set_source_rgb(0.8, 0, 0.8); cr->fill_preserve(); cr->set_line_cap(Cairo::LINE_CAP_ROUND); cr->set_line_join(Cairo::LINE_JOIN_ROUND); break; } cr->set_line_width(3); cr->set_source_rgb(0, 0, 0); cr->stroke(); return true; } public: CDrawingArea(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder): Gtk::DrawingArea(cobject) { } void SetShape(shape_t shape) { if (_curShape != shape) { _curShape = shape; /* Request re-drawing. */ queue_draw(); } } }; Glib::RefPtr<Gtk::Builder> _builder; Gtk::RadioButton *_rbRect, *_rbEllipse, *_rbTriangle; CDrawingArea *_drawingArea; public: /** Signal handler which is called when any radio button is clicked. */ void OnRadiobuttonClick() { if (_rbRect->get_active()) { _drawingArea->SetShape(CDrawingArea::SHAPE_RECTANGLE); } else if (_rbEllipse->get_active()) { _drawingArea->SetShape(CDrawingArea::SHAPE_ELLIPSE); } else if (_rbTriangle->get_active()) { _drawingArea->SetShape(CDrawingArea::SHAPE_TRIANGLE); } } /** "quit" action handler. */ void OnQuit() { hide(); } MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder): Gtk::Window(cobject), _builder(builder) { /* Retrieve all widgets. */ _builder->get_widget("rbRectangle", _rbRect); _builder->get_widget("rbEllipse", _rbEllipse); _builder->get_widget("rbTriangle", _rbTriangle); _builder->get_widget_derived("drawing_area", _drawingArea); /* Connect signals. */ _rbRect->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnRadiobuttonClick)); _rbEllipse->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnRadiobuttonClick)); _rbTriangle->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnRadiobuttonClick)); /* Actions. */ Glib::RefPtr<Gtk::Action>::cast_dynamic(_builder->get_object("action_quit"))-> signal_activate().connect(sigc::mem_fun(*this, &MainWindow::OnQuit)); } }; int main(int argc, char **argv) { Gtk::Main app(argc, argv); Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("sample.glade"); MainWindow *mainWindow = 0; builder->get_widget_derived("main_wnd", mainWindow); app.run(*mainWindow); delete mainWindow; return 0; }
      
      







すべては、クラス「Gtk :: Main」のオブジェクトを作成することにより、ライブラリの初期化から始まります。 次に、ビルダーオブジェクトが作成されます。このオブジェクトは、Gladeエディターが受け取ったグラフィカルインターフェイスの説明を含むファイルによって初期化されます(元の例を参照)。

 Gtk::Main app(argc, argv); Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("sample.glade");
      
      





Glib :: RefPtrクラスの使用に注意してください。 これは、glibmmライブラリでのスマートポインタの実装です。低レベルglibライブラリのC ++ラッパーです。 このオブジェクトに割り当てられたポインターは、オブジェクトが破棄されると自動的に解放されます。



 class MainWindow: public Gtk::Window
      
      





アプリケーションのメインウィンドウを表すために、gtkmmの標準ウィンドウクラス「Gtk :: Window」から継承される独自のクラスを使用します。 この手法はサブクラス化と呼ばれ、特に、以下に示すウィジェットのイベントをインターセプトする1つの方法です。



 MainWindow *mainWindow = 0; builder->get_widget_derived("main_wnd", mainWindow);
      
      







ここでは、ビルダーの説明に従って、メインウィンドウのオブジェクトを作成します。 サブクラス化を使用してオブジェクトを取得するには、get_widget_derivedメソッドが呼び出されます。 標準クラスを使用する場合(この場合は「Gtk :: Window」)、ビルダーのget_widgetメソッドを使用する必要があります。



 app.run(*mainWindow); delete mainWindow;
      
      





runメソッドは、動作するウィンドウオブジェクトへの引数を取り、非表示になった後にのみ制御を返します。 メモリリークを回避するには、ウィンドウオブジェクトを削除する必要があることに注意してください。 この要件はトップレベルのウィジェットにのみ適用され、埋め込みウィジェットには適用されません(たとえば、メインウィンドウ内のすべてのウィジェットには適用されません。メインウィンドウは、同じメソッドで受信されますが、明示的に削除されません)。



それでは、メインウィンドウクラスに移りましょう。 すべてのウィジェットのコンストラクターには、常に1つのプロトタイプがあります。

 MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& builder): Gtk::Window(cobject), _builder(builder)
      
      





最初の引数は、元のGTK +オブジェクトへのポインターです。タイプ「BaseObjectType」は、すべてのgtkmmクラスに対して常にこのように定義されます(この場合、GtkWindowになります)。 基本クラスのコンストラクターに渡す必要があります。 2番目の引数はビルダーオブジェクトです。これは、特に、上記で説明した方法で埋め込みウィジェットのオブジェクトを取得するために使用できます。

 _builder->get_widget("rbRectangle", _rbRect); _builder->get_widget("rbEllipse", _rbEllipse); _builder->get_widget("rbTriangle", _rbTriangle); _builder->get_widget_derived("drawing_area", _drawingArea);
      
      







さらに、ラジオボタンをクリックするイベントのシグナルは、クラスの「OnRadiobuttonClick」メソッドに接続されます。

 _rbRect->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnRadiobuttonClick)); _rbEllipse->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnRadiobuttonClick)); _rbTriangle->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnRadiobuttonClick));
      
      





gtkmmでシグナルを切り替えるためのメインフレームワークであるsigc ++ライブラリのsigc :: mem_funメソッドの使用に注意してください。 このメソッドは、クラスメソッドのファンクターを返します。 クラスのメンバーではない関数を使用する必要がある場合は、sigc :: ptr_funメソッドを使用できます。 説明したシグナルをハンドラーにバインドする方法は、radiobuttsの場合のように、サブクラス化が使用されていないウィジェットの唯一の方法です。



次の3階建ての構造は、プログラムを終了するためのアクティベーション信号をクラスのOnQuitメソッドに添付します。

 Glib::RefPtr<Gtk::Action>::cast_dynamic(_builder->get_object("action_quit"))-> signal_activate().connect(sigc::mem_fun(*this, &MainWindow::OnQuit));
      
      





この場合、Gladeでは、action_quitが作成されていることを確認する必要があります。これは、メインメニューのQuit要素が参照するものです。 元の記事では、アクションの瞬間は省略されていたので、コメントします。 GTK +のアクションは、実際には、さまざまなソース(メニュー項目、ツールバーボタン、ホットキー)からのイベントに対して実行できるアクションと呼ばれます。 アクションオブジェクトは、その外部表現(メニューやツールバーなど)の一般的な属性(ラベル、アイコン、ツールチップテキスト)も記述します。 gtkmmのアクションは、クラス「Gtk :: Action」に対応しています。 ビルダーから取得するには、基本クラスGlib :: Objectのオブジェクトを返すget_objectメソッドを使用する必要があるため、明示的な型変換にはGlib :: RefPtrクラスのcast_dynamicメソッドも使用する必要があります。 OnQuitメソッド自体は非常に簡単です。

 void OnQuit() { hide(); }
      
      





前述のように、「main」関数の「run」メソッドを終了するには、引数として渡されたウィンドウを非表示にするだけで十分です。これは、このメソッドの本体で行われます。



次に興味深い点は、「Gtk :: DrawingArea」クラスのサブクラスです。このクラスは、対応するウィジェットでの図形のレンダリングを実装します。 新機能のうち、on_drawメソッドがあります。

 virtual bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
      
      





これは、イベントのシグナルをインターセプトする別の方法の例であり、サブクラス化を使用するウィジェットにのみ適用されます。 その本質は、gtkmmのウィジェットの各クラスで、ウィジェットによってサポートされる各信号に対して仮想メソッドが定義され、対応する信号が受信されたときに呼び出されることです。 サブクラスは、目的の仮想メソッドをオーバーライドして、目的の信号の処理をインターセプトできます。これは、この例で行われます。



具体的には、このメソッドは、ウィジェットのコンテンツを再描画するイベントを処理します。 引数として、cairommライブラリのレンダリングコンテキストが彼に渡されます。この作業は、元の例と完全に類似しています。



この投稿は終了しました。 上記のライブラリの使用に関する情報のほとんどは、ライブラリ自体の自己文書化されたソースコードから取得されます。



All Articles