You need to enable JavaScript to run this app. 如何同时控制两个加载不同内容的QGraphicsView实现同步缩放平移
优惠活动
大模型
产品
解决方案
定价
更多

如何同时控制两个加载不同内容的QGraphicsView实现同步缩放平移

实现思路

  • 给两个QGraphicsView分别绑定独立的QGraphicsScene,各自添加不同的QGraphicsPixmapItem加载不同图片,解决同场景只能显示相同内容的问题
  • 关闭item的可移动属性,改为通过操作视图的视口实现平移,将其中一个视图的滚动条信号、缩放参数实时同步到另一个视图,实现操作完全同步

调整后的核心代码

可直接复用你现有的UI代码,主窗口逻辑修改如下:

import sys
from PyQt5 import QtWidgets
from PyQt5.QtCore import QRectF, Qt
from PyQt5.QtGui import QPixmap, QPainter, QColor
from PyQt5.QtWidgets import QGraphicsPixmapItem, QMainWindow, QGraphicsScene
from ui.preview_test import Ui_MainWindow

class mainwindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self._delta = 0.1
        self._is_dragging = False
        self._last_mouse_pos = None

        # 视图基础配置统一设置
        for view in [self.graphicsView_1, self.graphicsView_2]:
            view.setCursor(Qt.OpenHandCursor)
            view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
            view.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform)
            view.setBackgroundBrush(Qt.black)
            # 禁用视图自带的拖拽滚动,自定义实现同步逻辑
            view.setDragMode(QtWidgets.QGraphicsView.NoDrag)

        # 初始化两个独立场景
        self._scene1 = QGraphicsScene(self)
        self._scene2 = QGraphicsScene(self)
        self.graphicsView_1.setScene(self._scene1)
        self.graphicsView_2.setScene(self._scene2)

        # 分别加载不同图片,替换为你自己的图片路径即可
        self._item1 = QGraphicsPixmapItem()
        self._item1.setPixmap(QPixmap("第一张图片路径"))
        self._scene1.addItem(self._item1)

        self._item2 = QGraphicsPixmapItem()
        self._item2.setPixmap(QPixmap("第二张图片路径"))
        self._scene2.addItem(self._item2)

        # 双向绑定滚动条信号,任意一个视图平移都会同步到另一个
        self.graphicsView_1.horizontalScrollBar().valueChanged.connect(
            lambda val: self.graphicsView_2.horizontalScrollBar().setValue(val)
        )
        self.graphicsView_1.verticalScrollBar().valueChanged.connect(
            lambda val: self.graphicsView_2.verticalScrollBar().setValue(val)
        )
        self.graphicsView_2.horizontalScrollBar().valueChanged.connect(
            lambda val: self.graphicsView_1.horizontalScrollBar().setValue(val)
        )
        self.graphicsView_2.verticalScrollBar().valueChanged.connect(
            lambda val: self.graphicsView_1.verticalScrollBar().setValue(val)
        )

        self.show()

    def setBackground(self, color):
        if isinstance(color, QColor):
            brush = color
        elif isinstance(color, (str, Qt.GlobalColor)):
            color = QColor(color)
            brush = color if color.isValid() else Qt.black
        else:
            brush = Qt.black
        self.graphicsView_1.setBackgroundBrush(brush)
        self.graphicsView_2.setBackgroundBrush(brush)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            # 仅当鼠标落在两个视图区域内时激活拖拽逻辑
            pos = event.pos()
            if self.graphicsView_1.geometry().contains(pos) or self.graphicsView_2.geometry().contains(pos):
                self._is_dragging = True
                self._last_mouse_pos = event.pos()
                self.setCursor(Qt.ClosedHandCursor)
        super().mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self._is_dragging and self._last_mouse_pos is not None:
            # 计算鼠标偏移量,同步平移两个视图
            offset = event.pos() - self._last_mouse_pos
            for view in [self.graphicsView_1, self.graphicsView_2]:
                view.horizontalScrollBar().setValue(view.horizontalScrollBar().value() - offset.x())
                view.verticalScrollBar().setValue(view.verticalScrollBar().value() - offset.y())
            self._last_mouse_pos = event.pos()
        super().mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self._is_dragging = False
            self._last_mouse_pos = None
            self.setCursor(Qt.OpenHandCursor)
        super().mouseReleaseEvent(event)

    def wheelEvent(self, event):
        if event.angleDelta().y() > 0:
            self.zoom(1 + self._delta)
        else:
            self.zoom(1 - self._delta)
        event.accept()

    def zoom(self, factor):
        # 统一用第一个视图的缩放系数做边界判断,避免两个视图比例不一致
        current_factor = self.graphicsView_1.transform().scale(factor, factor).mapRect(QRectF(0, 0, 1, 1)).width()
        if current_factor < 0.07 or current_factor > 100:
            return
        # 同时给两个视图应用缩放
        for view in [self.graphicsView_1, self.graphicsView_2]:
            view.scale(factor, factor)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = mainwindow()
    app.exec_()

实现说明

  • 两个场景独立互不干扰,可分别加载不同图片、添加不同的图形元素
  • 滚动条信号双向绑定,无论操作哪个视图,另一个都会同步平移
  • 缩放操作同时作用于两个视图,统一用同一个基准值判断缩放边界,避免出现两个视图缩放比例不一致的问题
  • 拖拽逻辑直接操作视图滚动条,不需要依赖item的可移动属性,适配任意场景内容的同步

内容的提问来源于stack exchange,提问作者KimJitae

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.13 14:30:00