python3 pyside6图形库学习笔记及实践(四)

news2024/9/30 21:23:20

目录

    • 前言
    • 列表控件(QListWidget)
      • 创建列表
      • 增删插改查
        • 添加元素
        • 插入元素
        • 删除元素
        • 修改元素
        • 查找元素
      • 常用信号和槽
        • currentItemChanged
        • itemChanged
        • clear
      • 列表排序
      • 列表的上下文菜单
    • 图形视图框架
      • 简介
      • 框架核心
      • 图元类(QGraphicsItem)
      • 场景类(QGraphicsScene)
      • 视图类(QGraphicsView)
      • 交互机制
      • 实例
    • 实践:OCR可视化

前言

本系列文章为b站PySide6教程以及官方文档的学习笔记

原视频传送门:【已完结】PySide6百炼成真,带你系统性入门Qt

官方文档链接:Qt for Python

列表控件(QListWidget)

这里我们下载一个faker库,用于生成人名,模拟列表中的元素

pip install faker

在初始化函数中,我们创建faker库的实例

self.fake = Faker(locale='zh_CN')

创建列表

首先我们需要从QtWidgets中引入QListWidegt

from PySide6.QtWidgets import QListWidget

接下来我们可以创建一个列表控件实例

self.listWidget = QListWidget()

增删插改查

添加元素

使用addItem方法可以一次向列表中添加一个元素

self.listWidget.addItem(self.fake.name())

addItem方法可以接收字符串参数,也可以接收QListWidgetItem类的实例

之所以要额外使用QListWidgetItem这种数据类型,是因为它定义了一些便捷的属性和方法

from PySide6.QtWidgets import QListWidgetItem
self.listWidget.addItem(QListWidgetItem(self.fake.name()))

当然,逐个添加有时会比较麻烦,我们可以使用addItems方法一次添加多个元素

不过addItems方法只能传入字符串序列

self.listWidget.addItems([QListWidgetItem(self.fake.name()) for _ in range(20)])

我们传入20个人名,效果如下:

请添加图片描述

可以看到,当列表的元素较多时,右侧会出现滚动条,这也是列表的特性之一

插入元素

插入元素同样有insertIteminsertItems两种方法,分别是一次性插入一个和多个元素

insertItem方法需要传入两个参数,分别是插入位置和插入元素

例如我们在刚刚的列表的第三个位置插入数字3

self.listWidget.insertItem(2, '3')

请添加图片描述

insertItems则是指定插入位置以及字符串序列

self.listWidget.insertItems(2, ['3','4','5'])

请添加图片描述

删除元素

删除列表中的元素需要用到takeItem方法

例如我们想删除列表中的第三个元素,我们只需传入被删元素的序号

self.listWidget.takeItem(2)
修改元素

要修改列表中的某个元素,我们需要先获取到该元素

此时需要用到item方法,我们将获取的目标元素赋给一个变量

itemGet = self.listWidget.item(2)

当我们向列表中添加或者插入元素时,无论是用的字符串还是QListWidgetItem,每个元素最后都会成为QListWidgetItem数据结构,所以我们的接收变量itemGet也是指向一个QListWidgetItem

我们直接使用该数据结构的方法setText即可修改它的文本内容

itemGet.setText('6')

或者我们也可以压缩到一行语句

self.listWidget.item(2).setText('6')
查找元素

查找元素涉及到findItem方法

我们需要传入两个参数,匹配的字符串,以及匹配模式

当然,匹配模式需要我们先导入核心库

from PySide6.QtCore import Qt

下面是一些常用的匹配模式

匹配模式名特点
MatchContains匹配包含目标字符串的元素
MatchEndsWith匹配以目标字符串结尾的元素
MatchStartsWith匹配以目标字符串开头的元素
MatchCaseSensitive匹配时区分大小写
MatchRegularExpression正则匹配
MatchExactly完美匹配

该方法会返回一个列表变量,该变量中包括所有符合条件的元素

例如我想输出列表中所有包含字的人名

