标注工具核心代码解析——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)
相关推荐
灯澜忆梦6 小时前
GO_并发编程---定时器
开发语言·后端·golang
-银雾鸢尾-6 小时前
C#中的StringBuilder相关方法
开发语言·c#
-银雾鸢尾-6 小时前
C#中结构体与类的区别;抽象类与接口的区别
开发语言·c#
大模型码小白7 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
麻雀飞吧8 小时前
最新量化学习路径,交易认知和技术实现要并行
人工智能·python
段一凡-华北理工大学9 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
Ljwuhe10 小时前
C++——多态
开发语言·c++
心平气和量大福大10 小时前
C#-WPF-Window主窗体
开发语言·c#·wpf
从零开始的代码生活_12 小时前
C++ 继承详解:访问控制、对象模型、菱形继承与设计取舍
开发语言·c++·后端·学习·算法
云小逸12 小时前
【C++ 第七阶段:模板、泛型编程与工程综合详解】
开发语言·c++