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

この投稿は、クロスプラットフォームのGTK +ライブラリを使用してアプリケーションを作成することに専念しています。 主に初心者に焦点を当てていますか? したがって、いくつかのことは非常にシンプルで平凡であるように思えるかもしれませんが、すべてができるだけ明確になるように、すべてをできるだけ詳細に説明しようとしました。

このライブラリの大きな利点は、無料で商用利用できることです。 インターネット上でGTK +を操作するためのドキュメントや本当に質の高い記事はあまりありません。 多くの例では、プログラムインターフェイスは「ペン」で記述されていますが、これは非常に不便な場合があります。 私自身もこれに出くわし、多くの場合、フォーム(コンテナ)にウィジェット(オブジェクト)を正しく配置し、タスクの解決に集中していませんでした。

GladeビジュアルGUIアプリケーションを使用してGTK +のインターフェイスをすばやく作成し、プログラムに統合する方法を示します。 Gladeはコンパイラでもデバッガでもありません。 インターフェイスを記述し、GladeXML XML形式ファイルで表示することのみが許可されます。

GTK +ライブラリの基本的なインターフェイスはCです。しかし、この例ではC ++を使用します。 したがって、小さな機能が表示されますが、これについて説明します。 LinuxディストリビューションUbuntu 10.04を使用しています。

タスクは次のようになります:キャンバス、サイドメニュー(キャンバスに描画するものを選択する)、メインメニュー、ステータスバーで構成される小さなアプリケーションを作成します。 同時に、アプリケーションウィンドウ全体のサイズを変更する場合、サイドメニューとキャンバスのサイズを一定に保つ必要があります。 ただし、キャンバスが配置されているコンテナは、メインウィンドウのサイズの増減に応じてサイズを変更できます。 必要に応じて、スクロールバーが表示されます。

計画は次のとおりです。

Glade3をインストールして起動する


GTK + devパッケージが既にインストールされていることが前提です。インストールされていない場合は、コンソールからこれを実行できます。
sudo aptitude install libgtk2.0-dev 

Gladeは、Ubuntu Update Centerから、またはコンソールを使用して再度インストールできます。
 sudo apt-get install glade-gnome 

インストール後、アプリケーション-プログラミング-Glade Interface Designerを実行します
図に示すように、すべてのパラメーターを設定します。 バージョンツールキットバージョン選択2.16

画像

左側には、さまざまなウィジェットのセットがあるウィンドウがあります。 デルファイの開発Windowsフォームで働いている人、または環境に!はすぐにソートされました。 右側には2つのメニューがあります。1つはウィジェットの階層を表示し、2つ目のウィンドウはウィジェットのプロパティウィンドウを表示します。

GUI作成


GTK +アプリケーションのグラフィカルインターフェイスの作成は、メインフォーム(プログラムのメインウィンドウ)の設定から始まります。 ウィンドウウィジェットは、左メニューの[トップレベル]セクションにあります。

[プロパティ]ウィンドウの右側で、このウィジェットのプロパティを設定します。
名前:topWindow
Windowsの位置: 中央
デフォルトの幅: 500
デフォルトの高さ: 320

画像

Signalsタブ(signal、event)に移動し、GtkObjectがdestroyを探し、Handler列(handler)にtopWindow_destroy_cbを書き込むか、リストから選択します。 メインフォームの閉鎖 - これは、破壊するために信号を処理するプロシージャの名前になります。

画像

さらに、アプリケーションには、メインメニュー、メイン機能部分(これはキャンバスと描画対象を選択するためのメニューです)、およびステータスバーがあるはずです。 [コンテナ]セクションの左側のメニューにある[垂直ボックス]ウィジェットコンテナをメインフォームに配置します。 表示されるダイアログで、アイテム数:3を選択します。これは、作成するコンテナに3つのウィジェットを配置できることを意味します。

vbox1コンテナには3つのいわゆるセルまたはコンパートメントがあります。 2番目の(中央)コンパートメントに、Frame(ウィジェットメニューの[コンテナ]セクション)を配置します。 右側のウィジェットツリーを見てください。 - 彼らは削除することができalignment1とLABEL1:フレーム1作成したウィジェットの中に2 vizhdetaになります。 これについて少し逸脱して、理論に戻ります。

GTK +でウィジェットのサイズを管理する方法を理解することは、適切で効率的なグラフィカルインターフェイスを作成するために非常に重要です。 このプロセスは、多くの場合、二つの成分(フェーズ2)からなるマッチング処理と呼ばれ、要求されたサイズの解像度が割り当てられます。