result = self.listWidget.findItems('张', Qt.MatchFlag.MatchContains)
for item in result:
    print(item.text())

请添加图片描述

常用信号和槽

currentItemChanged

currentItemChanged信号可以侦测到当前选则元素的改变

**选则(selected)**即列表元素的一种显示状态,鼠标点击的列表元素会被选则,背景会被加深为蓝色

请添加图片描述

列表会默认选则第一个元素,只是它的背景不会被加深

例如我们可以写一个测试程序:当前选则元素改变时,输出新选则元素的内容

def bind(self):
    self.listWidget.currentItemChanged.connect(self.currentChanged)
def currentChanged(self):
    print(self.listWidget.currentItem().text())

currentItem()方法用于获取当前选则的元素

其实currentItemChanged信号会向槽发送两个参数,分别为当前选则元素及上一个选则的元素

请添加图片描述

此时我们可以简化槽函数

def currentChanged(self, item):
    print(item.text())
itemChanged

itemChanged信号可以侦测到当前选中元素的状态改变

当某个列表元素被设置为可选时,元素左侧会出现小方框,当鼠标勾选该方框时则为选中(checked)

例如我们给第一个元素先设置为未选中状态

self.listWidget.item(0).setCheckState(Qt.CheckState.Unchecked)

请添加图片描述

同时我们使用itemChanged信号来侦测元素的选中状态,当有元素的选中状态发生变化时,itemChanged信号会发送该元素给槽

self.listWidget.itemChanged.connect(self.itemChanged)
def itemChanged(self, item):
    print(item.text(), item.checkState())

checkState()属性会返回元素的选中状态,不过并不是布尔值,而是特定的枚举类型

请添加图片描述

clear

clear()槽在被调用时会清空列表中的所有元素

列表排序

想要对列表中的元素进行排序时,使用sortItems方法

我们只需向该方法传入排序规则即可,升序即AscendingOrder,降序传入DescendingOrder

self.listWidget.sortItems(Qt.SortOrder.DescendingOrder)

下面是数字列表的升序演示

请添加图片描述

该排序规则使用的是字符串排序比较规则,即从第一个字符开始比较,所以不是单纯的数字从小到大

列表的上下文菜单

给列表控件添加上下文菜单的方法与之前介绍的控件上下文菜单一致

首先给列表控件设置上下文菜单的策略

self.listWidget.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu)

接着我们向其中添加Action,即操作

事实上,这是一种伪上下文菜单,因为我们无法对列表中的具体元素定制上下文菜单的内容,所有元素使用的上下文菜单都是一样的

图形视图框架

简介

在之前文章的内容中,我们想要显示图片,只能通过QLabel控件

但是由于Qlabel本身并不是为浏览图片设计的,所以对交互等限制很大

同时如果我们想显示多张图片时,使用Qlabel也较为麻烦

pyside6中的图形视图框架可以让我们管理大量的自定义2D图元并与之交互

图形视图框架主要包含三个类:QGraphicsItem图元类、QGraphicsScene场景类和QGraphicsView视图类。

简单概括下三者的关系就是:图元放在场景上,场景内容通过视图来显示。下面我们来一一进行讲解

框架核心

在 PySide6的图形视图框架中,**场景(Scene)、视图(View)和图元(Graphics Items)**之间的关系构成了框架的核心。

场景是一个抽象的二维空间,用于组织和管理图元,但它本身不负责图元的渲染。

图元是场景中的基本构建块,用于表示所有可视化对象。它们存在于场景中,由场景管理。

视图是场景的可视化表示,是用户与场景和图元交互的界面。一个场景可以被多个视图展示,每个视图可以展示场景的不同部分或以不同方式渲染相同的内容。

QGraphicsView类与QGraphicsScene类配套实现了类似Mode/View的架构,这种设计模式旨在分离图形的管理与图形的呈现。

使用图形视图框架的一般流程包括:

  1. 创建一个 QGraphicsScene 实例来存储和管理图形项。
  2. 创建各种 QGraphicsItem 实例,并将它们添加到场景中。
  3. 创建一个 QGraphicsView 实例,将其设置为显示前面创建的场景。
  4. 使用 QGraphicsView 提供的功能来导航和交互场景。

