QTreeView/QTableView中利用QStandardItem实现复选框三种形态变化
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实现复选框三种形态变化的更多相关文章
- extjs 中动态给gridpanel 复选框赋值
最近在搞extjs时需要动态根据数据给gridpanel的复选框赋值 网上看了很多 ,多不行,最后找到一个好使的方法 如下: RBACformPanel.getSelectionModel().sel ...
- 关于netbeans中的JComboBox(复选框)
以最近写的选课系统中添加课程项为例 1.往复选框中放入选项(根据数据库添加) (1)首先将 属性—>model中默认Item1234清空 (2)获得数据库中的数据并放入. SelectCour ...
- 关于Unity中NGUI的Checkbox复选框、Slider滑动条和Button的6种触发回调事件的方式
Checkbox复选框 1.创建一个NGUI背景Sprite1节点 2.打开NGUI---->Open---->Prefab Toolbar---->选择一个复选框节点,拖拽到背景节 ...
- mui开发中获取单选按钮、复选框的值
js获取单选按钮的值 function getVals(){ var res = getRadioRes('rds'); if(res == null){mui.toast('请选择'); retur ...
- [原创]delphi一次性批量在TScrollBox中显示N个复选框TCheckBox的源码
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System ...
- Extjs3.4 grid中添加一列复选框
var sm = new Ext.grid.CheckboxSelectionModel(); var cm = new Ext.grid.ColumnModel( [ sm, new Ext.gri ...
- Qt之QTableView添加复选框(QAbstractTableModel)
简述 使用QTableView,经常会遇到复选框,要实现一个好的复选框,除了常规的功能外,还应注意以下几点: 三态:不选/半选/全选 自定义风格(样式) 下面我们介绍一下常见的实现方式: 编辑委托. ...
- Qt树形控件QTreeView使用1——节点的添加删除操作 复选框的设置
QtreeView是ui中最常用的控件,Qt中QTreeWidget比QTreeView更简单,但没有QTreeView那么灵活(QTreeWidget封装的和MFC的CTreeCtrl很类似,没有m ...
- 在php中验证复选框
PHP接收多个同名复选框信息不像ASP那样自动转换成为数组,这给使用带来了一定不便.但是还是有解决办法的,就是利用javascript做一下预处理.多个同名复选框在javascript中还是以数组的形 ...
随机推荐
- 洛谷 P1273 有线电视网(树形背包)
洛谷 P1273 有线电视网(树形背包) 干透一道题 题面:洛谷 P1273 本质就是个背包.这道题dp有点奇怪,最终答案并不是dp值,而是最后遍历寻找那个合法且最优的\(i\)作为答案.dp值存的是 ...
- Python开发:Windows下Python+Eclipse+Pydev开发环境配置
一.配置前的准备: 1.安装jdk: 下载地址: https://www.oracle.com/technetwork/java/javase/downloads/index.html 2.安装Ecl ...
- Jenkins 源代码编译
最近一直想写一个关于 Jenkins 管理的 InelliJ 插件,但是尝试很多次总是在登录认证上面失败,各种办法都不起作用,而且官方的文档含糊不清,就动起了从源代码编译在开发环境中进行调试. 废话少 ...
- Javascript之in操作符的用法
in操作符是js里面常用的一个操作符,下面是其几个常用的功能: 1.配合for语句循环遍历/迭代数组中的元素 2.配合for语句循环遍历/迭代集合中的属性 3.判断对象是否是数组的元素 4.判断对象是 ...
- javascript的JSON对象
JSON包含用于解析JSON(javascript object notation)的方法,将值转换成JSON.JSON不可以被调用或者用作构造函数. JSON对象保存在大括号内,JSON数组保存在中 ...
- web服务器/应用服务器
1.概念 Web服务器的基本功能就是提供Web信息浏览服务.它只需支持HTTP协议.HTML文档格式及URL.与客户端的网络浏览器配合.因为Web服务器主要支持的协议就是HTTP,所以通常情况下HTT ...
- 关于chrome浏览器事件拖动的bug(首次点击的时候也触发move的事件)
在做R80web的时候出现一个奇怪的现象,chorme现在的版本还是存在,拖动事件有mousedown.mousemove.mouseup组成,但是首次click以及失去焦点再重新点击的时候同样会触发 ...
- AutoMapper控件
1.下载AutoMapper控件. 2.定义类,实现Profile. 3.在定义类的构造方法中使用如下代码进行转换 // 1.匹配,o,t代表TDestination;s代表TSource,返回TDe ...
- elasticsearch 6.x 安装与注意
1. 下载,解压 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.4.tar.gztar -zx ...
- "类工厂模式"改写SqlHelper
看到标题您一定很疑惑,23种经典设计模式什么时候多了一个"类工厂模式",稍等,请听我慢慢道来. 实践是检验真理的唯一途径.最近用了"类工厂模式"改写了我公司的S ...