「あなたはどのくらいのスペースが必要なのでしょうか?」:お問い合わせのステップは、再帰的な質問です。 メインウィンドウは子ウィンドウに設定し、子ウィンドウは子ウィンドウに設定するため、この階層全体のすべてのウィジェットが応答するまでです。

2つの重要なポイントがあります。
  1. 子ウィジェットは親ウィジェットのサイズについて何も知りません
  2. 親ウィジェットのサイズは、子ウィジェットのサイズに依存します

メインウィンドウが理想的にどのくらいのスペースが必要であるかを知ったので、実際にどのくらいのスペースが利用可能になるかについて決定が下されます。 妥当な値がリクエストに含まれている場合、それがデフォルトです。 ただし、ウィンドウサイズが手動で設定されている場合(たとえば、gtk_window_setdefault_sizeを使用)、またはそうでない場合、ウィンドウは要求されたサイズを破棄し、別のサイズを設定します。

2番目の段階(サイズの割り当て)で、親ウィジェットから子ウィジェットへのコマンドが発生します:「ここにスペースがあります。それに合わせてすべてを行います。」 ウィジェットに複数の子ウィジェットがある場合、このステップのタスクは、子ウィジェット間で空きスペースを適切に分割することです。

次に、アプリケーションの主要部分に進みます。 私たちは、ウィジェットメニューに入り、コンテナセクションに水平ペインを選択し、我々はフレーム1の上に置きます。 左側は固定サイズである必要があり、右側は固定サイズではありません。 繰り返しますが、ウィジェットメニューに移動し、そこでスクロールウィンドウを探します。 最初に1つ、次に2番目のスクロールウィンドウを左右の区画hpand1(水平ペイン)に配置します。 scrolledwindow1と呼ばれる左側のScrolled Windowで、プロパティ(Commonタブで)Width reguestを145に設定します-これは、要求されたサイズ(マッチングプロセス用)を意味します。 scrolledwindow1のResizeプロパティがPackingタブでNoあり 、scrolledwindow2 Yesであることも確認する必要があります。
Containersセクションから、最初に最初のViewPortウィジェットを配置し、次にscrolledwindow1とscrolledwindow2の両方にそれぞれ2番目のウィジェットを配置します。

画像

サイドメニューを見てみましょう。 3つのコンパートメントを持つViewPort1垂直ボックスに追加します。 各コンパートメントにラジオボタンを追加します。 各ラジオボタンは、プロパティがありませんを展開して設定するので、彼らは親ウィジェットのサイズを増やすことで伸びていません。 また、共通]タブで、あなたは、彼らがデフォルトの代わりに、私たちは与えるように大きさのものであろう幅と高さの要求を設定することができます。 ただし、いずれにしてもサイズは異なります。 [全般]タブでプロパティを変更します。
それぞれrbutRectanglerbutEllipserbutTriangleの名前
それぞれRectangleEllipseTriangleにラベルを付けます
また、rbutEllipseおよびrbutTriangleの場合、特別なダイアログを使用してGroupプロパティrbutRectangleで指定します。

画像

次のようになります。

画像

次に、各ラジオボタンのイベントを登録する必要があります。 [シグナル]タブでは、GroupChangedイベントとトグル(どちらでもかまいません)のどちらでもかまいません。rbutton_toggled_cbハンドラーを記述します。

画像

次に、ウィンドウの右側に目を向けます。 2つのコンパートメントを持つ垂直ボックスをViewPort2に追加します。 上部に通常のラベルを配置し、下部の描画領域にキャンバスを配置します。 Label1の場合、labelプロパティに300 x 200 Canvasを記述します。 [パッキング]タブに移動し、[展開]を[ いいえ ]に設定します。
今、私たちのキャンバス。
名前: drawingarea
支出: いいえ
幅リクエスト: 300
高さリクエスト: 200
イベント: 露出を確認

[Signals]で、expose-eventを探し、リストから書き込むか選択します。
drawingarea_expose_event_cb

画像

次に、ステータスバー(一番下のコンパートメント)とメインメニュー(一番上のコンパートメント)を追加する必要があります。 メニューバー(ウィジェットメニューの[コンテナ]セクション)を最上部に配置し、ステータスバーの最下部のコンパートメント(ウィジェットメニューの[コントロールと表示]セクション)に、追加に関するダイアログが表示されます。[アイテム数:1]を選択します。

画像