图元类(QGraphicsItem)

图元在图形视图框架中可以表现为文本、图像、标准的几何形状或者是自定义的图形。已经有一些预定义的图元类型提供给开发者使用,包括:

  • QGraphicsLineItem 用于表示直线。
  • QGraphicsRectItem 用于表示矩形。
  • QGraphicsEllipseItem 用于表示椭圆。
  • QGraphicsPixmapItem 用于展示图片。
  • QGraphicsTextItem 用于展示文本。
  • QGraphicsPathItem 用于绘制复杂的图形路径。

例如下面的代码创建了一个矩形框图元,左上角坐标为同时给它设置可拖拽和可选择的属性

坐标为(120,30),宽50,高30

self.rect = QGraphicsRectItem()
self.rect.setRect(120, 30, 50, 30)
self.rect.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIsSelectable)

场景类(QGraphicsScene)

场景是所有图元的容器,提供了一个二维空间,在这个空间中可以添加、移动和管理图元。可以将场景想象成一个无限大的画布,而你可以在任意位置放置图形对象(如矩形、椭圆、文本等)。

场景本身是独立于任何视图的,这意味着你可以有多个视图展示同一个场景的不同部分或以不同的方式(如不同的缩放级别)

我们可以将场景类比于模型,同一个模型可以有不同的展示方式,同时多个场景也可以通过切换展示在同一个视图中。

QGraphicsScene类拥有非常多的管理图元的方法

首先我们通过下面这行代码创建一个场景

self.scene = QGraphicsScene()

当然,场景作为一个画布,我们需要为其设置大小

而且,图元在场景中的位置是通过坐标来确定的,所以我们还需要设置坐标原点

下面这行代码通过setSceneRect方法,设置场景的大小为300X300,坐标原点为(0,0),即左上角

self.scene.setSceneRect(0, 0, 300, 300)

接下来,通过将addItem方法将之前创建的矩形图元添加到场景中

self.scene.addItem(self.rect)

当然,除了直接添加图元实例,QGraphicsScene类还提供了一些方法,用于向场景中快速添加不同种类的图元(免去创建图元这一步骤),这些方法会返回创建的图元的指针,我们可以用变量接收

请添加图片描述

视图类(QGraphicsView)

图元和场景部分均属于模型,而视图则是实际显示出来的窗口控件(QWidget),与控件一样,它最终会被添加到布局并展示在窗口中

和场景一样,视图也是基于笛卡尔坐标系,左上角为原点,向右为x正轴,向下为y正轴。

请添加图片描述

如果视图的尺寸小于场景的尺寸,视图会变成一个可滚动的区域,允许用户通过滚动条查看整个场景的内容。即使视图与场景的大小相同,滚动条也会出现(需要手动隐藏)。

下面的代码创建了一个300X300大小的视图控件

self.view = QGraphicsView()
self.view.resize(300, 300)

接下来我们需要设置视图展示的场景,并将视图添加到布局中

self.view.setScene(self.scene)
self.mainLayout.addWidget(self.view)

效果如下

请添加图片描述

交互机制

QGraphicsItem 并没有继承 QObject 类,因此它自身不支持信号与槽的机制,也不能直接应用动画效果。

虽然不能使用信号与槽,图形视图框架也有一些用于和用户交互的机制

  1. 事件处理:

    QGraphicsItem 提供了一系列的事件处理函数,可以被重写来响应不同的事件,例如鼠标点击(mousePressEvent)、鼠标移动(mouseMoveEvent)等。通过重写这些事件处理函数,可以在事件发生时执行特定的逻辑,从而模拟信号和槽的行为。

  2. 场景事件:

    QGraphicsScene 也提供了事件处理机制,比如 itemClickeditemHovered 等事件。通过在场景层面处理这些事件,可以实现对场景中图元事件的响应。由于 QGraphicsScene 继承自 QObject,它能够使用信号和槽机制,从而允许场景与其他 QObject 对象或图元之间的通信。

  3. 定时器:

    对于需要定时更新或检查状态的图元,可以使用 QTimerQTimer 是基于 QObject 的,因此支持信号和槽。通过在图元中使用定时器,可以定时触发特定的行为,而无需直接在图元中实现信号和槽的机制。

  4. 绘制更新

    图元类中提供了paint方法,当图元、场景或者视图发送变化时,Qt 会自动调用paint方法,重新绘制视图

    我们可以通过重写的 paint 方法,在其中添加绘制行为,并设置绘制条件

