GTK4   ウィンドウ

ホーム   C/C++チュートリアル  

ウィンドウ   最小のアプリケーション作成

GTK のプログラミングはウィジェットと呼ばれる GUI パーツを使って作っていきます。ウィンドウもウィジェットの一つです。そして、さらにその上に(中に)ウィジェットを配置できるコンテナーと呼ばれるウィジェットです。 目に見えるアプリケーションの場合、ウィンドウがその土台になります。

GUI ライブラリである GTK4 にとってウィンドウの存在は非常に大きく、ウィンドウの存在がアプリケーションの起動と終了にリンクしています。

順を追って説明していきます。例として app.c というファイルで作業していきます。

app.c


  #include <gtk/gtk.h>
  
  int
  main (int argc, char **argv)
  {
    int stat;
    g_print ("main\n");
    return stat;
  }
  

  // ビルド
  cc app.c -o app `pkg-config --cflags --libs gtk4`
  
  // 実行
  ./app
  
  // 結果
  main
  

通常の C プログラミングと変わりありません。g_print 関数を使うために <gtk/gtk.h> を読み込んでいます。 <gtk/gtk.h> には GTK に必要な 関数、定数、マクロが宣言されています。

GTK4 プログラミングでの main 関数の役割は、GUI アプリケーションの起動と終了を実質管理している gtk_application のオブジェクトを作成して、そのオブジェクトを実行することです。


  #include <gtk/gtk.h>
  
  int
  main (int argc, char **argv)
  {
    GtkApplication *app;
    int stat;
    
    // アプリケーションオブジェクトの作成
    app = gtk_application_new ("com.usodesu.app", G_APPLICATION_DEFAULT_FLAGS);
    // アプリケーションオブジェクトの実行
    stat = g_application_run (G_APPLICATION (app), argc, argv);
    g_print ("main\n");
    return stat;
  }
  

  // ビルド
  cc app.c -o app `pkg-config --cflags --libs gtk4`
  
  // 実行
  ./app
  
  // 結果
  Your application does not implement g_application_activate() and has no handlers connected to the 'activate' signal.
  It should do one of these.
  
  アプリケーションには g_application_activate 関数がなく、activate 信号に接続されたハンドルもありません。
  これらの一つを行うべきです。
  

指示のとおりに activate 関数を作って、信号を接続します。

なお、ここで重要なのは g_application_run 関数の第一引数です。ここにはアプリケーションの識別子となる文字列を与えますが、必ず、 逆 URL 方式にしなければなりません。逆 URL 方式でない場合は、ビルドエラーになります。


#include <gtk/gtk.h>

static void
activate (GApplication *app, gpointer data)
{
    g_print ("activate\n");
}

