【QT常用技术讲解】QTableView添加QCheckBox、QPushButton

news2024/12/28 22:10:27

前言

        QT展示列表信息的时候通常用到列表(比如用户信息、机构信息、设备信息等菜单),当需要对某列进行修改、删除操作时,就需要加入按钮(QPushButton),当需要对多列进行右键菜单操作时,就需要加入QCheckBox和右键菜单功能,本篇即围绕QTableView、QCheckBox、QPushButton,以及右键菜单进行讲解。

功能显示效果图

功能讲解

1、创建QTableView

(1)创建QTableView列表头

//两种方式创建列表头
    //1、在UI中之间添加
    //2、组装QStringList,调用setHorizontalHeaderLabels方法加载进去,列表头不算在数据模型Model里面
    QStringList  tablelHeader;
    for(int i=0;i<m_all_fieldsHeadname.size();i++) {
        tablelHeader << m_all_fieldsHeadname[i];
    }
    qDebug() << __LINE__ << __FUNCTION__<<tablelHeader;
    //tablelHeader<< "选择" <<"序号"<<"编码"<<"名称"<<"品牌"<<"类型"<<"IP地址"<<"更新时间"<<"操作";

注意,两种方式在数据展示上没有差别,但存在一个坑:

当使用代码行添加列表头(tablelHeader)时,当设置勾选项(QCheckBox)的信号和槽函数来获取勾选项(QCheckBox)的位置时,会偏差1行,坑的位置是以下代码row在获取最后一行时,返回的是-1,返回值-1其实是无效的意思。

以下是片段代码
    //关联信号和槽
    QCheckBox *checkBox = new QCheckBox();
    connect(checkBox,SIGNAL(stateChanged(int)),this,SLOT(onCheckBoxStateChanged(int)));


