仅在选中时读取 GTK 单选按钮信号

Posted

技术标签:

【中文标题】仅在选中时读取 GTK 单选按钮信号【英文标题】:Read GTK Radio Button signal only when selected 【发布时间】:2012-11-14 18:31:19 【问题描述】:

GTK 的“toggled”信号在选择单选按钮时触发,但在此之前,它也会在取消选择之前选择的单选按钮时触发。

我正在使用一个使用单选按钮的 GUI,每个按钮代表一组实体。一对“切换”信号中的第一个触发了对 GUI 中其他字段的一些不需要的更新——我只想在新选择的按钮触发回调时发生更新。如何解决此信号并将回调函数限制为仅对选择而不是取消选择进行操作?我已经在我正在编码的类中考虑了一个标志变量,但也许还有一种更被 GTK 认可的技术。

【问题讨论】:

【参考方案1】:

我认为您不能获得选择信号,但您可以做其他事情。您可以编写信号处理程序,以便它获取被切换的按钮(假设您对多个按钮重用相同的处理程序)。然后你可以检查它的状态,看看它是被选中还是被取消选中。

你这样做的方法是连接一个适配器:

// 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
   )
);

在你的类中,handle_button_toggled 包含按钮参数:

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

在 C++11 中,您也可以使用 lambda 表达式:

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

【讨论】:

我是否认为这也可以通过连接activated 信号而不是toggled 信号来实现?【参考方案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::RadioButtonrb_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);
    // ...
  

;

【讨论】:

【参考方案3】:
This is a demo code using Radio Buttons, where you can find how I find which radio button is selected:
#include <gtkmm/window.h>
#include <gtkmm/box.h>
#include <gtkmm/radiobutton.h>
#include <gtkmm/separator.h>
#include <gtkmm/application.h>
#include <iostream>

class ButtonWindow : public Gtk::Window

private:
   //Child widgets:
   Gtk::Box m_Box_Top, m_Box1, m_Box2;
   Gtk::RadioButton m_RadioButton1, m_RadioButton2, m_RadioButton3;
   Gtk::Separator m_Separator;
   Gtk::Button m_Button_Close;
   Gtk::RadioButton *m_SelectedButtonnullptr;

public:
   ButtonWindow()
      : m_Box_Top(Gtk::ORIENTATION_VERTICAL),
        m_Box1(Gtk::ORIENTATION_VERTICAL, 15),
        m_Box2(Gtk::ORIENTATION_VERTICAL, 0),
        m_RadioButton1("button 1"),
        m_RadioButton2("button 2"),
        m_RadioButton3("button 3"),
        m_Button_Close("close")
   
      // Set title and border of the window
      set_title("radio buttons");
      set_border_width(0);

      // Put radio buttons 2 and 3 in the same group as 1:
      m_RadioButton2.join_group(m_RadioButton1);
      m_RadioButton3.join_group(m_RadioButton1);

      // Add outer box to the window (because the window
      // can only contain a single widget)
      add(m_Box_Top);

      //Put the inner boxes and the separator in the outer box:
      m_Box_Top.pack_start(m_Box1);
      m_Box_Top.pack_start(m_Separator);
      m_Box_Top.pack_start(m_Box2);

      // Set the inner boxes' borders
      m_Box1.set_border_width(20);
      m_Box2.set_border_width(10);

      // Put the radio buttons in Box1:
      m_Box1.pack_start(m_RadioButton1);
      m_Box1.pack_start(m_RadioButton2);
      m_Box1.pack_start(m_RadioButton3);

      // Put Close button in Box2:
      m_Box2.pack_start(m_Button_Close);

      // Connect the button signals:
#if 1 // C++11: (change this to #if 0 to use the traditional way)
      m_RadioButton1.signal_clicked().connect([&]on_radio_button_clicked(m_RadioButton1););
      m_RadioButton2.signal_clicked().connect([&]on_radio_button_clicked(m_RadioButton2););
      m_RadioButton3.signal_clicked().connect([&]on_radio_button_clicked(m_RadioButton3););

      m_Button_Close.signal_clicked().connect([&]on_close_button_clicked(););
#else // Traditional:
  m_RadioButton1.signal_clicked() // Full sigc
     .connect(sigc::bind(sigc::mem_fun(*this, &ButtonWindow::on_radio_button_clicked),
                         sigc::ref(m_RadioButton1)));

  m_RadioButton2.signal_clicked() // sigc && C++98
     .connect(std::bind(sigc::mem_fun(*this, &ButtonWindow::on_radio_button_clicked),
                        std::ref(m_RadioButton2)));

  m_RadioButton3.signal_clicked() // Full C++98
     .connect(std::bind(&ButtonWindow::on_radio_button_clicked, this,
                        std::ref(m_RadioButton3)));

      m_Button_Close.signal_clicked()
         .connect(sigc::mem_fun(*this, &ButtonWindow::on_close_button_clicked));
#endif

      // Set the second button active:
      m_RadioButton2.set_active();

      // Make the close button the default widget:
      m_Button_Close.set_can_default();
      m_Button_Close.grab_default();

      // Show all children of the window:
      show_all_children();
   
  
protected:
   //Signal handlers:
   void on_radio_button_clicked(Gtk::RadioButton& button)
   
      if(m_SelectedButton != &button && button.get_active())
      
         m_SelectedButton = &button;
         std::cout << "Radio "<< m_SelectedButton->get_label() << " selected.\n";
      
   

   void on_close_button_clicked()
   
      hide(); // Close the application
   
;

int main(int argc, char *argv[])

   auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

   ButtonWindow button;

   //Shows the window and returns when it is closed.
   return app->run(button);

【讨论】:

您能否澄清一下这如何解决所提出的问题? 是的,先生,我在第一行中添加了该示例显示我如何找到选择了哪个单选按钮。在回复您时,我现在意识到我使用的是 gtkmm 而不是 gtk+,因为问题可能会问。如果是这样的话,我认为这段代码无论如何都是有用的。 我还想澄清一下,我编写了不同的方法来连接信号。第一个是我在 C++11 中的做法。您可以使用#if 1 来选择它,如果您将if 更改为#if 0,您将获得gtkmm 手册中解释的表格。但是,在这种情况下,我还编写了三个替代方案来编写信号。

以上是关于仅在选中时读取 GTK 单选按钮信号的主要内容,如果未能解决你的问题,请参考以下文章

单选按钮仅在提交时返回“on”

如何检查“单选按钮”是不是被选中?

当内容包含在流布局中时,如何将单选按钮或复选框及其标签保持在一起

Foreach 仅在选中时才选择第一个复选框

如何链接一组切换按钮,如单选按钮?

多个单选按钮选择