int
 main (int argc, char **argv)
{
    g_print ("main\n");
    
    GtkApplication *app;
    int stat;
    
    app = gtk_application_new ("com.usodesu.app", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    stat = g_application_run (G_APPLICATION (app), argc, argv);
    
    g_print ("main\n");
    
    return stat;
}

// ビルド
cc app.c -o app `pkg-config --cflags --libs gtk4`

// 実行
./app

// 結果
main
activate
main

main 関数から activate 関数を呼び出して、main 関数に戻り、プログラムを終了していることがわかります。

activate 関数には、アプリケーションの振る舞いや見た目を設定していきます。


#include <gtk/gtk.h>

static void
activate (GApplication *app, gpointer data)
{
    g_print ("activate\n");
    
    GtkWidget * win;
    win = gtk_window_new ();
    
    g_print ("activate\n");
}

int
 main (int argc, char **argv)
{
    g_print ("main\n");
    
    GtkApplication *app;
    int stat;
    
    app = gtk_application_new ("com.usodesu.app", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    stat = g_application_run (G_APPLICATION (app), argc, argv);
    
    g_print ("main\n");
    
    return stat;
}

// ビルド
cc app.c -o app `pkg-config --cflags --libs gtk4`

// 実行
./app

// 結果
main
activate
activate
main

activate 関数内でウィンドウは作られたみたいですが、すぐに main に戻ってプログラムを終了しています。 アプリケーションを起動し続けるには、ウィンドウと application オブジェクトをリンクさせる必要があります。


#include <gtk/gtk.h>

static void
activate (GApplication *app, gpointer data)
{
    g_print ("activate\n");
    
    GtkWidget * win;
    win = gtk_window_new ();
    gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
    
    g_print ("activate\n");
}

int
 main (int argc, char **argv)
{
    g_print ("main\n");
    
    GtkApplication *app;
    int stat;
    
    app = gtk_application_new ("com.usodesu.app", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    stat = g_application_run (G_APPLICATION (app), argc, argv);
    
    g_print ("main\n");
    
    return stat;
}

GTK_WINDOW などのマクロについて

GTK のウィジェットは、ほとんどが汎用の GtkWiget 型に保持されます。しかし実際に関数で使われる場合は、実際の型に直さなければなりません。 その時に使われるのが、GTKK_WINDOW などのマクロです。これは型の変換 (キャスト) を行っています。
最初から GtkWindow 型に代入すれば良いのではと思われますが、実際にやってみると、それはできないことになっています。


// ビルド
cc app.c -o app `pkg-config --cflags --libs gtk4`

// 実行
./app

// 結果
main
activate
activate

// 何も表示されずに起動したままになるので、Control + C とキー入力して終了させる
^C

ウィンドウと application オブジェクトがリンクされ、アプリケーションは起動し続けますが、ウィンドウの表示を指定しなければ、 ウインドウは表示されません。


#include <gtk/gtk.h>

static void
activate (GApplication *app, gpointer data)
{
    g_print ("activate\n");
    
    GtkWidget * win;
    win = gtk_window_new ();
    gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
    gtk_window_present (GTK_WINDOW (win));
    
    g_print ("activate\n");
}

int
 main (int argc, char **argv)
{
    g_print ("main\n");
    
    GtkApplication *app;
    int stat;
    
    app = gtk_application_new ("com.usodesu.app", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
    stat = g_application_run (G_APPLICATION (app), argc, argv);
    
    g_print ("main\n");
    
    return stat;
}

// ビルド
cc app.c -o app `pkg-config --cflags --libs gtk4`

// 実行
./app

// 結果
main
activate
activate

// ウィンドウが表示され続けます。ウィンドウをクローズさせると、main 関数に戻り、アプリケーションは終了します
main

ウィンドウと application オブジェクトがリンクしているので、ウィンドウを閉じると、application オブジェクトも終了します。 そして main 関数に戻りプログラムは終了します。

ウィンドウのタイトルについて

ウィンドウのタイトルを設定していない場合は次のようになります

なお、ウィンドウの作成と、作成したウィンドウを application オブジェクトとリンクさせるのは一つの関数でできます。 通常はこちらを使います。


win = gtk_window_new ();
gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));

  ↓

win = gtk_application_window_new (GTK_APPLICATION (app));

以下が完成した、ミニマルなアプリケーションです。

完成品


#include <gtk/gtk.h>

static void
activate (GApplication *app, gpointer data)
{
	GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
	gtk_window_present (GTK_WINDOW (win));
}

int
main (int argc, char **argv)
{
	GtkApplication *app;
	int            stat;
	
	app = gtk_application_new ("jp.vivacocoa.window", G_APPLICATION_DEFAULT_FLAGS);
	g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
	stat = g_application_run (G_APPLICATION (app), argc, argv);
	g_object_unref (app);
	
	return stat;
}

ウィンドウのサイズについて

ウィンドウのサイズを指定していない場合は次のようになります

アレンジ

ウィンドウのタイトルとサイズを指定してみました

以下のファイルを window.c という名前で記述してください。

window.c


#include <gtk/gtk.h>
static void
activate(GtkApplication *app,
	 gpointer       user_data)
{
  GtkWidget *window;
  
  window = gtk_application_window_new(app);
  gtk_window_set_title(GTK_WINDOW(window),"window");
  gtk_window_set_default_size(GTK_WINDOW(window),600,400);
  gtk_window_present(GTK_WINDOW(window));
}
int
main(int    argc,
     char **argv)
{
  GtkApplication *app;
  int status;
  
  app = gtk_application_new("jp.vivacocoa.window", G_APPLICATION_DEFAULT_FLAGS);
  g_signal_connect(app, "activate",G_CALLBACK(activate),NULL);
  status = g_application_run(G_APPLICATION(app),argc,argv);
  g_object_unref(app);
  
  return status;
}

コード説明

  1. #include <gtk/gtk.h>
    ヘッダファイルを読み込みます。gtk.h には GTK で使われる関数、型、マクロが宣言されています
  2. static void activate(...)
    後ほど呼び出される activate 関数を定義しています。この中にアプリの挙動や見た目を定義します。第1引数に apllication オブジェクトのポインター app が、第2引数にそのほかのデータが渡されます。第2引数は NULL が渡されても大丈夫です
  3. GtkWidget *window;
    GTK のウィジェットの型はすべて GtkWidget になります。続く3行でウィンドウを作って、タイトルとサイズを決めています
  4. gtk_window_present(...)
    この関数ではじめてウィンドウが表示されます。それまでは、ウィンドウは作られていても表示はされていません
  5. int main(...)
    main 関数の役割は application オブジェクトを作成して、それを起動させることです。application オブジェクトが起動し続ける限り、 プログラムが終了することはありません
  6. app = gtk_application_new(...)
    application オブジェクトを作っています。第1引数にはアプリケーションに与えられる一意の識別子を与えます。通常は URL を逆にしたものを用いたものにします。 第2引数にアプリケーションの目的を表すマクロを指定します。特別な目的がない場合は、G_APPLICATION_DEFAULT_FLAGS にします。このマクロはアプリケーションがコマンド引数を使用しないことを表していて、一番シンプルな指定です。
  7. g_signal_connect(...)
    イベントとイベントリスナーを結びつけています。イベントは app オブジェクトの "activate" で、これは application オブジェクトが起動した時に発せられます。 イベントリスナーは先ほど定義した activate 関数です。第4引数に activate 関数に渡すデータを指定しますが、何もない時は NULL を渡します
  8. status = g_application_run(...)
    application オブジェクトを起動します。application オブジェクトは別途指令があるまでは起動し続けます。 application オブジェクトが終了した時には整数値を返しますが、その値を 変数 status に代入します
  9. g_object_unref(app);
    application オブジェクトが終了したら、application オブジェクト app に割り当てらたメモリーを解放します
  10. return status;
    最後に status を返して、プログラムを終了します

コンパイルと実行

以下のとおりです。Windows の場合は通常版でも ARM64版 でも mingw64 で行ってください。


// コンパイル
cc `pkg-config --cflags gtk4` window.c -o window `pkg-config --libs gtk4`

もしくは

gcc $(pkg-config --cflags gtk4) -o window window.c $(pkg-config --libs gtk4)

もしくは

cc window.c -o window `pkg-config --cflags --libs gtk4`

// 実行
./window


233 visits
Posted: Mar. 15, 2025
Update: Mar. 21, 2025

ホーム   C/C++チュートリアル   目次