//实现槽函数
void MainWindow::onCheckBoxStateChanged(int state){
    QCheckBox *checkBox =qobject_cast<QCheckBox *>(QObject::sender());

    if(checkBox){
        int row = ui->tableWidget->indexAt(checkBox->mapTo(ui->tableWidget, QPoint(0, 0))).row();
}

我提交的源代码也是使用代码行添加列表头(tablelHeader),但用了另外一个方法来规避此问题,规避方法是row取的是继承tableWidget获取到的row,而不是通过checkBox->mapTo(ui->tableWidget, QPoint(0, 0))反向获取到的行位置(本人未深入研究mapTo,有用此方法解决此问题的兄弟,可以把代码放在评论区),所以不会出现偏差。

代码如下:

void tab_basemsg::renderTable(const QStringList& rowData){
    int row = ui->tableWidget->rowCount();//当前tableWidget显示的行数
    //int rowCount = ui->tableWidget->model()->rowCount();//tableWidget表格中实际的数据行数
    ui->tableWidget->insertRow(row);//在 QTableWidget 中插入新行

    for (int column = 0; column < rowData.size(); ++column) {
        QTableWidgetItem* item = new QTableWidgetItem(rowData.at(column));
        item->setTextAlignment(Qt::AlignCenter);
        ui->tableWidget->setItem(row, column, item);

        if(column == HEAD_BASEMSG_CKBOX){
            //========创建复选框QCheckBox===============
            QCheckBox* checkBox = new QCheckBox();
            QWidget* widget = new QWidget();
            QHBoxLayout* layout = new QHBoxLayout(widget);
            layout->addWidget(checkBox);
            layout->setAlignment(Qt::AlignCenter);
            layout->setContentsMargins(0, 0, 0, 0);
            widget->setLayout(layout);
            if(m_controlstatus==false) checkBox->setEnabled(false); // 设置复选框为不可选中状态
            else checkBox->setEnabled(true); // 设置复选框为可选中状态
            connect(checkBox,&QCheckBox::stateChanged,this,[=](int state){
                //获取当前行的IP
                QString ip = ui->tableWidget->item(row, HEAD_BASEMSG_IP)->text();//可以继承到row
                //qDebug()<< __LINE__ << "state:"<<state;
                qDebug()<< __LINE__ << "row:"<<row << "ip:"<<ip;
                m_iplist.append(ip);
                if (state == Qt::Checked) {
                    for(int i=0;i<HEAD_BASEMSG_NUM;i++){
                        QTableWidgetItem *item = ui->tableWidget->item(row, i);
                        //if(i==0) {item->setText("");}
                        item->setBackground(QBrush(QColor("#308cc6")));
                        item->setForeground(Qt::white);
                    }
                    // 改变操作项图标文件(颜色变化)
                    QWidget *container = ui->tableWidget->cellWidget(row, HEAD_BASEMSG_OPT);
                    if (container) {
                        QLayout *layout = container->layout();
                        if (layout) {
                            if (layout) {
                                QPushButton *editbtn = qobject_cast<QPushButton *>(layout->itemAt(0)->widget());
                                QPushButton *deletebtn = qobject_cast<QPushButton *>(layout->itemAt(1)->widget());
                                editbtn->setIcon(QIcon(":/index/img/edit_ch.png"));
                                deletebtn->setIcon(QIcon(":/index/img/delete_ch.png"));
                            }
                        }
                    }
                }else {
                    for(int i=0;i<HEAD_BASEMSG_NUM;i++){
                        QTableWidgetItem *item = ui->tableWidget->item(row, i);
                        // 设置未选中行的背景颜色为默认颜色
                        item->setBackground(QBrush(Qt::white));
                        item->setForeground(Qt::black);
                    }
                    // 改变操作项图标文件(颜色变化)
                    QWidget *container = ui->tableWidget->cellWidget(row, HEAD_BASEMSG_OPT);
                    if (container) {
                        QLayout *layout = container->layout();
                        if (layout) {
                            if (layout) {
                                QPushButton *editbtn = qobject_cast<QPushButton *>(layout->itemAt(0)->widget());
                                QPushButton *deletebtn = qobject_cast<QPushButton *>(layout->itemAt(1)->widget());
                                editbtn->setIcon(QIcon(":/index/img/edit.png"));
                                deletebtn->setIcon(QIcon(":/index/img/delete.png"));
                            }
                        }
                    }
                }
            });
            ui->tableWidget->setCellWidget(row, column, widget);
        }
        if (column == HEAD_BASEMSG_OPT) {
            //编辑按钮
            QPushButton* edit = new QPushButton();
            edit->setIcon(QIcon(":/index/img/edit.png"));
            edit->setIconSize(QSize(24, 24));
            edit->setStyleSheet("QPushButton { border: none; }");
            edit->setCursor(Qt::PointingHandCursor);
            //删除按钮
            QPushButton* deleteButton = new QPushButton();
            deleteButton->setIcon(QIcon(":/index/img/delete.png"));
            deleteButton->setIconSize(QSize(24, 24));
            deleteButton->setStyleSheet("background-color:rgba(0,0,0,0);border:none;");
            deleteButton->setCursor(Qt::PointingHandCursor);
            //按钮信号监听
            connect(edit,SIGNAL(clicked()),this,SLOT(editBasemsg()));
            connect(deleteButton,SIGNAL(clicked()),this,SLOT(delBasemsg()));

            QWidget* widget = new QWidget();
            QHBoxLayout* layout = new QHBoxLayout(widget);
            layout->addWidget(edit);
            layout->addWidget(deleteButton);
            layout->setAlignment(Qt::AlignCenter);
            layout->setContentsMargins(0, 0, 0, 0);
            widget->setLayout(layout);
            ui->tableWidget->setCellWidget(row, column, widget);
        }
    }
}

(2)QTableView中创建QCheckBox

QCheckBox需要通过widget加载到QTableView中,代码如下:

            //创建勾选项
            QCheckBox* checkBox = new QCheckBox();
            //创建窗口视图
            QWidget* widget = new QWidget();
            //创建布局
            QHBoxLayout* layout = new QHBoxLayout(widget);
            //把勾选项加载到布局中
            layout->addWidget(checkBox);
            layout->setAlignment(Qt::AlignCenter);
            layout->setContentsMargins(0, 0, 0, 0);
            //把布局设置到窗口视图中
            widget->setLayout(layout);
            //把窗口视图中展示到tableWidget的指定位置
            ui->tableWidget->setCellWidget(row, column, widget);

        QCheckBox勾选项关联的信号和槽的代码参见【(1)创建QTableView列表头】分享的renderTable()函数源代码。

(3)QTableView中创建QPushButton

        QPushButton与QCheckBox一样,也是需要widget加载到QTableView,不过可以设置QPushButton的尺寸、背景颜色等友好展示的布局,源码如下所示:

//编辑按钮
            QPushButton* edit = new QPushButton();
            edit->setIcon(QIcon(":/index/img/edit.png"));
            edit->setIconSize(QSize(24, 24));
            edit->setStyleSheet("QPushButton { border: none; }");
            edit->setCursor(Qt::PointingHandCursor);
            //删除按钮
            QPushButton* deleteButton = new QPushButton();
            deleteButton->setIcon(QIcon(":/index/img/delete.png"));
            deleteButton->setIconSize(QSize(24, 24));
            deleteButton->setStyleSheet("background-color:rgba(0,0,0,0);border:none;");
            deleteButton->setCursor(Qt::PointingHandCursor);
            //按钮信号监听
            connect(edit,SIGNAL(clicked()),this,SLOT(editBasemsg()));
            connect(deleteButton,SIGNAL(clicked()),this,SLOT(delBasemsg()));

            QWidget* widget = new QWidget();
            QHBoxLayout* layout = new QHBoxLayout(widget);
            layout->addWidget(edit);
            layout->addWidget(deleteButton);
            layout->setAlignment(Qt::AlignCenter);
            layout->setContentsMargins(0, 0, 0, 0);
            widget->setLayout(layout);
            ui->tableWidget->setCellWidget(row, column, widget);

(4)QTableView创建右键菜单

①在头文件中添加右键菜单绑定的槽函数,源码如下:

//tab_basemsg.h
private slots:
    //处理右键菜单请求
    void tableWidget_MenuRequested(const QPoint &pos);

②设置右键功能及关联信号和槽,并实现槽函数(在槽函数中增加具体的右键菜单名称),源码如下:

//tab_basemsg.cpp
//设置右键菜单功能
ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
//绑定右键功能槽函数
connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this, &tab_basemsg::tableWidget_MenuRequested);

