C言語GUI入門|GtkEntryで文字を入力する

GtkEntryは、ユーザーが1行の文字列を入力するためのウィジェットです。名前、検索キーワード、数値、メールアドレスなどを入力する画面で使用します。

この記事では、次の内容を学びます。

  • GtkEntryの役割
  • gtk_entry_newによる入力欄の作成
  • gtk_editable_get_textによる入力文字列の取得
  • gtk_editable_set_textによる初期値の設定
  • gtk_entry_set_placeholder_textによるプレースホルダーの設定
  • 入力欄が空かどうかを確認する方法
  • 入力欄をGtkBoxへ配置する方法
  • プログラムのコンパイルと実行

今回作成するプログラムでは、GtkEntryへ入力した文字列を、入力内容を確認ボタンで取得します。取得した文字列は、プログラムを起動したMSYS2 UCRT64 Bashへ表示します。

GtkEntryとは

GtkEntryは、1行の文字列を入力するためのウィジェットです。

GtkEntryは、次のような入力に使用できます。

  • ユーザー名
  • 商品名や検索キーワード
  • メールアドレス
  • 電話番号
  • 個数や金額
  • ファイル名
  • 短いメッセージ

GtkEntryは1行入力用です。複数行にわたる長い文章を入力する場合は、GtkTextViewなどのウィジェットを使用します。

ウィジェット主な役割
GtkLabel文字列を表示する
GtkEntry1行の文字列を入力する
GtkTextView複数行の文字列を入力・表示する
GtkButtonユーザーの操作を受け取る

図1:GUI画面で文字列を入力するGtkEntry

この図から分かること

GtkLabelは入力項目の説明を表示し、GtkEntryはユーザーから文字列を受け取ります。GtkButtonを組み合わせると、入力された文字列を使う処理を開始できます。

入力欄だけを表示するよりも、何を入力する欄なのかをGtkLabelやプレースホルダーで案内すると、分かりやすい画面になります。

GtkEntryを作成する

GtkEntryはgtk_entry_newで作成します。

GtkWidget *entry;

entry = gtk_entry_new();

gtk_entry_newには引数がありません。戻り値として、新しく作成されたGtkEntryを指すGtkWidgetへのポインターが返されます。

作成直後のGtkEntryは空です。ユーザーは、画面に表示された入力欄をクリックして文字列を入力できます。

GtkWidgetとGtkEntryの関係

gtk_entry_newの戻り値はGtkWidgetへのポインターなので、変数は次のように宣言できます。

GtkWidget *entry;

GtkEntryはGtkWidgetを基礎として作られています。そのため、余白、表示状態、横方向への広がりなど、GtkWidgetに共通する設定を利用できます。

gtk_widget_set_hexpand(entry, TRUE);

gtk_widget_set_hexpandへTRUEを指定すると、親ウィジェットから割り当てられる横方向の空間を利用して広がるようになります。

GtkEntry専用の関数を使用する場合は、GTK_ENTRYを使ってGtkEntryへのポインターとして渡します。

gtk_entry_set_placeholder_text(
    GTK_ENTRY(entry),
    "名前を入力してください"
);

入力文字列の取得や設定にはGtkEditableの関数を使うため、GTK_EDITABLEを使用します。

gtk_editable_set_text(
    GTK_EDITABLE(entry),
    "初期値"
);

GtkEditableとは

GtkEntryはGtkEditableという仕組みを実装しています。GtkEditableは、編集可能な文字列を扱うための共通機能です。

GtkEntryの入力文字列を扱うときは、次の関数をよく使用します。

関数役割
gtk_editable_get_text現在の入力文字列を取得する
gtk_editable_set_text入力欄の文字列を設定する
gtk_editable_delete_text指定した範囲の文字列を削除する
gtk_editable_get_positionカーソル位置を取得する
gtk_editable_set_positionカーソル位置を設定する

この記事では、gtk_editable_get_textとgtk_editable_set_textを使用します。

入力された文字列を取得する

GtkEntryへ入力された文字列はgtk_editable_get_textで取得します。

const char *text;

text = gtk_editable_get_text(
    GTK_EDITABLE(entry)
);

gtk_editable_get_textの引数には、入力内容を取得するGtkEditableを指定します。GtkEntryへのポインターはGTK_EDITABLEで変換して渡します。

戻り値は、現在の入力文字列を指すconst charへのポインターです。

g_print("入力された文字列:%s\n", text);

ユーザーがGTK 4を入力していた場合は、次のように表示されます。

