QT QTableView添加CheckBox

news2024/12/25 8:50:30

需求:QTableView中指定列所有Item均为CheckBox项,要求CheckBox居中显示
显示效果如下:三种表现效果

 实现方式:
  1. 系统控件QCheckBox
  2. 自绘制CheckBox
  3. CheckBox的图片
实现代码:(原理:利用委托自绘的方式)
CheckBoxDelegate
#ifndef CHECKBOXDELETAGE_H
#define CHECKBOXDELETAGE_H

#include <QStyledItemDelegate>

class QPixmap;
class CheckBoxDelegate : public QStyledItemDelegate
{
    Q_OBJECT

public:
    enum class CheckBoxPaintType : quint8
    {
        SysControl  = 0, // 系统控件
        OwnerDraw   = 1, // 自绘CheckBox
        DrawImage   = 2, // 绘制图片
    };

public:
    explicit CheckBoxDelegate(CheckBoxPaintType type = CheckBoxPaintType::SysControl, QWidget *parent = nullptr);
    ~CheckBoxDelegate();

    void initCheckBoxPixmaps(CheckBoxPaintType type);
    void initCheckBoxPixmapBySysControl(const QString& key, bool checked);
    void initCheckBoxPixmapByOwnerDraw(const QString& key, bool checked);
    void initCheckBoxPixmapByDrawImage(const QString& key, bool checked);

    // 虚函数
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;

signals:

private:
    QPixmap* mCheckedPix = nullptr;
    QPixmap* mUnCheckedPix = nullptr;
};

#endif // CHECKBOXDELETAGE_H
#include "checkboxdeletage.h"
#include <QCheckBox>
#include <QApplication>
#include <QMouseEvent>
#include <QPixmapCache>
#include <QPainter>

CheckBoxDelegate::CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType type, QWidget *parent)
    : QStyledItemDelegate(parent)
{
    initCheckBoxPixmaps(type);
}

CheckBoxDelegate::~CheckBoxDelegate()
{
    delete mCheckedPix;
    delete mUnCheckedPix;
}

void CheckBoxDelegate::initCheckBoxPixmaps(CheckBoxDelegate::CheckBoxPaintType type)
{
    switch (type)
    {
    case CheckBoxPaintType::SysControl:
        initCheckBoxPixmapBySysControl("checked", true);
        initCheckBoxPixmapBySysControl("unchecked", false);
        break;
    case CheckBoxPaintType::OwnerDraw:
        initCheckBoxPixmapByOwnerDraw("checked", true);
        initCheckBoxPixmapByOwnerDraw("unchecked", false);
        break;
    case CheckBoxPaintType::DrawImage:
        initCheckBoxPixmapByDrawImage("checked", true);
        initCheckBoxPixmapByDrawImage("unchecked", false);
        break;
    default:
        break;
    }
}

void CheckBoxDelegate::initCheckBoxPixmapBySysControl(const QString &key, bool checked)
{
    QPixmap* pix = new QPixmap(13,13);
    QPainter painter(pix);

    QStyleOptionToolButton style;
    style.iconSize = QSize(13, 13);
    style.state = checked ? QStyle::State_On : QStyle::State_Off;
    style.state |= QStyle::State_Enabled;
    style.rect = QRect(0,0, 13,13);
    QCheckBox box;
    QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &style, &painter, &box);

    if (checked)
        mCheckedPix = pix;
    else
        mUnCheckedPix = pix;
}

void CheckBoxDelegate::initCheckBoxPixmapByOwnerDraw(const QString &key, bool checked)
{
    QPixmap* pix = new QPixmap(13,13);
    QPainter painter(pix);
    painter.setPen(QColorConstants::Green);

    QRect rect(0,0,13,13);
    // 抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setBrush(QBrush(QColorConstants::White));
    painter.drawRect(rect);

    if (checked)
    {
        QPointF points[3] = {
            QPointF(rect.x() + rect.width() * 2 / 11, rect.y() + rect.height() * 6 / 11),
            QPointF(rect.x() + rect.width() * 4 / 11, rect.y() + rect.height() * 8 / 11),
            QPointF(rect.x() + rect.width() * 9 / 11, rect.y() + rect.height() * 3 / 11),
        };

        painter.setPen(QPen(QBrush(QColorConstants::Green),2));
        painter.drawPolyline(points, 3);
    }

    if (checked)
        mCheckedPix = pix;
    else
        mUnCheckedPix = pix;
    // 也可直接放入QPixmapCache中去,此处就简单处理更高效些
    //QPixmapCache::insert(key, pix);
}

void CheckBoxDelegate::initCheckBoxPixmapByDrawImage(const QString &key, bool checked)
{
    QPixmap* pix = new QPixmap(checked ? ":/image/checked.png" : ":/image/unchecked.png");

    if (checked)
        mCheckedPix = pix;
    else
        mUnCheckedPix = pix;
}