实例

下面我们通过一个例子来体现前面提到的四种交互机制

首先我们创建一个新的图元类NewRectItem,继承QGraphicsRectItem

其中我们重写鼠标响应以及悬停的事件处理函数,加上我们想要的反馈:鼠标点击时图元变色、悬停时边框变红,用于测试事件处理机制

重写paint方法来添加自定义的绘图条件及行为:当矩形图元在鼠标下方时会在中间画一个圆,用于测试绘制更新机制

class NewRectItem(QGraphicsRectItem):
    def __init__(self, x, y, width, height):
        super(NewRectItem, self).__init__(x, y, width, height)
        self.setAcceptHoverEvents(True)  # 启用悬停事件
        self.setFlags(QGraphicsItem.ItemIsMovable )
        
    # 1. 事件处理: 
    # 重写鼠标点击事件来改变框内颜色
    def mousePressEvent(self, event):
        self.setBrush(QColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))

    # 重写悬停事件来改变边框颜色
    def hoverEnterEvent(self, event):
        self.setPen(QPen(Qt.red, 3))

    def hoverLeaveEvent(self, event):
        self.setPen(QPen(Qt.black, 1))

    # 2. 绘制更新: 
    # 重写paint来添加自定义的绘图条件及行为
    def paint(self, painter, option, widget):

        super().paint(painter, option, widget)
        if self.isUnderMouse():
            # 如果被选中,在中间绘制一个圆
            centerX = self.boundingRect().x()+self.boundingRect().width()/2
            centerY = self.boundingRect().y()+self.boundingRect().height()/2
            radius = min(self.boundingRect().width(),self.boundingRect().height())/4  # 圆的半径为矩形最短边的四分之一

            # 设置画笔和画刷来绘制圆
            painter.setPen(QPen(QColor(0, 0, 0, 127), 2))  # 设置圆的边框颜色和宽度
            painter.setBrush(QColor(0, 0, 0, 127))  # 设置圆的填充颜色和透明度
            
            # 绘制圆
            painter.drawEllipse(QPointF(centerX, centerY), radius, radius)

接下来我们也自定义一个新场景MyScene

通过重写场景事件mouseDoubleClickEvent来达到交互效果:双击鼠标时,在场景添加一个矩形图元

同时设置一个每秒触发一次的计时器,用于测试计时器机制

class MyScene(QGraphicsScene):
    def __init__(self, parent=None):
        super(MyScene, self).__init__(parent)
        self.timer = QTimer()
        self.timer.timeout.connect(self.onTimeout)
        self.timer.start(1000)

    # 3. 场景事件: 重写 mouseDoubleClickEvent 来响应鼠标双击
    def mouseDoubleClickEvent(self, event):
        rect = NewRectItem(event.scenePos().x() - 25, event.scenePos().y() - 25, 50, 50)
        self.addItem(rect)

    # 4. 定时器: 将timeout信号与自定义的槽函数onTimeout连接
    def onTimeout(self):
        # 定时器触发的行为:旋转所有图元
        for item in self.items():
            
            centerX = item.boundingRect().x()+item.boundingRect().width()/2
            centerY = item.boundingRect().y()+item.boundingRect().height()/2

            item.setTransformOriginPoint(centerX, centerY)
            item.setRotation(item.rotation() + 10) 

需要注意的是,由于图元是沿着变换原点旋转,所以每次触发旋转事件时需要使用setTransformOriginPoint方法更新变换原点,将其矫正到矩形中央的坐标

