功能需求描述:要求制作一个自定义控件CheckBoxList,控件中有N个复选框QCheckBox,当任何一个复选框反转时,该控件发出信号,信号指示出:此时哪几个复选框处于选中状态。
解决方案:显示出一列复选框,用QListWidget来干最合适了,默认情况下QListWidget添加的条目item是纯文字,而这里我们要求添加的条目是复选框。
同理,也可以使用树形控件QTreeWidget、表格控件QTableWidget来组织自定义控件。本文仅以列表形组织为例了:
UI设计界面、把它应用在别的程序中的运行效果,分别如下所示:
为了使这个自定义控件更加好用,还添加了全选、全不选、正则筛选等功能,这些功能都没什么难度。最关键的部分是要搞懂如何在QListWidget里面添加QCheckBox。
其实也简单,在ui中拖出一个或者用代码new一个QListWidget,然后在窗口的构造函数中对QListWidget添加条目即可:
for(int i = 0; i < cnt; i++)
{
QListWidgetItem *item = new QListWidgetItem();
QCheckBox *checkBox= new QCheckBox ();
ui->listWidget->addItem(item);//在ListWidget中添加一个条目
ui->listWidget->setItemWidget(item, checkBox);//在这个条目中放置CheckBox
icheckBox->setText(QString("checkBox_%1").arg(i));
//把所有checkBox的信号都引向同一个槽
connect(checkBox, SIGNAL(stateChanged(int)), this, SLOT(anyStateChanged()));
}
/*任何一个checkBox被点击时,共同的槽函数*/
void XXXXX::anyStateChanged()
{
//qDebug() << "one checkBox State Changed";
selectedItems.clear();
//遍历所有的CheckBox,把所有选中的CheckBox索引号都记录到QStringList selectedItems中
for(int i = 0; i < ui->listWidget->count(); i++)
{
QListWidgetItem *item = ui->listWidget->item(idx);//先获取QListWidgetItem
QCheckBox *checkBox = static_cast<QCheckBox *>(ui->listWidget->itemWidget(item));//找到第i个Item对应的CheckBox
if(checkBox->isChecked())
selectedItems.append(i);
}
}
需要注意的是,任何一个CheckBox被点击都会触发anyStateChanged()这个槽函数,进行遍历所有CheckBox,如果用户点击了全选,那岂不是在一瞬间要遍历N多遍,这样做太低效,我的做法是,点击全选或者全不选时,用disConnect解除Click信号与anyStateChanged()槽的connect,然后自己构建编号的List并emit出去,然后再重新connect他们。
注意上面的ui->listWidget->setItemWidget(item, checkBox),其实我们不仅能向QLishWidget里面放置CheckBox,任何QWidget都可以放,我们可以自定义一个QWidget,里面包含好几个基本控件,然后把这个含有多个基本控件的自定义的Widget一并放到QLishWidget的每一个item里去。
我的一个项目的应用场景中,不仅要支持多选,还要实时显示每一项的数值,效果如下:
代码已上传到CSDN,下载链接见评论
-----------------------2020.10.15后记---------------------------
突然发现一个QButtonGroup类,用这个类可以大幅简化上述工作,这个组只是一个逻辑组,不会在界面上产生效果。
大体思路就是,把任意按钮(包括普通按钮、单选按钮、复选按钮等都可以)加入这个组,然后组内任何一个按钮被点击时,QButtonGroup会有信号指示出,是组内哪个按钮发生了动作。