这是我的符号定义:
auto box1=new QCheckBox;
box1->setText("choice1");
auto box2=new QCheckBox;
box2->setText("choice2")
QPushButton* button=new QPushButton;
connect(button,&QPushButton::clicked,this,&Widget::onClicked);
auto group=new QButtonGroup;
group->setExclusive(false);
group->addButton(box1);
group->addButton(box2);
void Widget::onClicked()
{
std::for_each(group->buttons().begin(),group->buttons().end(),[](QAbstractButton* button){
button->setChecked(!button->isChecked());
});
/*
QList<QAbstractButton *> buttons=group->buttons();
std::for_each(buttons.begin(),buttons.end(),[](QAbstract* button){
button->setChecked(!button->isChecked());
});
*/
}
buttons()
调用将返回QList<QAbstractButton *>
。
我尝试使用
onClicked
插槽来迭代列表并执行某些操作。
如果我添加未注释的代码部分,程序就会崩溃。我调试了一下,发现循环了三次,但实际上只添加了两个元素,第三次循环就会导致程序崩溃。
如果我删除注释掉的代码段,它就可以工作。
我想知道为什么第一种写法,即没有注释掉的代码,会导致错误。
正如我在评论中解释的那样(我自己没有检查过,但得到了 @musicamente 的确认),
std::for_each(group->buttons().begin(), group->buttons().end(), [...])
创建了 2 个单独的列表(通过复制构造),其中 end()
迭代器是不同的;重要的是,您无法从前者的 end()
迭代器到达后者的 begin()
迭代器,这会导致 std::for_each
不断循环到末尾。
使用基于范围的循环就不会出现此问题(这更容易阅读顶部)。当我这样做时,我将使用
toggle
方法来切换复选框的选中状态:
void Widget::onClicked()
{
for (auto checkbox: group->buttons())
button->toggle();
}
在一个单独的说明中,除非您有特定的原因按照您在问题中提出的方式执行此操作,例如下面@musicamente的评论(但即便如此,我宁愿每次在运行时创建一个新复选框时都创建一个连接-删除对象时自动断开连接),将按钮连接到许多复选框的正确方法是:
[...]
QPushButton* button=new QPushButton;
auto group=new QButtonGroup;
group->setExclusive(false);
group->addButton(box1);
group->addButton(box2);
for (auto checkbox : group->buttons())
QObject::connect(button, &QAbstractButton::clicked, checkbox, &QAbstractButton::toggle);
这样可以节省声明
void Widget::onClicked()
。取决于
Widget
类的其余部分,它甚至可以在没有 group
的情况下工作,以这种方式:
[...]
QPushButton* button=new QPushButton;
for (auto checkbox : findChildren<QCheckBox>(QString()))
QObject::connect(button, &QAbstractButton::clicked, checkbox, &QAbstractButton::toggle);