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. PHP队列的实现 算法

    <?php /** * php队列算法 * * Create On 2010-6-4 * Author Been * QQ:281443751 * Email:binbin1129@126.co ...

  2. kubernetes pod termination pending

    在将k8s从1.7.9 升级到1.10.2 之后,发现删除pod一直处于terminating状态, 调查发现删不掉的pod都有一个特点就是pod yaml中command部分写错了,如下所示: ap ...

  3. SQL LIKE 通配符随笔

    通配符 说明 _    与任意单字符匹配 %    与包含一个或多个字符的字符串匹配 [ ]  与特定范围(例如,[a-f])或特定集(例如,[abcdef])中的任意单字符匹配. [^]  与特定范 ...

  4. codeblocks中文编码问题

    其实这是老调重弹的问题了,在windows下面出现中文乱码大多都是编码格式的问题不一致的问题,最简单的就是uft-8和gbk冲突的问题.如果一个文件本来是以utf-8存的,但是以gbk打开,当然会出现 ...

  5. Numpy API

    Numpy API 矩阵操作 np.squeeze(mat): 将mat降维 np.linalg.norm(x, axis=1, keepdims=True): keepdim=True是防止出现sh ...

  6. git hub 建立公钥

    1.  执行 $ eval "$(ssh-agent -s)" 2. 增加 ssh $ ssh-add ~/.ssh/id_rsa 3. 复制 生成的key (执行下面命令后就相当 ...

  7. Linux下如何查看版本信息(转)

    Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等等,整个CPU信息一目了然.   1.# uname -a   (Linux查看版本当前操作系统内核信息)   L ...

  8. JavaScript ES6 Symbol.hasInstance的理解。

    Symbol.hasInstance 本案例是结合阮一峰老师的ECMAScript 6 入门丛书进一步的详细介绍,和对Symbol.hasInstance的理解.本着互联网的精神,分享给大家. 对象的 ...

  9. PHP项目学习1

    最近在学习PHP,看了<轻松学PHP>,2天看完,学习了很多基础知识,可是没有出什么成果.然后看<PHP项目开发全程实录>,里面讲到一个online影视365网,刚好有一个朋友 ...

  10. 对自写的Asp.Net分页控件的应用方式(异步无刷新分页)

    前台代码 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" co ...