使用Glade& amp;将切换按钮绑定到彼此GTK +(C中)

时间:2018-01-16 14:24:06

标签: c gtk gtk3 glade

我有两个名为RUN和KILL的切换按钮。当我打开(即按下)RUN按钮时,我只希望通过按下KILL切换按钮来关闭它(而不是通过切换RUN按钮)。除非按下KILL按钮,否则我希望任何后续鼠标点击RUN按钮都不会执行任何操作。同样,当打开KILL按钮时,我只希望通过按下RUN按钮来关闭它(再次,不是通过切换KILL按钮)。我不确定如何构造将这两个切换按钮的动作绑定在一起的事件处理程序。我正在使用GTK +和Glade一起使用C编程。

1 个答案:

答案 0 :(得分:2)

由于GtkToggleButton是一个通用按钮,它将与所有用户交互切换,我们必须阻止它在某些条件下切换。在这种情况下,切换后的按钮不能再次自动切换,而是通过另一个切换按钮切换。要实现这一目标,您必须:

  1. 在某些条件下阻止按钮事件切换按钮
  2. 将两个按钮绑定为倒置逻辑(互斥)
  3. 要实现1)我们可以将回调连接到GtkWidget "button-press-event"信号并根据所需条件返回,其中TRUE阻止信号传播,否则为FALSE。

    然后,为了处理2),我们可以使用带有GtkToggleButton "active"标志的G_BINDING_INVERTED_BOOLEAN属性的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`
    

    输出应该是这样的:

    output

    切换按钮是互斥的,在激活时按下它们不会产生任何视觉效果。

    PS:假设没有键盘处理,否则我们必须处理这些信号并采取相应的行动。