GTK 的“toggled”信号在选择单选按钮时触发,但在此之前,它也会在取消选择先前选择的单选按钮时触发。
我正在使用一个使用单选按钮的 GUI,每个按钮代表一组实体。一对“切换”信号中的第一个触发了对 GUI 中其他字段的一些不需要的更新——我只想在新选择的按钮触发回调时发生更新。如何解决此信号并将回调函数限制为仅对选择而不是取消选择进行操作?我已经在我正在编码的类中考虑了一个标志变量,但也许有一种更被 GTK 认可的技术。
我不认为你只能得到选择信号,但你可以做其他事情。您可以编写信号处理程序,以便它获取被切换的按钮(假设您正在为多个按钮重用相同的处理程序)。然后你可以检查它的状态,看看它是被选中还是被取消选中。
你这样做的方法是连接一个适配器:
// 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);
});
// 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);
// ...
}
};
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_SelectedButton{nullptr};
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);
}