我需要能够以编程方式探索 GTK GUI 的结构。我有 GtkWidget,我想找到该小部件的任何子级。现在我知道 GtkContainer 具有查找子级的功能,并且 GtkContainer 是从 GtkWidget 派生的。
无论如何我可以检查一个小部件是否是一个 GtkContainer 然后执行转换?如果没有,有没有其他方法可以发现我所拥有的 GtkWidget 的孩子?
我需要能够以编程方式探索 GTK GUI 的结构。我有 GtkWidget,我想找到该小部件的任何子级。现在我知道 GtkContainer 具有查找子级的功能,并且 GtkContainer 是从 GtkWidget 派生的。
无论如何我可以检查一个小部件是否是一个 GtkContainer 然后执行转换?如果没有,有没有其他方法可以发现我所拥有的 GtkWidget 的孩子?
是的,每个 GObject 类型都有宏来检查对象是否属于该类型:
if(GTK_IS_CONTAINER(widget)) {
GList *children = gtk_container_get_children(GTK_CONTAINER(widget));
...
}
如果小部件是 aGtkBin
它只有一个孩子。在这种情况下,以下操作比处理 a 更简单GList
:
if(GTK_IS_BIN(widget)) {
GtkWidget *child = gtk_bin_get_child(GTK_BIN(widget));
...
}
In the following code I have implemented find_child
function which recursively searches for the widget by name. Ideas build on the answer of @ptomato and from the following PHP example:
#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;
}
如果使用 GTK4 作为 GtkContainer 不再存在,则需要一种不同的方法。请参阅迁移指南
遍历小部件层次结构的简单函数:
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);
}
}
}
我创建了这些函数,它们与接受的答案基于相同的原则。
在find_child_by_index
中,depth
等于您需要传递的索引数量。第一个索引是 的孩子parent
,第二个索引是孙辈,依此类推。
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;
}