入力された文字列:GTK 4

取得した文字列を変更したり解放したりしない

gtk_editable_get_textで取得した文字列は、GtkEntry側で管理されています。そのため、取得したポインターが指す文字列を直接書き換えたり、freeやg_freeで解放したりしてはいけません。

const char *text;

text = gtk_editable_get_text(GTK_EDITABLE(entry));

変数をconst charへのポインターとして宣言しているのは、取得した文字列を変更しないことを表しています。

入力欄の内容が変更されると、取得済みのポインターが同じ内容を指し続けるとは限りません。文字列を長く保存しておく必要がある場合は、g_strdupなどで複製します。

char *copy;

copy = g_strdup(
    gtk_editable_get_text(GTK_EDITABLE(entry))
);

g_print("コピーした文字列:%s\n", copy);

g_free(copy);

今回のプログラムでは、取得直後にg_printで表示するだけなので、文字列を複製する必要はありません。

入力欄が空かどうかを確認する

GtkEntryに何も入力されていない場合、gtk_editable_get_textは空文字列を返します。

空文字列は、先頭の文字がナル文字になっています。そのため、次の条件で確認できます。

if (text[0] == '\0') {
    g_print("入力欄は空です\n");
}
条件入力欄の状態
text[0] == '\0'何も入力されていない
text[0] != '\0'1文字以上入力されている

空欄を確認せずに処理を進めると、必要な値がないまま保存や計算を行ってしまう可能性があります。入力内容を利用する前に、空欄を確認する習慣を付けておくと安心です。

図2:GtkEntryから入力文字列を取得する流れ

この図から分かること

ユーザーが入力した文字列はGtkEntry側で保持されます。gtk_editable_get_textを呼び出すと、その文字列をconst charへのポインターとして参照できます。

取得した文字列はGtkEntryが管理しているため、プログラム側で直接変更したり解放したりしません。必要な処理がある場合は、取得した文字列を読み取り用として利用します。

初期値を設定する

プログラムの起動時からGtkEntryへ文字列を表示しておきたい場合は、gtk_editable_set_textを使用します。

gtk_editable_set_text(
    GTK_EDITABLE(entry),
    "GTK 4を学習中"
);

gtk_editable_set_textの第1引数には設定対象のGtkEditableを指定し、第2引数には表示する文字列を指定します。

引数指定する内容
第1引数文字列を設定するGtkEntry
第2引数入力欄へ設定する文字列

設定された初期値は、単なる案内表示ではありません。実際の入力内容としてGtkEntryに保存されます。そのため、ユーザーが変更しなければ、gtk_editable_get_textから初期値が取得されます。

初期値は、次のような場面で便利です。

  • 前回保存した設定を表示する
  • 修正対象のデータを表示する
  • よく使う値をあらかじめ入力する
  • 数値入力欄へ0を設定する

入力欄を空にする

gtk_editable_set_textへ空文字列を指定すると、GtkEntryの入力内容を消去できます。

gtk_editable_set_text(
    GTK_EDITABLE(entry),
    ""
);

GUI電卓のクリアボタンなどで利用できます。

プレースホルダーを設定する

プレースホルダーは、入力欄が空のときに表示される案内用の文字列です。

gtk_entry_set_placeholder_textを使って設定します。

gtk_entry_set_placeholder_text(
    GTK_ENTRY(entry),
    "文字を入力してください"
);

プレースホルダーには、何を入力すればよいか分かる短い案内を指定します。

プレースホルダーの例は次のとおりです。

入力項目プレースホルダーの例
名前名前を入力してください
検索検索キーワードを入力
メールアドレスexample@example.com
数値0以上の数値を入力

初期値とプレースホルダーの違い

初期値とプレースホルダーは、どちらもGtkEntryの中に文字が表示されますが、役割が異なります。

比較項目初期値プレースホルダー
設定する関数gtk_editable_set_textgtk_entry_set_placeholder_text
表示される条件入力内容として常に表示される入力欄が空のときに表示される
gtk_editable_get_textで取得取得される取得されない
ユーザーによる編集できる案内表示なので編集対象ではない
主な用途既定値や保存済みの値入力内容の例や案内

初期値が設定されている間、プレースホルダーは見えません。初期値をすべて削除して入力欄を空にすると、プレースホルダーが表示されます。

プレースホルダーが画面に見えていても、実際に入力されているわけではありません。その状態でgtk_editable_get_textを実行すると、空文字列が取得されます。

入力内容をボタンで取得する