//槽函数实现
void tab_basemsg::tableWidget_MenuRequested(const QPoint &pos) {
    QModelIndex index = ui->tableWidget->indexAt(pos);//获取当前行
    if (!index.isValid()) return;

    QMenu menu(this);
    QAction *DiplaymsgAction = menu.addAction(tr("查看详情"));
    connect(DiplaymsgAction,&QAction::triggered,[=](){
        //获取选择的单元格
        QList<QTableWidgetItem *> selected_cells = ui->tableWidget->selectedItems();
        if(!selected_cells.isEmpty()){
            QTableWidgetItem *codeCell = ui->tableWidget->item(selected_cells.first()->row(),HEAD_BASEMSG_CODE);
            if(codeCell!=nullptr){
                QString code = codeCell->text();
                stBasemsg basemsg=m_basemsgmap[code];
                basemsgDialg->setModal(false);
                basemsgDialg->setWindowTitle("保存");
                //basemsgDialg->setFixedSize(500,400);
                basemsgDialg->open();
                basemsgDialg->init(1,basemsg);
                basemsgDialg->exec();
            }
        }
    });
    QAction *NetpingAction = menu.addAction(tr("Ping此计算机"));
    connect(NetpingAction,&QAction::triggered,[=](){
        //获取选择的单元格
        QList<QTableWidgetItem *> selected_cells = ui->tableWidget->selectedItems();
        if(!selected_cells.isEmpty()){
            QTableWidgetItem *codeCell = ui->tableWidget->item(selected_cells.first()->row(),HEAD_BASEMSG_CODE);
            if(codeCell!=nullptr){
                QString code = codeCell->text();
                stBasemsg basemsg=m_basemsgmap[code];
                QString ip=basemsg.Ip;
                qDebug() << __LINE__ << ip;
                pingdlg->setIp(ip);
                pingdlg->setModal(false);
                pingdlg->setWindowTitle("PING测试");
                pingdlg->setFixedSize(500,400);
                pingdlg->open();
                pingdlg->init();
                pingdlg->exec();
            }
        }
    });

    menu.exec(QCursor::pos());
    //menu.exec(ui->tableWidget->mapToGlobal(pos));
}

