17

プログラムでGTKGUIの構造を調べることができる必要があります。私はGtkWidgetを持っていて、そのウィジェットの子を見つけたいと思っています。これで、GtkContainerには子を検索する関数があり、GtkContainerはGtkWidgetから派生していることがわかりました。

とにかく、ウィジェットがGtkContainerであるかどうかを確認してから、キャストを実行することはできますか?そうでない場合、私が持っているものの子であるGtkWidgetを発見する他の方法はありますか?

4

4 に答える 4

16

はい、オブジェクトがそのタイプであるかどうかをチェックするために、すべてのGObjectタイプにマクロがあります。

if(GTK_IS_CONTAINER(widget)) {
    GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
    ...
}

ウィジェットがの場合、GtkBin子は1つだけです。GListその場合、以下は:を扱うよりも簡単です。

if(GTK_IS_BIN(widget)) {
    GtkWidget *child = gtk_bin_get_child(GTK_BIN(widget));
    ...
}
于 2011-03-24T09:00:20.180 に答える
7

次のコードではfind_child、ウィジェットを名前で再帰的に検索する関数を実装しました。アイデアは、@ ptomatoの答えと、のPHPの例に基づいています。

    #include <gtk/gtk.h>

    GtkWidget*
    find_child(GtkWidget* parent, const gchar* name)
    {
            if (g_strcasecmp(gtk_widget_get_name((GtkWidget*)parent), (gchar*)name) == 0) { 
                    return parent;
            }

            if (GTK_IS_BIN(parent)) {
                    GtkWidget *child = gtk_bin_get_child(GTK_BIN(parent));
                    return find_child(child, name);
            }

            if (GTK_IS_CONTAINER(parent)) {
                    GList *children = gtk_container_get_children(GTK_CONTAINER(parent));
                    while ((children = g_list_next(children)) != NULL) {
                            GtkWidget* widget = find_child(children->data, name);
                            if (widget != NULL) {
                                    return widget;
                            }
                    }
            }

            return NULL;
    }

    int
    main(int argc, char *argv[])
    {
            gtk_init(&argc, &argv);

            GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
            GtkWidget *frame = gtk_frame_new(NULL);
            GtkWidget *vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5);
            GtkWidget *textView = gtk_text_view_new();
            GtkWidget *hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5);
            GtkWidget *button1 = gtk_button_new_with_label("button1");
            gtk_widget_set_name(button1, "btn1");
            GtkWidget *button2 = gtk_button_new_with_label("button2");
            gtk_widget_set_name(button2, "btn2");

            gtk_window_set_title(GTK_WINDOW(window), "Hello");
            gtk_container_set_border_width(GTK_CONTAINER(window), 10);
            gtk_window_set_default_size(GTK_WINDOW(window), 450, 400);

            gtk_container_add(GTK_CONTAINER(window), frame);
            gtk_container_add(GTK_CONTAINER(frame), vbox1);

            gtk_box_pack_start(GTK_BOX(vbox1), textView, 1, 1, 0);
            gtk_box_pack_start(GTK_BOX(vbox1), hbox1, 0, 1, 0);
            gtk_box_pack_start(GTK_BOX(hbox1), button1, 0, 1, 0);
            gtk_box_pack_start(GTK_BOX(hbox1), button2, 0, 1, 0);

            gtk_widget_show_all(window);

            g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

            GtkWidget* child = find_child(window, "btn2");
            if (child == button2) {
                    g_print("found it!\n");
            } else {
                    g_print("not found it!\n");
            }

            gtk_main();
            return 0;
    }
于 2014-05-06T14:08:39.740 に答える
0

受け入れられた回答と同じプリンシパルに基づいてこれらの関数を作成しました。

find_child_by_indexdepthは渡す必要のあるインデックスの量と同じです。最初のインデックスはの子用でparent、2番目のインデックスは孫用などです。

void print_children_helper(GtkWidget* parent, int indent_size, int depth)
{
    for (int i = 0; i < depth * indent_size; i++)
        printf(" ");
    printf("%s\n", gtk_widget_get_name(parent));

    GList* children = NULL;
    if (GTK_IS_CONTAINER(parent))
        children = gtk_container_get_children(GTK_CONTAINER(parent));

    while (children != NULL)
    {
        print_children(children->data, indent_size, depth + 1);
        children = children->next;
    }
}

void print_children(GtkWidget* parent, int indent_size)
{
    print_children_helper(parent, indent_size, 0);
}

GtkWidget* find_child_by_name(GtkWidget* parent, const gchar* name)
{
    if (g_strcmp0(gtk_widget_get_name(parent), name) == 0)
        return parent;

    GList* children = NULL;
    if (GTK_IS_CONTAINER(parent))
        children = gtk_container_get_children(GTK_CONTAINER(parent));

    while (children != NULL)
    {
        GtkWidget* widget = find_child_by_name(children->data, name);

        if (widget != NULL)
            return widget;

        children = children->next;
    }

    return NULL;
}

GtkWidget* find_child_by_index(GtkWidget* parent, int depth, ...)
{
    va_list argp;
    va_start(argp, depth);

    for (int i = 0; i < depth; i++)
    {
        int index = va_arg(argp, int);

        GList* children = NULL;
        if (GTK_IS_CONTAINER(parent))
            children = gtk_container_get_children(GTK_CONTAINER(parent));

        for (int j = 0; j < index; j++)
            if (children != NULL)
                children = children->next;

        if (children != NULL)
            parent = children->data;
        else
            return NULL;
    }

    va_end(argp);
    return parent;
}
于 2021-11-10T14:38:24.757 に答える
0

GtkContainerが存在しなくなったため、GTK4を使用する場合は、別のアプローチが必要です。移行ガイドを参照してください

ウィジェット階層をトラバースする単純な関数:

void print_widget_names(GtkWidget* parent, int level) {
  for (int i=0; i < level; i++) { 
    g_print("    ");
  }
  level++;
  g_print("%s\n", gtk_widget_get_name(GTK_WIDGET(parent)));
  GtkWidget *widget = gtk_widget_get_first_child(GTK_WIDGET(parent));
  GtkWidget *next;
  if (widget != NULL) {
    print_widget_names(widget, level);
    while ((next = gtk_widget_get_next_sibling(widget)) != NULL) {
      widget = next;
      print_widget_names(widget, level);
    }
  }
}
于 2022-02-14T06:40:43.103 に答える