标注工具核心代码解析——class AnnotationVie【canvas.py]

详细解析

🔧 构造函数解析

python 复制代码
def __init__(self, parent=None):
    # 🏗️ 继承链调用:调用QGraphicsView的构造函数进行基础初始化
    super(AnnotationView, self).__init__(parent)
    
    # 🖱️ 鼠标跟踪设置:启用连续鼠标位置监听
    # 默认情况下,只有按下鼠标时才触发移动事件
    # 设置为True后,鼠标悬停移动也会触发事件
    self.setMouseTracking(True)
    
    # 📜 滚动条策略:强制显示滚动条
    # ScrollBarAlwaysOn = 始终显示,不管内容是否超出视图
    self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
    self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
    
    # 🖐️ 拖拽模式设置:启用手动拖拽滚动
    # ScrollHandDrag = 鼠标变成手形,可以拖拽移动视图内容
    self.setDragMode(QtWidgets.QGraphicsView.DragMode.ScrollHandDrag)
    
    # 🔍 缩放参数:定义缩放步长
    self.factor = 1.2  # 每次缩放20%

🎯 核心方法解析

🖱️ 滚轮事件处理

python 复制代码
def wheelEvent(self, event: QtGui.QWheelEvent):
    # 📐 获取滚轮滚动信息
    angel = event.angleDelta()  # 返回QPoint对象,包含x和y方向的角度增量
    angelX, angelY = angel.x(), angel.y()  # 分别提取水平和垂直滚动量
    
    # 📍 获取鼠标当前位置(视图坐标系)
    point = event.pos()
    
    # 🔍 根据滚动方向进行缩放
    if angelY > 0:  # 向上滚动 = 放大
        self.zoom(self.factor, point)
    else:  # 向下滚动 = 缩小
        self.zoom(1 / self.factor, point)

继承调用链

复制代码
用户滚动鼠标 → Qt事件系统 → QGraphicsView.wheelEvent() → AnnotationView.wheelEvent()

🔍 缩放功能方法

python 复制代码
def zoom_in(self):
    # 🔍 放大:直接调用zoom方法,不指定鼠标位置
    self.zoom(self.factor)

def zoom_out(self):
    # 🔍 缩小:使用缩放因子的倒数
    self.zoom(1 / self.factor)

def zoomfit(self):
    # 📐 自适应缩放:调用QGraphicsView的内置方法
    # fitInView继承自QGraphicsView,用于自动调整视图以完全显示指定区域
    self.fitInView(
        0, 0,  # 起始坐标
        self.scene().width(), self.scene().height(),  # 场景的宽度和高度
        QtCore.Qt.AspectRatioMode.KeepAspectRatio  # 保持宽高比
    )

🎨 核心缩放方法深度解析