篇尾

        因为多个勾选项很多情况下涉及多项数据的处理,有些处理是要异步才不会导致主界面卡顿,下一篇用多线程+ping+全局变量+结果展示技术点(【QT常用技术讲解】多线程处理+全局变量处理异步事件并获取多个线程返回的结果),来详细讲解【多线程解决QTableView多勾选项右键菜单功能卡顿问题】。

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

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

相关文章

DjangoRF-15-分布式celery应用

前面我们同步实现了测试任务的执行&#xff0c;但是它有一个致命的问题。 实际项目测试任务耗时会非常长&#xff0c;而django框架的请求是有超时的&#xff0c;哪怕没有超时&#xff0c;这么做显然不妥。所以需要使 用异步任务的方式来执行测试任务。 发送一个执行任务的请求&…

沐风老师3DMAX纹理工具箱TexTools使用方法详解

DMAX纹理工具箱TexTools是一组工具,可帮助任何纹理艺术家完成UV和纹理相关任务。主要理念是将典型步骤简化为简单的上下文相关单击。 大多数功能仅在3dMax中处于editUVW模式时才起作用(展开UVW修改器,然后单击编辑按钮)。 【版本要求】 3dMax9及更高版本 【安装方法】 将…

EmbeddedBuilder_v1.4.1.23782 - 在工程中添加自己的C实现文件

文章目录 EmbeddedBuilder_v1.4.1.23782 - 在工程中添加自己的C实现文件概述笔记添加自己的文件夹在文件夹中建立新文件在文件夹中载入已经存在的文件修改工程编译时的包含路径和库路径添加包含路径添加实现路径 在main.c或其他实现中添加自己的头文件引用和自己的函数调用保存…

Seaborn库

目录 主要功能和特点 使用方法 实例应用 Seaborn库的最新版本有哪些新功能和改进&#xff1f; 如何在Seaborn中实现复杂的数据预处理步骤&#xff0c;例如数据清洗和转换&#xff1f; Seaborn与其他数据可视化库&#xff08;如Matplotlib、Plotly&#xff09;相比有哪些优…

【图像去雾系列】使用暗通道先验去雾算法对图像进行去雾处理

目录 一 暗通道先验去雾算法 1 雾形成机理-大气散射模型 2 暗通道先验的整体思想 二 实践 一 暗通道先验去雾算法 论文名称:Single Image Haze Removal Using Dark Channel Prior 论文地址:Single Image Haze Removal Using Dark Channel Prior | IEEE Journals & …

合合信息的OCR技术在智能文档处理方面有哪些具体的应用案例?

智能文档处理(IDP)是利用人工智能技术,自动从复杂的非结构化和半结构化文档中抽取关键数据,并将其转换成结构化数据的技术。能够自动识别、提取并结构化处理文档中的关键信息。这种技术通常基于自然语言处理&#xff08;NLP&#xff09;和计算机视觉等先进技术&#xff0c;可以…

【连续4届EI检索,SPIE 出版】第五届信号处理与计算机科学国际学术会议(SPCS 2024,8月23-25)

第五届信号处理与计算机科学国际学术会议&#xff08;SPCS 2024) 将于2024年8月23-25日在中国哈尔滨举行。会议主要围绕信号处理与计算机科学等研究领域展开讨论。 会议旨在为从事信号处理与计算机科学研究的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技…

如何使用Wireshake解密Wi-Fi QoS Data报文?

1. 使用Wireshake解密Wi-Fi数据报文 通常当Wi-Fi发生某些问题时&#xff0c;我们都会抓取Wi-Fi sniffer log&#xff0c;用以协助分析问题&#xff0c;但是如果Wi-Fi使用了加密&#xff0c;则我们无法从sniffer log中获取到IP数据的层级&#xff0c;因为在Wi-Fi报文中&#xf…

非专业人士的编程梦:低代码开发平台的崛起与挑战

文章目录 每日一句正能量前言技术概览基本概念主要特点市场现状适用性分析结论 效率与质量的权衡效率提升质量与安全的挑战企业应用开发中的利弊应对策略结论 挑战与机遇挑战机遇应对策略结论 后记 每日一句正能量 书读的越多而不加思考&#xff0c;你就会觉得你知道得很多&…

24/8/14算法笔记 复习_逻辑回归sigmoid