最后我们在场景中添加几个矩形图元

# 初始化一些图元
for _ in range(5):
    rect = NewRectItem(random.randint(0, 150), random.randint(0, 150), 50, 50)
    self.scene.addItem(rect)

交互效果如下:

请添加图片描述

实践:OCR可视化

这两天调研了一下WPS的图片转文字功能后,突然发现Pyside6的图形视图框架及列表控件非常适合用来实现OCR可视化

请添加图片描述

右侧文字部分在被鼠标覆盖时,背景颜色会加深,这与列表控件的特性很相似

而左侧的检测框则可以看成是一个个图元,因为它也具有能交互的特性

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

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

相关文章

守护数据安全:有效应对.hmallox勒索病毒的策略

引言 近年来,随着网络技术的飞速发展,勒索病毒成为网络安全领域的一大威胁。其中,.hmallox勒索病毒作为malox勒索软件家族的新变种,给个人和企业带来了极大的数据安全和经济损失风险。本文将对.hmallox勒索病毒进行详细介绍&…

机器学习用python还是R,哪个更好?

机器学习领域中,Python和R都是非常流行的编程语言,它们各有优势和特点: Python: 优势: 拥有丰富的库和框架,如scikit-learn、TensorFlow、PyTorch等,适合各种级别的机器学习任务。语法简洁清晰,易于学习。社…

3DM游戏运行库合集离线安装包2024最新版

3DM游戏运行库合集离线安装包是一款由国内最大的游戏玩家论坛社区3DM推出的集成式游戏运行库合集软件,旨在解决玩家在玩游戏时遇到的运行库缺失或错误问题。该软件包含多种常用的系统运行库组件,支持32位和64位操作系统,能够自动识别系统版本…

LeetCode每日一题_572.另一棵树的子树

