由于GtkToggleButton 是一个通用按钮,它会随着所有用户交互而切换,我们必须防止它在某些条件下切换。在这种情况下,切换后的按钮不能在其自身上再次切换,而是通过另一个切换按钮。为此,您必须:
- 防止按钮事件在特定条件下切换按钮
- 用反转逻辑绑定两个按钮(互斥)
要实现 1) 我们可以将回调连接到 GtkWidget "button-press-event" 信号并根据所需条件返回,TRUE 阻止信号传播,否则为 FALSE。
然后,为了处理 2),我们可以使用带有 G_BINDING_INVERTED_BOOLEAN 标志的 GtkToggleButton "active" 属性的 g_object_bind_property 来获得所需的行为。请注意,我们必须将其中一个设置为激活状态。
所以,一个简单的例子可以是:
#include <gtk/gtk.h>
gboolean on_toggle_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) {
return TRUE;
}
return FALSE;
}
void on_run_toggle_active(GObject *obj, GParamSpec *pspec, gpointer user_data) {
g_return_if_fail (user_data != NULL);
GtkLabel *label = GTK_LABEL(user_data);
GtkToggleButton *button = GTK_TOGGLE_BUTTON(obj);
if (gtk_toggle_button_get_active(button) == TRUE) {
gtk_label_set_text (label, "Running...");
} else {
gtk_label_set_text (label, "Idle");
}
}
gint main(gint argc, gchar **argv) {
GtkLabel *status;
GtkWindow *window;
GtkBuilder *builder;
GtkToggleButton *run_toggle;
GtkToggleButton *kill_toggle;
gtk_init(&argc, &argv);
builder = gtk_builder_new_from_file("gui.ui");
window = GTK_WINDOW(gtk_builder_get_object(builder, "window1"));
status = GTK_LABEL(gtk_builder_get_object(builder, "status"));
run_toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "toggle"));
kill_toggle = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "kill"));
g_object_bind_property (G_OBJECT(run_toggle), "active", G_OBJECT(kill_toggle), "active", G_BINDING_INVERT_BOOLEAN);
g_object_bind_property (G_OBJECT(kill_toggle), "active", G_OBJECT(run_toggle), "active", G_BINDING_INVERT_BOOLEAN);
g_signal_connect(G_OBJECT(run_toggle), "button-press-event", G_CALLBACK(on_toggle_button_press_event), NULL);
g_signal_connect(G_OBJECT(kill_toggle), "button-press-event", G_CALLBACK(on_toggle_button_press_event), NULL);
g_signal_connect(G_OBJECT(run_toggle), "notify::active", G_CALLBACK(on_run_toggle_active), status);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(GTK_WIDGET(window));
gtk_main();
return 0;
}
为简化起见,我使用 glade (gui.ui) 概述了用户界面:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.18"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="row_spacing">20</property>
<child>
<object class="GtkLabel" id="status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Idle</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToggleButton" id="toggle">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">media-playback-start-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Run</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="kill">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="active">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">3</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">user-trash-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Kill</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
<object class="GtkSizeGroup">
<widgets>
<widget name="label1"/>
<widget name="label2"/>
</widgets>
</object>
</interface>
编译:
gcc -o main main.c `pkg-config --cflags --libs gtk+-3.0`
输出应该是这样的:
切换按钮是互斥的,在激活时按下它们不会有任何视觉效果。
PS:假设没有键盘处理,否则我们必须处理这些信号并采取相应的行动。