この例のmenubar1では、メニュー項目を1つだけ残します-プログラムを終了します。 したがって、あなたが削除することができます。menuitem2、menuitem3、menuitem4を。 その後、我々はmenuitem1を明らかにし、中に入ると、すべてを削除してもそうimagemenuitem5 MENU1。 これはQuitアイテムです。 これをクリックして、プロパティウィンドウの[全般]タブのプロパティ、Stock Itemプロパティを見ることができます。このプロパティにはgtk-quitが登録されています。 そこで「遊ぶ」ことができます。 通常、カスタムラベルと画像を選択し、すべてを自分で設定できます。 これはそれほど重要ではありません。 imagemenuitem5の場合、Signalsタブで、フォームを閉じる場合とまったく同じように( topWindow_destroy_cb )信号のアクティベート信号(メニュー項目をクリック)を設定します。

これが、インターフェースが最終的にどのように見えるかです。 mainFormという名前でプロジェクトを保存します。 ファイルはmainForm.gladeという名前になります

画像

プログラムのコード


Example1.cppあなたがmainForm.gladeを保存した同じフォルダにファイルを作成します。 最初にコード全体を説明し、次にいくつかの重要なポイントを説明します。

 /* Example1.cpp */ #include <cairo.h> #include <gtk/gtk.h> #define UI_FILE "mainForm.glade" //   GtkBuilder *builder; GtkWidget *topWindow; GtkRadioButton *rbutRectangle, *rbutEllipse, *rbutTriangle; GtkDrawingArea *drawingarea; //    extern "C" void topWindow_destroy_cb (GtkObject *object, gpointer user_data); extern "C" gboolean drawingarea_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data); extern "C" void rbutton_toggled_cb (GtkObject *object); int main( int argc, char **argv ) { GError *error = NULL; //  GTK+ gtk_init( &argc, &argv ); //   GtkBuilder  builder = gtk_builder_new(); //     ,     Glade if( ! gtk_builder_add_from_file( builder, UI_FILE, &error ) ) { g_warning( "%s", error->message ); g_free( error ); return( 1 ); } //        GladeXML topWindow = GTK_WIDGET(gtk_builder_get_object(builder, "topWindow")); rbutRectangle = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutRectangle")); rbutEllipse = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutEllipse")); rbutTriangle = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutTriangle")); drawingarea = GTK_DRAWING_AREA(gtk_builder_get_object(builder, "drawingarea")); //       gtk_builder_connect_signals (builder, NULL); //   g_object_unref( G_OBJECT( builder ) ); //       gtk_widget_show( topWindow ); //     gtk_main(); return( 0 ); } //   void topWindow_destroy_cb (GtkObject *object, gpointer user_data) { //     gtk_main_quit(); } //   gboolean drawingarea_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_set_line_width (cr, 7); cairo_set_source_rgb (cr, 0, 0, 0); //     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutRectangle))) { //   cairo_rectangle (cr, 20, 20, 200, 100); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0, 0.8, 0); } //     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutEllipse))) { //   cairo_arc(cr, 150, 100, 90, 0, 2 * 3.14); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.8, 0, 0); } //     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutTriangle))) { //   cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_move_to (cr, 40, 40); cairo_line_to (cr, 200, 40); cairo_line_to (cr, 120, 160); cairo_line_to (cr, 40, 40); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.8, 0, 0.8); } cairo_fill(cr); cairo_destroy(cr); return FALSE; } void rbutton_toggled_cb (GtkObject *object) { //  drawingarea gtk_widget_queue_draw (GTK_WIDGET(drawingarea)); }/* Example1.cpp */ #include <cairo.h> #include <gtk/gtk.h> #define UI_FILE "mainForm.glade" //   GtkBuilder *builder; GtkWidget *topWindow; GtkRadioButton *rbutRectangle, *rbutEllipse, *rbutTriangle; GtkDrawingArea *drawingarea; //    extern "C" void topWindow_destroy_cb (GtkObject *object, gpointer user_data); extern "C" gboolean drawingarea_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data); extern "C" void rbutton_toggled_cb (GtkObject *object); int main( int argc, char **argv ) { GError *error = NULL; //  GTK+ gtk_init( &argc, &argv ); //   GtkBuilder  builder = gtk_builder_new(); //     ,     Glade if( ! gtk_builder_add_from_file( builder, UI_FILE, &error ) ) { g_warning( "%s", error->message ); g_free( error ); return( 1 ); } //        GladeXML topWindow = GTK_WIDGET(gtk_builder_get_object(builder, "topWindow")); rbutRectangle = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutRectangle")); rbutEllipse = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutEllipse")); rbutTriangle = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutTriangle")); drawingarea = GTK_DRAWING_AREA(gtk_builder_get_object(builder, "drawingarea")); //       gtk_builder_connect_signals (builder, NULL); //   g_object_unref( G_OBJECT( builder ) ); //       gtk_widget_show( topWindow ); //     gtk_main(); return( 0 ); } //   void topWindow_destroy_cb (GtkObject *object, gpointer user_data) { //     gtk_main_quit(); } //   gboolean drawingarea_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data) { cairo_t *cr; cr = gdk_cairo_create (widget->window); cairo_set_line_width (cr, 7); cairo_set_source_rgb (cr, 0, 0, 0); //     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutRectangle))) { //   cairo_rectangle (cr, 20, 20, 200, 100); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0, 0.8, 0); } //     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutEllipse))) { //   cairo_arc(cr, 150, 100, 90, 0, 2 * 3.14); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.8, 0, 0); } //     if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(rbutTriangle))) { //   cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_move_to (cr, 40, 40); cairo_line_to (cr, 200, 40); cairo_line_to (cr, 120, 160); cairo_line_to (cr, 40, 40); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.8, 0, 0.8); } cairo_fill(cr); cairo_destroy(cr); return FALSE; } void rbutton_toggled_cb (GtkObject *object) { //  drawingarea gtk_widget_queue_draw (GTK_WIDGET(drawingarea)); } 