复制代码
def zoom(self, factor, point=None):
    # 📍 坐标转换:将视图坐标转换为场景坐标
    # mapToScene()是QGraphicsView的方法,用于坐标系转换
    mouse_old = self.mapToScene(point) if point is not None else None

    # 🧮 计算缩放后的像素比例
    # transform()获取当前变换矩阵
    # scale()创建新的缩放变换
    # mapRect()应用变换到矩形
    pix_widget = self.transform().scale(factor, factor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()
    
    # 🚫 缩放限制检查
    if pix_widget > 30 and factor > 1:  # 防止过度放大
        return
    if pix_widget < 0.01 and factor < 1:  # 防止过度缩小
        return

    # 🔍 执行缩放:调用QGraphicsView的scale方法
    self.scale(factor, factor)
    
    # 📐 以鼠标为中心的缩放调整
    if point is not None:
        mouse_now = self.mapToScene(point)  # 缩放后的鼠标场景坐标
        
        # 获取当前视图中心点的场景坐标
        center_now = self.mapToScene(self.viewport().width() // 2, self.viewport().height() // 2)
        
        # 🧮 计算新的视图中心:确保鼠标位置保持不变
        center_new = mouse_old - mouse_now + center_now
        
        # 🎯 调整视图中心:调用QGraphicsView的centerOn方法
        self.centerOn(center_new)

🔄 方法调用关系图

复制代码
用户操作
    ↓
┌─────────────────────┐
│   wheelEvent()      │ ← Qt事件系统
│   zoom_in()         │ ← 工具栏按钮
│   zoom_out()        │ ← 工具栏按钮  
│   zoomfit()         │ ← 菜单选项
└─────────────────────┘
            ↓
    ┌─────────────┐
    │   zoom()    │ ← 核心缩放逻辑
    └─────────────┘
            ↓
┌─────────────────────┐
│  QGraphicsView方法   │
│  • mapToScene()     │ ← 坐标转换
│  • transform()      │ ← 获取变换矩阵
│  • scale()          │ ← 执行缩放
│  • centerOn()       │ ← 调整视图中心
│  • fitInView()      │ ← 自适应显示
└─────────────────────┘

🧠 设计思路分析

🎯 核心设计模式

  1. *� 模板方法模式
    • 重写wheelEvent()自定义滚轮行为
    • 保留Qt的事件处理机制
  1. *� 适配器模式
    • 封装复杂的Qt Graphics Framework
    • 提供简洁的缩放接口
  1. *� 策略模式
    • 不同的缩放策略(以鼠标为中心 vs 以视图中心)

💡 关键技术点

复制代码
# 🔄 坐标系转换
视图坐标 → mapToScene() → 场景坐标

# 🎯 变换矩阵操作  
当前变换 → scale() → 新变换 → mapRect() → 像素计算

# 📐 几何计算
鼠标位置保持 = 旧鼠标坐标 - 新鼠标坐标 + 当前中心

🛡️ 错误处理机制

  • 缩放限制:防止过度放大/缩小导致性能问题
  • 坐标验证:确保变换矩阵计算正确
  • 边界检查:避免视图超出合理范围

这个类完美地展示了Qt Graphics Framework的高级用法面向对象设计的继承机制

源代码

python 复制代码
class AnnotationView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(AnnotationView, self).__init__(parent)
        self.setMouseTracking(True)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn)
        self.setDragMode(QtWidgets.QGraphicsView.DragMode.ScrollHandDrag)
        self.factor = 1.2

    def wheelEvent(self, event: QtGui.QWheelEvent):
        angel = event.angleDelta()
        angelX, angelY = angel.x(), angel.y()
        point = event.pos()
        if angelY > 0:
            self.zoom(self.factor, point)
        else:
            self.zoom(1 / self.factor, point)

    def zoom_in(self):
        self.zoom(self.factor)

    def zoom_out(self):
        self.zoom(1 / self.factor)

    def zoomfit(self):
        self.fitInView(0, 0, self.scene().width(), self.scene().height(), QtCore.Qt.AspectRatioMode.KeepAspectRatio)

    def zoom(self, factor, point=None):
        mouse_old = self.mapToScene(point) if point is not None else None

        pix_widget = self.transform().scale(factor, factor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()
        if pix_widget > 30 and factor > 1: return
        if pix_widget < 0.01 and factor < 1: return

        self.scale(factor, factor)
        if point is not None:
            mouse_now = self.mapToScene(point)
            center_now = self.mapToScene(self.viewport().width() // 2, self.viewport().height() // 2)
            center_new = mouse_old - mouse_now + center_now
            self.centerOn(center_new)
相关推荐
thinking-fish14 分钟前
提示词Prompts(2)
python·langchain·提示词·提示词模板
道剑剑非道16 分钟前
QT开发技术【ffmpeg EVideo录屏软件 一】
开发语言·qt·ffmpeg
2501_9118285031 分钟前
Python训练营---DAY53
python·深度学习
oioihoii35 分钟前
C++11 Generalized(non-trivial) Unions:从入门到精通
java·开发语言·c++
谢尔登1 小时前
【Three.js】初识 Three.js
开发语言·javascript·ecmascript
该用户已不存在1 小时前
Python生态全景图:8大主流框架怎么选,一篇文章告诉你
python·django·flask
H2122021651 小时前
P5 QT项目----会学网络调试助手服务端(5.1)
开发语言·网络·qt
C++ 老炮儿的技术栈1 小时前
文本文件与二进制文件的区别
大数据·c语言·开发语言·c++·git·算法·visual studio
君鼎2 小时前
C++标准库大全(STL)
开发语言·c++·stl
广州正荣2 小时前
Python爬虫进阶:气象数据爬取中的多线程优化与异常处理技巧
人工智能·python·科技