Read GTK Radio Button signal only when selected

2019-07-29 21:42发布

问题:

GTK's "toggled" signal fires when a radio button is selected, but before that, it also fires upon deselection of the previously selected radio button.

I am working with a GUI that uses radio buttons, each representing a group of entities. The first of the pair of "toggled" signals is triggering some unwanted updates to other fields in the GUI -- updates that I only want to happen when the newly selected button triggers the callback. How do I work around this signal and limit the callback function to only operate on selection instead of deselection? I've considered a flag variable within the class I'm coding, but perhaps there is a more GTK-approved technique.

回答1:

I don't think you can only get selection signals, but you can do something else. You can write your signal handler so it gets the button that was toggled (assuming you are reusing the same handler for several buttons). Then you can check its state to see if it was selected or deselected.

The way you do this is to connect with an adapter:

// do this for each button (this one is for "buttona"):
buttona.signal_toggled().connect(
   sigc::bind(
      sigc::mem_fun(*this, &myclass::handle_button_toggled),
      buttona
   )
);

In your class, handle_button_toggled includes the button parameter:

myclass {
  Gtk::ToggleButton buttona, buttonb, ...
  ....
  void handle_button_toggled(Gtk::ToggleButton &b) {
   ...check state of b ...
  }
}

In C++11, you can alternatively use a lambda expression:

buttona.signal_toggled().connect([this,&buttona]{
  handled_button_toggled(buttona); 
});


回答2:

// C++11
#include <gtkmm.h>
#include <iostream>
#include <vector>

using namespace std;

class RadioBox
{
public:
    Gtk::Box                     {Gtk::ORIENTATION_HORIZONTAL};
    vector<Gtk::RadioButton*>    rb_list;
    string                       selected_text;
    int                          selected_pos;

    RadioBox(int defpos,
             std::initializer_list<string> rb_name)
    {
        add(box);
        int i = 0;
        for (auto& rb_name_i : rb_name) {
          Gtk::RadioButton* rb  = new Gtk::RadioButton{rb_name_i};
          rb_list.push_back(rb);
          if (i==defpos) {
            rb->set_active();
          }
          box.pack_start(*rb, 0, 0);
          if (i != 0) {
            rb->join_group(*rb_list[0]);
          }
          rb->signal_toggled().connect(
            sigc::bind(
              sigc::mem_fun(*this, &LabRadio::clicked),
              rb,
              i
            ));
          i++;
        }
    }

    void clicked(Gtk::RadioButton* rb, int pos) {
       if (!rb) return;
       if (rb->get_active()) {
         selected_pos  = pos;
         selected_text = rb->get_label().c_str();
         cout << "RadioButton:selected"
              << " pos:" << selected_pos
              << " text:" << selected_text
              << "\n";
       }
    }

    ~RadioBox() {
        rb_count = rb_list.size();
        for(int i=0; i < rb_count; ++i) {
          if (rb_list[i]) delete rb_list[i];
        }
    }

};


//USAGE:

class mywindow : public Gtk::Window {
  public:
    RadioBox myradiobox {2, {"Apples", "Pears", "Oranges", "Peaches"}};

  // ... your code here

  mywindow() {
    // ...
    <somewidget>.pack_start(myradiobox.box);
    // ...
  }

};


标签: gtk gtkmm