无法隐藏和显示小部件以响应事件
Trouble hiding and showing widgets in response to event
问题
我有一个问题,通过 gtk_widget_hide_on_delete 关闭带有删除事件的小部件无法通过交换的 gtk_widget_show_all 再次显示菜单小部件,并将相应的小部件作为参数传递给它。
背景
我正在创建一个程序,其中包含一个带有多个按钮小部件的选择菜单。按一个按钮将隐藏菜单,并显示一个包含标签和 TextEntry 的 window 小部件,此 window 小部件的删除事件将隐藏该小部件,并再次显示菜单。
示例程序
我已经为这个问题创建了一个最小的例子。该代码只是通过 GtkBuilder
加载 ui,然后进入主 gtk 循环。
我依赖 gtk_widget_show_all
、gtk_widget_hide
和 gtk_widget_hide_on_delete
,但是当我使用 delete-event
关闭 练习小部件 时,window 消失,但菜单小部件未显示。
#include <gtk/gtk.h>
#include <stdio.h>
int main(int argc, char **argv)
{
GtkBuilder * builder;
GtkWidget * menu;
GError *error = NULL;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
if (!gtk_builder_add_from_file(builder, "example.glade", &error)) {
g_warning("%s", error->message);
g_free(error);
fprintf(stderr, "Failed to load build file");
}
menu = (GtkWidget *) gtk_builder_get_object(builder, "menu");
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(menu);
gtk_main();
return 0;
}
已使用 Glade 创建 XML 文件 example.glade。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="exercise">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label" translatable="yes">A window where stuff will happen.</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="menu">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">button2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
问题出在您的 Glade 文件的这两行中:
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
查看 gtk_widget_hide_on_delete()
的 manual page,我们看到:
Utility function; intended to be connected to the “delete-event” signal on a GtkWindow. The function calls gtk_widget_hide()
on its argument, then returns TRUE
.
如果我们查看 delete-event 信号,我们会看到:
Returns
TRUE
to stop other handlers from being invoked for the event. FALSE
to propagate the event further.
这意味着在调用 gtk_widget_hide_on_delete()
之后,返回 TRUE
,这将阻止 GTK 运行时调用 gtk_widget_show_all()
。
要实现你想要的,你可以使用自定义的处理程序,如下所示:
删除那两行并替换为以下内容:
<signal name="delete-event" handler="my_custom_func" object="menu" swapped="no"/>
将自定义处理程序添加到 C 文件:
G_MODULE_EXPORT gboolean
my_custom_func(GtkWidget *w, GdkEvent *e, gpointer u) {
gtk_widget_hide(w);
gtk_widget_show_all(GTK_WIDGET(u));
return TRUE;
}
问题
我有一个问题,通过 gtk_widget_hide_on_delete 关闭带有删除事件的小部件无法通过交换的 gtk_widget_show_all 再次显示菜单小部件,并将相应的小部件作为参数传递给它。
背景
我正在创建一个程序,其中包含一个带有多个按钮小部件的选择菜单。按一个按钮将隐藏菜单,并显示一个包含标签和 TextEntry 的 window 小部件,此 window 小部件的删除事件将隐藏该小部件,并再次显示菜单。
示例程序
我已经为这个问题创建了一个最小的例子。该代码只是通过 GtkBuilder
加载 ui,然后进入主 gtk 循环。
我依赖 gtk_widget_show_all
、gtk_widget_hide
和 gtk_widget_hide_on_delete
,但是当我使用 delete-event
关闭 练习小部件 时,window 消失,但菜单小部件未显示。
#include <gtk/gtk.h>
#include <stdio.h>
int main(int argc, char **argv)
{
GtkBuilder * builder;
GtkWidget * menu;
GError *error = NULL;
gtk_init(&argc, &argv);
builder = gtk_builder_new();
if (!gtk_builder_add_from_file(builder, "example.glade", &error)) {
g_warning("%s", error->message);
g_free(error);
fprintf(stderr, "Failed to load build file");
}
menu = (GtkWidget *) gtk_builder_get_object(builder, "menu");
gtk_builder_connect_signals(builder, NULL);
gtk_widget_show(menu);
gtk_main();
return 0;
}
已使用 Glade 创建 XML 文件 example.glade。
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="exercise">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
<child>
<object class="GtkGrid" id="grid2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="entry1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label" translatable="yes">A window where stuff will happen.</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkWindow" id="menu">
<property name="can_focus">False</property>
<property name="window_position">center</property>
<signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">button1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">button2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<signal name="clicked" handler="gtk_widget_hide" object="menu" swapped="yes"/>
<signal name="clicked" handler="gtk_widget_show_all" object="exercise" swapped="yes"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
问题出在您的 Glade 文件的这两行中:
<signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
<signal name="delete-event" handler="gtk_widget_show_all" object="menu" after="yes" swapped="yes"/>
查看 gtk_widget_hide_on_delete()
的 manual page,我们看到:
Utility function; intended to be connected to the “delete-event” signal on a GtkWindow. The function calls
gtk_widget_hide()
on its argument, then returnsTRUE
.
如果我们查看 delete-event 信号,我们会看到:
Returns
TRUE
to stop other handlers from being invoked for the event.FALSE
to propagate the event further.
这意味着在调用 gtk_widget_hide_on_delete()
之后,返回 TRUE
,这将阻止 GTK 运行时调用 gtk_widget_show_all()
。
要实现你想要的,你可以使用自定义的处理程序,如下所示:
删除那两行并替换为以下内容:
<signal name="delete-event" handler="my_custom_func" object="menu" swapped="no"/>
将自定义处理程序添加到 C 文件:
G_MODULE_EXPORT gboolean my_custom_func(GtkWidget *w, GdkEvent *e, gpointer u) { gtk_widget_hide(w); gtk_widget_show_all(GTK_WIDGET(u)); return TRUE; }