今回のプログラムでは、GtkEntryをg_signal_connectの第4引数に指定します。

g_signal_connect(
    show_button,
    "clicked",
    G_CALLBACK(on_show_clicked),
    entry
);

第4引数へ指定したentryは、コールバック関数のuser_dataへ渡されます。

static void on_show_clicked(
    GtkButton *button,
    gpointer user_data
)
{
    GtkWidget *entry;
    const char *text;

    (void)button;

    entry = GTK_WIDGET(user_data);
    text = gtk_editable_get_text(
        GTK_EDITABLE(entry)
    );
}

コールバック関数では、user_dataからGtkEntryを受け取り、gtk_editable_get_textで入力文字列を取得します。

入力欄をレイアウトへ追加する

今回のプログラムでは、GtkLabel、GtkEntry、GtkButtonをGtkBoxへ縦方向に配置します。

ウィジェットの階層は次のようになります。

GtkWindow
└─GtkBox
  ├─GtkLabel
  ├─GtkEntry
  └─GtkButton

GtkBoxへ追加するコードは次のとおりです。

gtk_box_append(GTK_BOX(box), guide_label);
gtk_box_append(GTK_BOX(box), entry);
gtk_box_append(GTK_BOX(box), show_button);

gtk_box_appendを実行した順番で、上からGtkLabel、GtkEntry、GtkButtonが並びます。

GtkEntryへ入力した文字列を取得するプログラム

ファイル名:entry_demo.c

#include <gtk/gtk.h>

static void on_show_clicked(
    GtkButton *button,
    gpointer user_data
)
{
    GtkWidget *entry;
    const char *text;

    (void)button;

    entry = GTK_WIDGET(user_data);

    text = gtk_editable_get_text(
        GTK_EDITABLE(entry)
    );

    if (text[0] == '\0') {
        g_print("入力欄は空です\n");
        return;
    }

    g_print(
        "入力された文字列:%s\n",
        text
    );
}

