https://www.techieliang.com/2017/12/729/ 原文地址

using_checkbox_item.h

/**
* @file using_checkbox_item.h
* @brief 本文件包含支持复选框item类声明。
* @version 1.0.0.0
* @date 2017.12.18
* @author Techie亮
*/
#ifndef _H_USINGCHECKBOXITEM_
#define _H_USINGCHECKBOXITEM_
#include <QStandardItem>
#include <QString>
/**
* @brief 支持复选框item类
* 支持复选框三态转变-全选对勾、全不选空白、半选黑点
* 子类会自动通知父子节点item,若不符合设计需要可仿照此方式在model中的setDate重现
*/
class UsingCheckboxItem : public QStandardItem {
public:
/**
* @brief 构造函数
* @param item显示内容
*/
explicit UsingCheckboxItem(const QString &text);
/**
* @brief setData重写
* @param value data值
* @param role data类型
*/
virtual void setData(const QVariant &value, int role = Qt::UserRole + 1);
};
#endif // _H_USINGCHECKBOXITEM_

using_checkbox_item.cpp

#include "using_checkbox_item.h"
//构造函数
UsingCheckboxItem::UsingCheckboxItem(const QString &text)
: QStandardItem(text) {
setCheckable(true);
}
//setData重写
void UsingCheckboxItem::setData(const QVariant &value, int role) {
if(role == Qt::CheckStateRole) {//针对复选框变动做操作
Qt::CheckState check_state = (Qt::CheckState)value.toInt();
QString mtext=text();
switch (check_state) {
case Qt::Unchecked: {//取消
for(int i = 0, num = rowCount(); i < num; i++) {
child(i)->setData(Qt::Unchecked, Qt::CheckStateRole);
}
//修改内容-必须先修改自己再通知父节点
QStandardItem::setData(value,role);
//通知父节点,我取消了选择,直接告诉父节点半选即可
if(parent())parent()->setData(Qt::PartiallyChecked, role);
}
return;//此事件已完成直接return
case Qt::PartiallyChecked: {//半选
Qt::CheckState current_state = checkState();//当前状态
int checked_num = 0;//被选择的数量
int unchecked_num = 0;//未选择的数量
bool is_partially = false;
Qt::CheckState child_state;
int m_rowCount = rowCount();
//遍历所有子节点
for(int i = 0; i < m_rowCount; i++) {
child_state = child(i)->checkState();
//子节点半选,则直接半选
switch (child_state) {
case Qt::PartiallyChecked:is_partially = true;break;
case Qt::Unchecked:unchecked_num++;break;
case Qt::Checked:checked_num++;break;
default:checked_num++;break;
}
}
//根据子节点状态确定当前节点应该设置的状态
Qt::CheckState now_state;
if(is_partially)
now_state = Qt::PartiallyChecked;
else if(checked_num == m_rowCount)
now_state = Qt::Checked;
else if(unchecked_num == m_rowCount)
now_state = Qt::Unchecked;
else
now_state = Qt::PartiallyChecked;
//修改状态并通知父节点
if(current_state != now_state) {
//修改内容-必须先修改自己再通知父节点
QStandardItem::setData(now_state,role);
//通知父节点,我的状态更改,也就是父节点进入半选
if(parent())parent()->setData(Qt::PartiallyChecked, role);
}
}
return;//此事件已完成直接return
case Qt::Checked: {//全选
for(int i = 0, num = rowCount(); i < num; i++) {
child(i)->setData(Qt::Checked, Qt::CheckStateRole);
}
//修改内容-必须先修改自己再通知父节点
QStandardItem::setData(value,role);
//通知父节点,我被选了,也就是父节点进入半选
if(parent()) {
parent()->setData(Qt::PartiallyChecked, role);
}
}
return;//此事件已完成直接returndefault://如果出现此情况就是错了,可以加错误处理break;}}QStandardItem::setData(value,role);}

测试函数

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <qstandarditemmodel.h>
#include "using_checkbox_item.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow) {
ui->setupUi(this);
QStandardItemModel *m = new QStandardItemModel(this);
ui->treeView->setModel(m);
auto i1 = new UsingCheckboxItem("1");
auto i2 = new UsingCheckboxItem("2");
m->appendRow(i1);
m->appendRow(i2);
auto i11 = new UsingCheckboxItem("1-1");
auto i12 = new UsingCheckboxItem("1-2");
i1->appendRow(i11);
i1->appendRow(i12);
auto i111 = new UsingCheckboxItem("1-1-1");
auto i112 = new UsingCheckboxItem("1-1-2");
i11->appendRow(i111);
i11->appendRow(i112);
auto i121 = new UsingCheckboxItem("1-2-1");
auto i122 = new UsingCheckboxItem("1-2-2");
i12->appendRow(i121);
i12->appendRow(i122); auto i21 = new UsingCheckboxItem("2-1");
auto i22 = new UsingCheckboxItem("2-2");
i2->appendRow(i21);
i2->appendRow(i22);
auto i211 = new UsingCheckboxItem("2-1-1");
auto i212 = new UsingCheckboxItem("2-1-2");
i21->appendRow(i211);
i21->appendRow(i212);
auto i221 = new UsingCheckboxItem("2-2-1");
auto i222 = new UsingCheckboxItem("2-2-2");
i22->appendRow(i221);
i22->appendRow(i222);
}

说明

  • 重写了setData方法,但仅对CheckStateRole类型data做了操作,其余类型通过最后的QStandardItem::setData(value,role)直接使用默认方式
  • setData中每个case后均直接return,因为会根据value和父子类情况对实际要使用value做修改,最终赋值给QStandardItem::setData不一定是参数value,所以若不返回,必然会调用最后一样导致出错
  • 系统默认只有两个状态切换选中和补选中,所以可以借用这个特性,当一个节点状态修改时都通知其父类为PartiallyChecked部分选中状态,由父节点自行判断子节点情况并设置自身状态
  • 注意一定要先修改自身状态以后在通知父节点,否则在父节点函数运行过程中自身仍为未修改状态,会导致判断错误
  • 在PartiallyChecked的case中判断了一下新旧状态是否改变,若改变会向上一父节点继续传递消息,不改变则立刻停止减少运算量
  • 若子节点存在PartiallyChecked状态的,则当前节点一定为PartiallyChecked
  • 注意最顶级item是没有parent的所以想父节点传递消息前一定要判断parent是否为nullptr
  • 选择一个节点那么此节点一定会在全选-不选两个状态切换,而部分选择仅存在于此节点的子节点发生变动,所以全选-不选两个case直接对所有子节点赋值
 

QTreeView/QTableView中利用QStandardItem实现复选框三种形态变化的更多相关文章

  1. extjs 中动态给gridpanel 复选框赋值

    最近在搞extjs时需要动态根据数据给gridpanel的复选框赋值 网上看了很多 ,多不行,最后找到一个好使的方法 如下: RBACformPanel.getSelectionModel().sel ...

  2. 关于netbeans中的JComboBox(复选框)

    以最近写的选课系统中添加课程项为例 1.往复选框中放入选项(根据数据库添加) (1)首先将  属性—>model中默认Item1234清空 (2)获得数据库中的数据并放入. SelectCour ...

  3. 关于Unity中NGUI的Checkbox复选框、Slider滑动条和Button的6种触发回调事件的方式

    Checkbox复选框 1.创建一个NGUI背景Sprite1节点 2.打开NGUI---->Open---->Prefab Toolbar---->选择一个复选框节点,拖拽到背景节 ...

  4. mui开发中获取单选按钮、复选框的值

    js获取单选按钮的值 function getVals(){ var res = getRadioRes('rds'); if(res == null){mui.toast('请选择'); retur ...

  5. [原创]delphi一次性批量在TScrollBox中显示N个复选框TCheckBox的源码

    unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System ...

  6. Extjs3.4 grid中添加一列复选框

    var sm = new Ext.grid.CheckboxSelectionModel(); var cm = new Ext.grid.ColumnModel( [ sm, new Ext.gri ...

  7. Qt之QTableView添加复选框(QAbstractTableModel)

    简述 使用QTableView,经常会遇到复选框,要实现一个好的复选框,除了常规的功能外,还应注意以下几点: 三态:不选/半选/全选 自定义风格(样式) 下面我们介绍一下常见的实现方式: 编辑委托. ...

  8. Qt树形控件QTreeView使用1——节点的添加删除操作 复选框的设置

    QtreeView是ui中最常用的控件,Qt中QTreeWidget比QTreeView更简单,但没有QTreeView那么灵活(QTreeWidget封装的和MFC的CTreeCtrl很类似,没有m ...

  9. 在php中验证复选框

    PHP接收多个同名复选框信息不像ASP那样自动转换成为数组,这给使用带来了一定不便.但是还是有解决办法的,就是利用javascript做一下预处理.多个同名复选框在javascript中还是以数组的形 ...

随机推荐

  1. stark - 4 ⇲ 视图函数

    ✘  list_view 处理表格(默认是显示表结构的所有字段) 1 list_display = self.get_list_display() # 4.1处理表头 header_list = [] ...

  2. SVN无法读取cruuent修复方法

    解决方法:在网上百度和google了一大圈之后,终于得知是断电时current和txn-current文件没有写入当前最新版本号和最新版本的路径问题 当时非常抓狂,项目刷新一直为空. 1.先把curr ...

  3. 【Guava】基于guava的重试组件Guava-Retryer

    一.使用场景 在日常开发中,我们经常会遇到需要调用外部服务和接口的场景.外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失 ...

  4. linux 安装php bz2扩展

    折腾了半天,最大的坑就是我是用lnmp一键安装php环境,php7下面没有ext文件夹,有个include下面虽然有个ext 但是里面没有需要的bz2 也尝试去pecl  和 pear 上面去找  无 ...

  5. VMware里Ubuntu-14.04-desktop的VMware Tools安装图文详解

    不多说,直接上干货!    前期步骤,请见如下 VMware里Ubuntukylin-14.04-desktop的VMware Tools安装图文详解 我这里,直接,是来说明,Ubuntu-14.04 ...

  6. SpringMVC中配置AOP拦截controller 失效

    来源:http://www.oschina.net/question/222929_124314 目测大部分同学的aop失效都是因为在springmvc的配置文件里面扫描了类,那么spring去扫描的 ...

  7. tmux快捷键汇总(常用)

    会话外操作: tmux new -s <name-of-my-session> 在会话外创建一个新的会话 tmux ls 在会话外获取会话列表 tmux a(attach) -t < ...

  8. *2.3.3-加入monitor

    验证平台必须监测DUT的行为,只有知道DUT的输入输出信号变化之后,才能根据这些信号变化来判定DUT的行为是否正确. 验证平台中实现监测DUT行为的组件是monitor.driver负责把transa ...

  9. js 列表选择

    首选定义数组,然后进行操作时遍历数组获取选中值 function getSelect(userId) { //var userId = userCheckBox.value; //标记删除还是添加 v ...

  10. [转]Vue.js 目录结构

    本文转自:http://www.runoob.com/vue2/vue-directory-structure.html 上一章节中我们使用了 npm 安装项目,我们在 IDE(Eclipse.Ato ...