解题思路: Step1:首先我们要知道如何判断两颗树相同,思路就是遍历每个节点,然后判断是否均相等,需要用递归来实现。代码如下所示: public static boolean equals(TreeNode t1,TreeNode t2){if(t1null&&t2null…

[Java]面向对象,从浅到深

快速入门 计算机的核心作用就是处理数据, 变量用来存储单个数据, 数组用来储存一批数据, 对象用来存储一类数据 什么是对象: 对象就是一种特殊的数据结构, 在java中万物皆对象 面相对象编程的好处: 更加符合人类思维习惯 类和实例对象 在java中必须先设计类, 才能根据类创…

git学习入门1——下载安装与添加用户标识设置name与Email

想法是这样的,先是自己工作闲暇之余在学习C语言,在跟一个某平台的机构学习C语言的基础知识,空闲之余学习了几天,想起了之前学习过程中某学员提出的git每日提交代码的那个表格记录,忽然想起自己也先学习git的使用。 先是…

三、初识工作流

基础操作 拖动操作,按住鼠标左键可以拖动 放大缩小,可以通过鼠标滚轮操作 节点含义 1、大模型 2、正向与负向提示词(生成图片的文字信息) 3、图片尺寸设定(批次大小为每次生产图片数量) 4、采样器 5、图片渲染 6、保存图像 设…

Reed-Solomon纠错码——RS(255,251)学习及实现

1、基础知识 1.1 有限域 有限域_百度百科​​​​​​ 伽罗华域(Galois Field)上的四则运算_模2的伽罗华域乘法-CSDN博客 1.2 RS(255,251) 里德-所罗门码(一种前向错误更正的信道编码)_百度百科 本原…

Spring面试篇章——IOC

IOC概念和原理 IOC概念 IOC就是控制反射,把对象创建和对象之间的调用过程,交给Spring进行管理使用IOC的目的:降低耦合度 IOC底层原理 xml解析、工厂模式、反射 图解: 原始模式 耦合度太高了,即当dao改了&#xf…

UWB实操:使用 litepoint 收发UWB信号

使用 litepoint 收发UWB信号 把信号线接到 litepoint 的RF1 和RF2。 注意: RF1 支持 VSG(TX) 和VSA(RX)RF2 只支持 VSG(TX)同一时间只能一个 VSG(TX) 双击 LED STATUS,改变RF1和RF2的模式。 RF1:VSA(RX) RF2:VSG(TX) Techno…

学习笔记--算法(双指针)3

快乐数 . - 力扣(LeetCode) 题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是 无…

8.怎么配嵌套子路由,以及它的作用

作用 配嵌套子路由,就是可以通过同一个页面,让不同的位置发生变化,其他的位置不会发生变化,而做到一个局部刷新 例子 红线框住的部分,头部和导航栏是不会发生变化的,变化的只有中间的内容 子路由的操作步骤 将这个页面的头部和导航栏部分的样式和风格,移到主路由上(<tem…

111页PPT某大型制造业ERP转型规划方案

德勤为大型制造业ERP转型规划方案提供了一系列的策略和步骤&#xff0c;这些策略和步骤旨在帮助企业实现数字化转型&#xff0c;提升业务效率和竞争力。 以下是德勤提出的关键点 &#xff1a;资料下载方式&#xff0c;请看每张图片右下角信息 1. 流程规划&#xff1a;德勤首先…

企业级业务架构设计:指南解析

引言 在数字化转型的浪潮中&#xff0c;企业业务架构的设计成为了连接企业战略与技术实现的桥梁&#xff0c;其重要性日益凸显。本文将深入探讨企业级业务架构的设计原则、流程、工具和技术实现&#xff0c;并结合具体案例&#xff0c;为读者提供详尽的实战指导。通过结合《企…

GAZEBO之MyRobot建立

GAZEBO之MyRobot建立 1. 源由2. 示例Step 1: 新建一个简单世界Step 2: 新建一个模型(model)Step 3: 机器人组成链接(Links)Step 3.1: 新增底盘(Links/Chassis)Step 3.1.1: 惯性属性(Inertial properties)Step 3.1.2: 视觉(Visual)Step 3.1.3: 碰撞(Collision) Step 3.2: 新增左…

PointNet和PointNet++论文解读

目录 一、导言 二、PointNet介绍 三、PointNet网络结构 1、损失函数 2、正则化 四、PointNet 1、分层次的点集抽象层 一、导言 PointNet来自CVPR2017&#xff0c;是最早直接处理点云数据用于计算机视觉的模型&#xff0c;并运用于分割、检测、场景理解任务&#xff0c;P…

celery简单使用

1. 框架介绍 Celery是一个强大的异步任务队列/作业队列框架, 它主要用于处理大量消息, 同时为操作提供稳定可靠的消息传输机制. Celery的分布式特性允许任务分散到多个计算节点上并行处理, 从而提高系统的可扩展性, 可靠性和性能. Celery使用消息代理(如: RabbitMQ, Redis)来实…

【Linux】win 环境下进行 linux开发

文章目录 IDE 安装Python开发创建一个新项目安装 Python、pip 和 venv创建虚拟环境&#xff08;建议&#xff09;运行Python 参考文章 想要win 环境下进行 linux开发&#xff0c;需要依赖于wsl。wsl安装可参考上篇文章 【Linux】wsl win安装Linux环境 这里主要介绍在 linux下…

【pkill pgrep】Centos/Linux pkill命令详细介绍

简介 系统版本&#xff1a;Centos7.6 pkill命令用于杀死一个进程&#xff0c;会根据进程名称和其他属性杀死进程&#xff08;默认会向进程发送SIGTERM信号&#xff0c;详细请看Linux信号的行为说明&#xff09;&#xff0c;与之相似的命令有killall&#xff0c;与kill命令相比&…

C++学习之路(1)— 第一个HelloWorld程序

C学习之路&#xff08;1&#xff09;— 第一个HelloWorld程序 一、前言 C在C语言的基础上添加了对面向对象编程和泛型编程的支持&#xff0c;在 20世纪90年代便是最重要的编程语言之一&#xff0c;并在21世纪仍保持强劲势头。C继承了C语言高效、简洁、快速和可移植性的传统。 …