static void activate(
    GtkApplication *app,
    gpointer user_data
)
{
    GtkWidget *window;
    GtkWidget *box;
    GtkWidget *guide_label;
    GtkWidget *entry;
    GtkWidget *show_button;

    (void)user_data;

    window = gtk_application_window_new(app);
    gtk_window_set_title(
        GTK_WINDOW(window),
        "GtkEntryの例"
    );
    gtk_window_set_default_size(
        GTK_WINDOW(window),
        460,
        240
    );

    box = gtk_box_new(
        GTK_ORIENTATION_VERTICAL,
        16
    );

    gtk_widget_set_margin_top(box, 24);
    gtk_widget_set_margin_bottom(box, 24);
    gtk_widget_set_margin_start(box, 24);
    gtk_widget_set_margin_end(box, 24);

    guide_label = gtk_label_new(
        "確認したい文字列を入力してください"
    );

    entry = gtk_entry_new();

    gtk_entry_set_placeholder_text(
        GTK_ENTRY(entry),
        "文字を入力してください"
    );

    gtk_editable_set_text(
        GTK_EDITABLE(entry),
        "GTK 4を学習中"
    );

    show_button = gtk_button_new_with_label(
        "入力内容を確認"
    );

    g_signal_connect(
        show_button,
        "clicked",
        G_CALLBACK(on_show_clicked),
        entry
    );

    gtk_box_append(
        GTK_BOX(box),
        guide_label
    );
    gtk_box_append(
        GTK_BOX(box),
        entry
    );
    gtk_box_append(
        GTK_BOX(box),
        show_button
    );

    gtk_window_set_child(
        GTK_WINDOW(window),
        box
    );

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char *argv[])
{
    GtkApplication *app;
    int status;

    app = gtk_application_new(
        "com.example.entrydemo",
        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;
}

プログラムの解説

入力内容を取得するコールバック関数

static void on_show_clicked(
    GtkButton *button,
    gpointer user_data
)

on_show_clickedは、入力内容を確認ボタンのclickedシグナルが発生したときに呼び出されます。

buttonにはクリックされたGtkButtonが渡されます。このプログラムでは使用しないため、次の記述で未使用であることを明示しています。

(void)button;

user_dataからGtkEntryを受け取る

entry = GTK_WIDGET(user_data);

g_signal_connectの第4引数に指定したentryを、コールバック関数のuser_dataから受け取ります。

入力文字列を取得する

text = gtk_editable_get_text(
    GTK_EDITABLE(entry)
);

GTK_EDITABLEでentryをGtkEditableとして扱い、現在の入力文字列を取得しています。

空欄を確認する

if (text[0] == '\0') {
    g_print("入力欄は空です\n");
    return;
}

取得した文字列の先頭がナル文字なら、入力欄は空です。メッセージを表示してreturnを実行し、コールバック関数を終了します。

取得した文字列を表示する

g_print(
    "入力された文字列:%s\n",
    text
);

g_printを使って、プログラムを起動したMSYS2 UCRT64 Bashへ入力文字列を表示します。

GtkEntryを作成する

entry = gtk_entry_new();

1行の文字列を入力できる空のGtkEntryを作成します。

プレースホルダーを設定する

gtk_entry_set_placeholder_text(
    GTK_ENTRY(entry),
    "文字を入力してください"
);

入力欄が空のときに、文字を入力してくださいという案内が表示されるように設定します。

初期値を設定する

gtk_editable_set_text(
    GTK_EDITABLE(entry),
    "GTK 4を学習中"
);

起動直後の入力値としてGTK 4を学習中を設定します。初期値が入っている間はプレースホルダーが表示されません。

ボタンとコールバック関数を接続する

g_signal_connect(
    show_button,
    "clicked",
    G_CALLBACK(on_show_clicked),
    entry
);

入力内容を確認ボタンのclickedシグナルへon_show_clickedを接続します。第4引数にentryを指定し、コールバック関数へ渡しています。

プログラムをコンパイルする

VSCodeでMSYS2 UCRT64 Bashの統合ターミナルを開きます。

最初にchap05ディレクトリへ移動します。

cd /c/cgui/chap05

警告を有効にしてC17規格でコンパイルする場合は、次のコマンドを実行します。

gcc -std=c17 -Wall -Wextra $(pkg-config --cflags gtk4) entry_demo.c -o entry_demo.exe $(pkg-config --libs gtk4)

コンパイルに成功すると、C:\cgui\chap05にentry_demo.exeが作成されます。

次の短いコマンドでもコンパイルできます。

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

短いコマンドでは、pkg-configの--cflagsと--libsをまとめて指定しています。

記述役割
gccGCCを起動する
-std=c17C17規格を使用する
-Wall基本的な警告を有効にする
-Wextra追加の警告を有効にする
pkg-config --cflags gtk4GTK 4のヘッダーファイルに必要な情報を取得する
entry_demo.cコンパイルするソースファイル
-o entry_demo.exe作成する実行ファイル名を指定する
pkg-config --libs gtk4GTK 4のライブラリに必要な情報を取得する

プログラムを実行する

次のコマンドを実行します。

./entry_demo.exe

ウィンドウが表示されたら、最初に初期値の状態で入力内容を確認ボタンをクリックします。

次に、入力欄の初期値をすべて削除して、プレースホルダーが表示されることを確認します。そのままボタンをクリックすると、入力欄が空であることを確認できます。

最後に、好きな文字列を入力してから、もう一度ボタンをクリックします。

図3:初期値・プレースホルダー・入力結果の確認

この図から分かること

初期値は実際の入力内容なので、gtk_editable_get_textで取得できます。一方、プレースホルダーは入力欄が空であることを前提に表示される案内なので、入力文字列としては取得されません。

ユーザーが新しい文字列を入力すると、gtk_editable_get_textからその時点の内容を取得できます。

実行結果の例

プログラムを起動すると、次の内容が表示されます。

  • ウィンドウのタイトルはGtkEntryの例
  • ウィンドウの初期サイズは横460ピクセル、縦240ピクセル
  • 上部に確認したい文字列を入力してくださいと表示される
  • GtkEntryには初期値としてGTK 4を学習中と表示される
  • 入力欄の下に入力内容を確認ボタンが表示される

初期値を変更せずに入力内容を確認ボタンをクリックすると、MSYS2 UCRT64 Bashに次のように表示されます。

入力された文字列:GTK 4を学習中

入力欄の文字列をすべて削除すると、入力欄には次のプレースホルダーが表示されます。

文字を入力してください

この状態で入力内容を確認ボタンをクリックすると、次のように表示されます。

入力欄は空です

入力欄へ「C言語GUI入門」と入力してからボタンをクリックすると、MSYS2 UCRT64 Bashにに次のように表示されます。

入力された文字列:C言語GUI入門

文字列を変更してボタンをクリックするたびに、その時点でGtkEntryに入力されている内容が取得されます。

ウィンドウ右上の閉じるボタンをクリックすると、ウィンドウが閉じてプログラムが終了します。