import numpy as np import matplotlib.pyplot as pltdef sigmoid(x):return 1/(1np.exp(-x))x np.linspace(-5,5,100) y sigmoid(x)plt.plot(x,y,colorgreen) #损失函数 from sklearn import datasets from sklearn.linear_model import LogisticRegression from mpl_toolki…

SpringBoot教程(二十一) | SpringBoot实现定时任务

SpringBoot教程&#xff08;二十一&#xff09; | SpringBoot实现定时任务 单点定时任务方式一&#xff1a;使用ScheduledEnableScheduling注解巨坑&#xff08;Scheduled任务都用了同一个线程去执行&#xff0c;导致定时任务存在堵塞&#xff09;解决办法一&#xff1a;添加自…

linux监控命令

在 Linux 中&#xff0c;有许多命令可以用于监控系统的性能和状态。以下是一些常用的监控命令及其用途&#xff1a; 1. top​ 和 htop​ top ​top​ 命令显示当前系统中运行的进程列表及其资源使用情况。 top​​ ‍ htop ​htop​ 是 top​ 命令的增强版&#xff0c;提…

使用 Spring Event 解耦代码

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 前言 在Spring框架中&#xff0c;事件机制扮演着至关重要的角色&#xff0c;它不仅促进了组件间的互动&#xff0c;还在提高系统灵活性方面迈出了重要步伐。相较于常规的方法调用&#xff0c;这种机制显著提…

前端组件库汇总

文章目录 一、前端组件库1. ElementUI(基于 Vue 2.0 的桌面端组件库)2. Element Plus(基于 Vue 3,面向设计师和开发者的组件库)3. Vue DevUI(一个基于 DevUI Design 的 Vue3 组件库)4. vant(轻量、可定制的移动端 Vue 组件库)5. Ant Design(助力设计开发者「更灵活」…

使用Spring Boot整合ip2region获取客户端IP地理位置信息

&#x1f604; 19年之后由于某些原因断更了三年&#xff0c;23年重新扬帆起航&#xff0c;推出更多优质博文&#xff0c;希望大家多多支持&#xff5e; &#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Mi…

Spring之@Import注解

1. 前言 Import 注解 在 Spring 中占据重要地位&#xff0c;是 Spring 的一个重要扩展点。这篇博文我们以案例、源码、应用相结合&#xff0c;来系统的学习一下这个注解 2. 案例演示 2.1 代码准备 2.1.1 创建配置类 AppConfig ComponentScan("com.ys") public c…

实战项目:贪吃蛇游戏的实现(上)

前言 Hello, 今天我们来一起完成一个实战项目&#xff1a;贪吃蛇。 相信大家都不会对这个游戏感到陌生&#xff0c;贪吃蛇游戏是久负盛名的游戏&#xff0c;他和俄罗斯方块&#xff0c;扫雷游戏等游戏位列世界经典游戏之列。这次我们旨在通过实战项目贪吃蛇的实现&#xff0c…

opencv2.4.9源码在Windows下VS2019的编译

1、opencv2.4.9解压后根目录下建立build文件夹 2、采用CMake-gui进行编译 记得把上面两个√去掉&#xff0c;用老版本的opencv再用cuda完全没有意义&#xff0c;我们只是验证算法用。 把这个√也去掉。 重新Configure和Generate&#xff0c;如下图&#xff1a; 然后&#xff1…

大模型汇总:文心一言大模型、腾讯混元大模型、通义千问大模型、字节豆包大模型、智普清言大模型、KIMI 大模型、紫东太初大模型、讯飞星火大模型

文心一言大模型 作为百度自主研发的大型语言模型&#xff0c;具有显著的特点、广泛的应用场景以及独特的优势。以下是对文心一言特点、应用、优势的详细介绍&#xff1a; 特点&#xff1a;知识增强&#xff1a; 文心一言通过持续学习技术&#xff0c;不断吸收海量数据和知识…

Postman接口测试基础教程--2024最新版

文章目录 一、Postman 简介二、Postman 功能概览三、Postman 安装说明1. 下载与安装2. 界面导航说明3. 发送第一个请求 四、Postman 基础功能1. 常见类型的接口请求查询参数的接口请求表单类型的接口请求上传文件的表单请求JSON 类型的接口请求 2. 接口响应数据解析3. 接口管理…