void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionViewItem viewOption(option);
    initStyleOption(&viewOption, index);
    if (viewOption.state.testFlag(QStyle::State_HasFocus))
        viewOption.state ^= QStyle::State_HasFocus;

    QStyledItemDelegate::paint(painter, option, index);

    bool checked = index.data(Qt::UserRole).toBool();

    QPixmap* pix = checked? mCheckedPix : mUnCheckedPix;
    if (pix)
    {
        // 居中显示
        QRect rect = pix->rect();
        int offsetX = option.rect.width() / 2 - rect.width() / 2;
        int offsetY = option.rect.height() / 2 - rect.height() / 2;
        rect.translate(option.rect.x() + offsetX, option.rect.y() + offsetY);
        painter->drawPixmap(rect, *pix);
    }
}

bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick)
    {
        // 鼠标单双击切换选中状态
        QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
        if (option.rect.contains(mouseEvent->pos()))
        {
            model->setData(index, !model->data(index, Qt::UserRole).toBool(), Qt::UserRole);
        }
    }
    return QStyledItemDelegate::editorEvent(event, model, option, index);
}
使用:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTabWidget>
#include <QSplitter>
#include <QTableView>
#include <QStandardItemModel>
#include "checkboxdeletage.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QTabWidget* tabWidget = new QTabWidget(this);
    QSplitter* splitter = new QSplitter(Qt::Orientation::Horizontal, this);

    QTableView* tableView = new QTableView(this);

    QStandardItemModel* model = new QStandardItemModel(2,3,this);
    tableView->setModel(model);

    tableView->setItemDelegateForColumn(0, new CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType::SysControl, this));
    tableView->setItemDelegateForColumn(1, new CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType::OwnerDraw, this));
    tableView->setItemDelegateForColumn(2, new CheckBoxDelegate(CheckBoxDelegate::CheckBoxPaintType::DrawImage, this));
    // 不可编辑
    tableView->setEditTriggers(QAbstractItemView::EditTrigger::NoEditTriggers);
    // 整行选中
    tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    // 多行可选
    tableView->setSelectionMode(QAbstractItemView::SelectionMode::ExtendedSelection);

    splitter->addWidget(tableView);
    tabWidget->addTab(splitter, "CheckBox");

    setCentralWidget(tabWidget);
}

MainWindow::~MainWindow()
{
    delete ui;
}

QTableView如果实现指定项不可编辑状态方法:
  1. 重写Model的虚函数flags,指定index下的item的flags去除Qt::ItemIsEditable标志
  2. 重写DelegatecreateEditor,实现返回空的editor即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/761166.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FasterViT实战:使用FasterViT实现图像分类任务(一)

文章目录 摘要安装包安装timm安装 grad-cam 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集 摘要 论文翻译&#xff1a;https://blog.csdn.net/m0_47867638/article/details/131542132 官方源码&#xff1a;https://github.com/NVlabs/FasterViT 这是一篇来自英伟…

Flask_使用flask_marshmallow序列化数据

代码如下&#xff1a; from flask import Flask from flask_marshmallow import Marshmallow from flask_sqlalchemy import SQLAlchemy from marshmallow import fieldsapp Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] "mysqlpymysql://root:12…

JavaFx 用户界面控件2——ListView

1.列表显示ListView 下面是一个JavaFX ListView的示例代码和使用方法&#xff1a; public class ListViewExample extends Application {Overridepublic void start(Stage primaryStage) {// 创建一个可观察的列表&#xff0c;用于存储ListView中的数据ObservableList<Str…

【深度学习笔记】正则化与 Dropout

本专栏是网易云课堂人工智能课程《神经网络与深度学习》的学习笔记&#xff0c;视频由网易云课堂与 deeplearning.ai 联合出品&#xff0c;主讲人是吴恩达 Andrew Ng 教授。感兴趣的网友可以观看网易云课堂的视频进行深入学习&#xff0c;视频的链接如下&#xff1a; 神经网络和…

如何手动初始化项目目录结构,并在命令行用gradle编译运行项目

父目录 Android 开发入门 - wuyujin1997 文章目录 Intro纯手动手动创建项目目录结构源码gradle tasksgradle wrapper执行前&#xff1a;执行后&#xff1a;执行前后对比&#xff1a; gradle wrappergradlew 和 gradlew.batplugin java编译Java项目【重点】如何通过 gradle run …

【GAMES202】Real-Time Shadows1—实时阴影1

一、Shadow Mapping回顾 [计算机图形学]光线追踪前瞻&#xff1a;阴影图(前瞻预习/复习回顾)__Yhisken的博客-CSDN博客 关于Shadow Mapping我们在GAMES101中学过&#xff0c;如果不知道可以参考我的博客。 Shadow Mapping是光栅化时为了实现阴影的一种算法&#xff0c;而它实…