まず、これらのオブジェクトを宣言します。 誰と我々は働きます。 次に、シグナルハンドラの登録を開始します。 なぜなら C ++で記述し、extern“ C”を使用して、外部関数によってtopWindow_destroy_cb、drawingarea_expose_event_cb、rbutton_toggled_cbを宣言し、Cのバインディング順序に従ってリンクする必要があることを示します。GtkBuilderにはGladeの記述からのすべてのオブジェクトへのリンクが含まれます。 gtk_builder_get_object関数は、GtkBuilder(この場合はビルダー)から対応する名前を持つオブジェクトへの参照を取得します。 gtk_builder_connect_signals関数を使用して、コード内のハンドラー関数をGladeXMLの対応するシグナルハンドラーに接続します。 これは自動的に行われます。 Gladeとコードの名前が一致することが重要です。 アプリケーションは正常にコンパイルされ、シグナルだけが処理されません。コンソールからプログラムを実行すると、そのようなシグナルのハンドラーを見つけることができないという警告が表示されます。

また、 C ++で記述する場合、明示的な型変換を使用する必要が非常に多くあります。 例えば
 rbutRectangle = GTK_RADIO_BUTTON(gtk_builder_get_object(builder, "rbutRectangle")); 


Cで記述した場合、GTK_RADIO_BUTTONの明示的なゴーストなしで実行できます。

プログラムをコンパイルするには、自動ビルドシステム(CMakeなど)を使用するか、メイクファイルを自分で登録する必要があります。 これについては詳しく説明しません。 そして、makefileの説明の例を挙げてください。 ポストの終わりに設立に関する最近の2つの参照は、単にファイルを作ります。

 CC=g++ LDLIBS=`pkg-config --libs gtk+-2.0 gmodule-2.0` CFLAGS=-Wall -g `pkg-config --cflags gtk+-2.0 gmodule-2.0` Example1: Example1.o $(CC) $(LDLIBS) Example1.o -o Example1 Example1.o: Example1.cpp $(CC) $(CFLAGS) -c Example1.cpp clean: rm -f Example1 rm -f *.o 


コンパイルはコマンドです。
 make 


私たちのプログラムの小規模なテスト



起動中...

画像

...そしてウィンドウのサイズを変更します

画像

サイドメニューとキャンバスは伸びず、同じ寸法のままでしたが、キャンバスが寸法を変更したコンテナが表示されています。 そして、どこフォームのサイズの増加に伴って登場し、すべての空き領域が、彼を得ました。 私たちが幅= 145 reguest scrolledwindow1を確立し、 はいサイズを変更しているので、これがすべてです メインウィンドウが小さくなったときに表示されるスクロールバーの例を次に示します

画像

そして今、私はYesにプロパティを展開Glade3に来て、LABEL1に変更されました。 プロジェクトを再コンパイルする必要はありません。 mainFormファイルを保存するだけです。 結果は次のとおりです。

画像

なぜそう 固定サイズのキャンバスがあります。 また、メインウィンドウを拡大したときに取得されるすべてのスペースは、label1ウィジェットに与えられます。 このすべてのビジネスで「遊ぶ」ことができます。 たとえば、[展開]を[いいえ]に設定し、正確な高さの値(70など)を指定します。また、既定のサイズではなく、指定したサイズに固定されます。

これでこの投稿は終了です。 トピックは面白いですが、私はこの方向でより多くの記事を書きたいという願望を持っています。

Glade3のチュートリアル-サイズネゴシエーションから少しの理論が得られます。
私はあなたが読むことをお勧めし: のパッキングウィジェットをカイログラフィックチュートリアルのMakefileの例によるGNU `make 'を

Source: https://habr.com/ru/post/J107403/


All Articles