PySide(PyQT)的视图(QGraphicsView)范例(一) 基本框架

最近学习了视图(QGraphicsView)的知识,总结一下,做一个demo以备忘。在demo中演示了常用的设置方法和信号槽传递机制。

QT的视图(QGraphicsView)体系是建立在场景(QGraphicsScene)基础上的,场景(QGraphicsScene)是图形项(QGraphicsItem)的容器,图形项(QGraphicsItem)最终呈现的显示元素。

基本的框架演示:

python 复制代码
# 设置样本图片的QGraphicsView模型
from PySide6.QtCore import Qt, QRectF
from PySide6.QtGui import QPainter, QPen, QColor, QAction, QMouseEvent
from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QGraphicsRectItem, QMenu, QWidget, \
    QVBoxLayout, QFrame, QSizePolicy


# 设置矩形方框(QGraphicsRectItem)模型
class MyRectItem(QGraphicsRectItem):
    def __init__(self, temp_pen, normal_pen, *args):
        super().__init__(*args)
        self.temp_pen = temp_pen   # 临时画笔
        self.normal_pen = normal_pen   # 正常画笔

        # 启用鼠标跟踪,以便在没有按下鼠标按钮时也能接收鼠标移动事件
        self.setAcceptHoverEvents(True)


    def hoverEnterEvent(self, event: QMouseEvent):
        """鼠标进入项的事件处理"""
        print("鼠标进入项")
        super().hoverEnterEvent(event)
        self.setPen(self.temp_pen)


    def hoverLeaveEvent(self, event: QMouseEvent):
        """鼠标离开项的事件处理"""
        print("鼠标离开项")
        super().hoverLeaveEvent(event)
        self.setPen(self.normal_pen)

# 设置QGraphicsView模型
class MyView(QGraphicsView):
    def __init__(self, parent=None, autoScale=True):
        super().__init__(parent)
        self.autoScale = autoScale  # 自动缩放标志,是否全画幅显示
        self.set_scene()   # 设置场景
        self.set_mouse()   # 设置鼠标
        self.set_flags()   # 设置标志
        self.set_menu()   # 设置菜单


    def set_scene(self):
        """设置场景"""
        self.scene = QGraphicsScene()  # 创建窗口场景
        # 设置渲染提示
        self.setRenderHint(QPainter.Antialiasing)  # 开启抗锯齿
        self.setRenderHint(QPainter.SmoothPixmapTransform)  # 开启平滑缩放
        # 设置缩放锚点
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)  # 转换时以鼠标为中心
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)  # 缩放时以鼠标为中心
        self.setScene(self.scene)  # 将场景应用到视窗中

    def set_mouse(self):
        """设置鼠标"""
        self.setMouseTracking(True)  # 设置鼠标跟踪
        # 鼠标的实时位置(视窗坐标)
        self.view_x = 0
        self.view_y = 0
        # 鼠标的实时位置(场景坐标)
        self.scene_x = 0
        self.scene_y = 0
        # 鼠标按下时的位置(场景坐标)
        self.press_x = None
        self.press_y = None
        # 鼠标释放时的位置(场景坐标)
        self.release_x = 0
        self.release_y = 0

    # 处理滚轮事件以实现缩放
    def wheelEvent(self, event):
        """处理滚轮事件以实现缩放"""
        factor = 1.001 ** event.angleDelta().y()  # 滚轮每滚动一格,缩放比例变化
        self.scale(factor, factor)

    def set_flags(self):
        """设置标志"""
        pass

    def set_menu(self):
        """设置菜单"""
        pass

    # 设置图像文件
    def set_image(self, pixmap):
        self.scene.clear()  # 清空场景
        self.scene_rect = QRectF(0, 0, pixmap.width(), pixmap.height())  # 设置场景范围
        self.image_item = QGraphicsPixmapItem(pixmap)  # 创建图片对象
        self.scene.addItem(self.image_item)  # 将图片对象添加到场景中
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)  # 设置视图对齐方式
        if self.autoScale:
            self.fitInView(self.image_item, Qt.AspectRatioMode.KeepAspectRatio)  # 设置视图适应图片,全幅显示



if __name__ == "__main__":
    import sys
    from PySide6.QtWidgets import QApplication
    from PySide6.QtGui import QPixmap

    app = QApplication(sys.argv)
    widget = QWidget()  # 创建窗口对象
    widget.resize(800, 600)  # 设置窗口大小
    widget.layout = QVBoxLayout(widget)  # 创建垂直布局对象
    widget.view = MyView(widget)  # 创建MyView对象
    widget.layout.addWidget(widget.view)  # 将视图添加到布局中

    pixmap = QPixmap("your/image/path")  # 创建QPixmap对象

    widget.show()  # 显示窗口
    widget.view.set_image(pixmap)  # 设置图像文件

    sys.exit(app.exec())  # 进入程序的主循环,并通过exit()函数确保主循环安全结束

基本框架具备了图像显示和鼠标滚轮缩放的功能:

注意:

python 复制代码
widget.show()  # 显示窗口
widget.view.set_image(pixmap)  # 设置图像文件

这两行代码的顺序一定不能反,如果将 widget.show() 放在widget.view.set_image(pixmap)后面,将会是下面的显示效果,初始化后不能全幅显示。

这是因为 fitInView 方法的行为依赖于视图的实际大小,而在窗口尚未显示时,视图的大小可能是未确定的或者是默认值,从而导致 fitInView 无法正确计算和应用缩放,而show()函数执行之后就确定了视图的大小。

相关推荐
Humbunklung3 天前
PySide6 GUI 学习笔记——常用类及控件使用方法(多行文本控件QTextEdit)
笔记·python·学习·pyqt
En^_^Joy4 天前
PyQt常用控件的使用:QFileDialog、QMessageBox、QTreeWidget、QRadioButton等
开发语言·python·pyqt
zhlei_123455 天前
封闭内网安装配置VSCode Anconda3 并配置 PyQt5开发
ide·vscode·pyqt
猫头虎6 天前
零基础安装 Python 教程:从下载到环境配置一步到位(支持 VSCode 和 PyCharm)与常用操作系统操作指南
vscode·python·pycharm·beautifulsoup·numpy·pyqt·pip
江畔柳前堤14 天前
PyQt学习系列08-插件系统与模块化开发
运维·开发语言·数据库·python·学习·机器学习·pyqt
江畔柳前堤17 天前
PyQt学习系列05-图形渲染与OpenGL集成
开发语言·javascript·人工智能·python·学习·ecmascript·pyqt
江畔柳前堤17 天前
PyQt学习系列11-综合项目:多语言文件管理器
开发语言·网络·python·学习·django·pyqt
幽络源小助理17 天前
基于Yolov8+PyQT的老人摔倒识别系统源码
yolo·pyqt
江畔柳前堤18 天前
PyQt学习系列07-数据库操作与ORM集成
数据库·学习·算法·机器学习·架构·pyqt
江畔柳前堤18 天前
PyQt学习系列10-性能优化与调试技巧
开发语言·javascript·数据库·学习·性能优化·ecmascript·pyqt