python将dataframe数据导入MySQL

文章目录 mysql操作pymysql操作导入数据并启动使用pandas导入MySQL数据库连接引擎使用to_sql方法pandas读取sqlread_sql_tableread_sql_query mysql操作 创建数据库test和table create database test;CREATE TABLE car (文章ID int, 链接 VARCHAR(255), 标题 VARCHAR(255),发…

ts中setState的类型

两种方法: 例子: 父组件 const [value, setValue] useState(); <ChildsetValue{setValue} />子组件 interface Ipros {setValue: (value: string) > void } const Child: React.FC<Ipros> (props) > {}

应用层协议设计及ProtoBuf

文章目录 一、协议概述二、消息的完整性三、协议设计3.1 协议设计实例IM即时通讯的协议设计nginx协议HTTP协议redis协议 3.2 序列化方法3.3 协议安全3.4 协议压缩3.5 协议升级 四、Protobuf4.1 安装编译4.2 工作流程4.3 标量数值类型4.4 编码原理4.4.1 Varints 编码4.4.2 Zigza…

soci源码解析

结构 use_type into_type statement backend 针对不同数据库后端的抽象 session

vue对象复制(使用es6对象扩展运算符,深拷贝)

vue3es6语法 直接上代码 const objA { name: 小飞, age: 18 };const objACopy { ...objA };console.log(对比objA与objACopy的引用地址是否相同);console.log(objA objACopy); //falseconsole.log(objA);console.log(objACopy);//对象包含对象&#xff0c;浅拷贝const objB …

pytorch cv自带预训练模型再微调

参考&#xff1a; https://pytorch.org/docs/0.4.1/torchvision/models.html https://zhuanlan.zhihu.com/p/436574436 https://blog.csdn.net/u014297502/article/details/125884141 Network Top-1 error Top-5 error AlexNet 43.45 20.91 VGG-11 30.98 11.37 VGG-13 30.07 …

动态规划完全背包之518零钱兑换 II

题目&#xff1a; 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 …

【Kafka中间件】ubuntu 部署kafka,实现Django生产和消费

原文作者&#xff1a;我辈李想 版权声明&#xff1a;文章原创&#xff0c;转载时请务必加上原文超链接、作者信息和本声明。 文章目录 前言一、Kafka安装1.下载并安装Java2.下载和解压 Kafka3.配置 Kafka4.启动 Kafka5.创建主题和生产者/消费者6.发布和订阅消息 二、KafkaDjang…

红黑树底层原理【白话版】

一、红黑树——特殊的平衡二叉搜索树 定义&#xff1a;红黑树是一种特殊的平衡二叉搜索树。我们用它来排列数据&#xff0c;并方便以后快速检索数据。 估计看到这句话&#xff0c;你就崩溃了&#xff0c;因为这话说了等于没说。 先观察这个图。 球要不是黑色&#xff0c;要不…

console的奇妙用法

console的奇妙用法 console.log是调试 JavaScript 代码的最佳方法之一。但是本文将介绍几个与console交互的更好方法。 在vscode或者的其他ide中输入console可以看到里边提供了非常多的方法。 虽然我们通常都是用console.log&#xff0c;但是使用其他可以使调试过程变得更加容…

分布式链路追踪

文章目录 1、背景2、微服务架构下的问题3、链路追踪4、核心概念5、技术选型对比6、zipkin 1、背景 随着互联网业务快速扩展&#xff0c;软件架构也日益变得复杂&#xff0c;为了适应海量用户高并发请求&#xff0c;系统中越来越多的组件开始走向分布式化&#xff0c;如单体架构…

流水灯——FPGA

文章目录 前言一、流水灯介绍二、系统设计1.模块框图2.RTL视图 三、源码四、效果五、总结六、参考资料 前言 环境&#xff1a; 1、Quartus18.0 2、vscode 3、板子型号&#xff1a;EP4CE6F17C8 要求&#xff1a; 每隔0.2s循环亮起LED灯 一、流水灯介绍 从LED0开始亮起到LED3又回…

如何定制自己的应用层协议?|面向字节流|字节流如何解决黏包问题?如何将字节流分成数据报?

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量干货博客汇总https://blog.csdn.net/yu_cblog/c…

基于ssm的社区生活超市的设计与实现

博主介绍&#xff1a;专注于Java技术领域和毕业项目实战。专注于计算机毕设开发、定制、文档编写指导等&#xff0c;对软件开发具有浓厚的兴趣&#xff0c;工作之余喜欢钻研技术&#xff0c;关注IT技术的发展趋势&#xff0c;感谢大家的关注与支持。 技术交流和部署相关看文章…