Python 链接两个qgraphicsview对象之间的缩放

Python 链接两个qgraphicsview对象之间的缩放,python,pyqt5,qgraphicsview,Python,Pyqt5,Qgraphicsview,我正在尝试链接两个qgraphicsview对象,以便当一个窗口放大时,另一个qgraphicsview也会放大。我试图通过在一个窗口要缩放时调用test函数来实现这一点。然后我尝试在另一个qgraphicsview对象中调用self.scale(factor,factor)。我得到一个错误:AttributeError:“PhotoViewer”对象没有属性“viewer”。我试图调用类ui self.viewer,但从错误判断,我仍然在Photoviewer对象中。当一个窗口被放大时,如何从

我正在尝试链接两个qgraphicsview对象,以便当一个窗口放大时,另一个qgraphicsview也会放大。我试图通过在一个窗口要缩放时调用test函数来实现这一点。然后我尝试在另一个qgraphicsview对象中调用self.scale(factor,factor)。我得到一个错误:AttributeError:“PhotoViewer”对象没有属性“viewer”。我试图调用类ui self.viewer,但从错误判断,我仍然在Photoviewer对象中。当一个窗口被放大时,如何从中调用其他窗口self.scale?提前谢谢

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtGui import QPixmap, QPainter, QPen
import sys

class PhotoViewer(QtWidgets.QGraphicsView):
    photoClicked = QtCore.pyqtSignal(QtCore.QPoint)

    def __init__(self, parent,num_view):
        super(PhotoViewer, self).__init__(parent)
        #to track which viewer
        self.num_view=num_view
        self.drawmode=0
        self._zoom = 0
        self.drawing = False
        self.lastPoint = QPoint()
        self.image=False
        self.image=QPixmap(r"image.jpg")
        self._empty = True
        self._scene = QtWidgets.QGraphicsScene(self)
        self._photo = QtWidgets.QGraphicsPixmapItem()
        self._scene.addItem(self._photo)
        self.setScene(self._scene)
        self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30)))
        self.setFrameShape(QtWidgets.QFrame.NoFrame)

    def hasPhoto(self):
        return not self._empty

    def fitInView(self, scale=True):
        rect = QtCore.QRectF(self._photo.pixmap().rect())
        if not rect.isNull():
            self.setSceneRect(rect)
            if self.hasPhoto():
                unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1))
                self.scale(1 / unity.width(), 1 / unity.height())
                viewrect = self.viewport().rect()
                scenerect = self.transform().mapRect(rect)
                factor = min(viewrect.width() / scenerect.width(),
                             viewrect.height() / scenerect.height())
                self.scale(factor, factor)
            self._zoom = 0

    def setPhoto(self, pixmap=None):
        self._zoom = 0
        if pixmap and not pixmap.isNull():
            self._empty = False
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
            self._photo.setPixmap(pixmap)
        else:
            self._empty = True
            self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
            self._photo.setPixmap(QtGui.QPixmap())
        self.fitInView()

    def wheelEvent(self, event):
        if self.hasPhoto():
            if event.angleDelta().y() > 0:
                factor = 1.25
                self._zoom += 1
            else:
                factor = 0.8
                self._zoom -= 1
            if self._zoom > 0:
                ui.test(self,self.num_view,factor)

                self.scale(factor, factor)
            elif self._zoom == 0:
                self.fitInView()
            else:
                self._zoom = 0


    def toggleDragMode(self):
        if self.dragMode() == QtWidgets.QGraphicsView.ScrollHandDrag:
            self.setDragMode(QtWidgets.QGraphicsView.NoDrag)
        elif not self._photo.pixmap().isNull():
            self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)


class ui(QtWidgets.QWidget):
    def __init__(self):
        super(ui, self).__init__()

        self.viewer = PhotoViewer(self,1)
        self.viewer2 = PhotoViewer(self,2)
        # 'Load image' button
        self.btnLoad = QtWidgets.QToolButton(self)
        self.btnLoad.setText('Load image')
        self.btnLoad.clicked.connect(self.loadImage)
        # draw mode
        self.btndraw = QtWidgets.QToolButton(self)
        self.btndraw.setText('Draw Mode')
        self.btndraw.clicked.connect(self.drawmode)
        # Button to change from drag/pan to getting pixel info
        self.btnPixInfo = QtWidgets.QToolButton(self)
        self.btnPixInfo.setText('Enter pixel info mode')
        self.btnPixInfo.clicked.connect(self.pixInfo)
        self.editPixInfo = QtWidgets.QLineEdit(self)
        self.editPixInfo.setReadOnly(True)
        self.viewer.photoClicked.connect(self.photoClicked)
        # Arrange layout
        VBlayout = QtWidgets.QVBoxLayout(self)
        HBlayout2 = QtWidgets.QHBoxLayout()
        HBlayout2.setAlignment(QtCore.Qt.AlignLeft)
        HBlayout2.addWidget(self.viewer2)
        HBlayout2.addWidget(self.viewer)
        HBlayout = QtWidgets.QHBoxLayout()
        HBlayout.setAlignment(QtCore.Qt.AlignLeft)
        HBlayout.addWidget(self.btnLoad)
        HBlayout.addWidget(self.btnPixInfo)
        HBlayout.addWidget(self.btndraw)
        HBlayout.addWidget(self.editPixInfo)
        VBlayout.addLayout(HBlayout2)
        VBlayout.addLayout(HBlayout)
        #scroll bars
        self.viewer.horizontalScrollBar().valueChanged.connect(self.horizontal_scroll)
        self.viewer.verticalScrollBar().valueChanged.connect(self.vertical_scroll)
        self.viewer2.horizontalScrollBar().valueChanged.connect(self.horizontal_scroll2)
        self.viewer2.verticalScrollBar().valueChanged.connect(self.vertical_scroll2)

    def test(self,num,factor):
        if num==1:
            self.viewer2.scale(factor,factor)
        if num==2:
            self.viewer.scale(factor,factor)


        #auto scroll
    def horizontal_scroll(self):
        self.viewer2.horizontalScrollBar().setValue(self.viewer.horizontalScrollBar().value())    
    def horizontal_scroll2(self):
        self.viewer.horizontalScrollBar().setValue(self.viewer2.horizontalScrollBar().value())
    def vertical_scroll(self):
        self.viewer2.verticalScrollBar().setValue(self.viewer.verticalScrollBar().value())   
    def vertical_scroll2(self):
        self.viewer.verticalScrollBar().setValue(self.viewer2.verticalScrollBar().value())


    def loadImage(self):
        self.viewer.setPhoto(QtGui.QPixmap(r'temp.png'))
        self.viewer2.setPhoto(QtGui.QPixmap(r'temp.png'))
        self.image=QPixmap(r"image.jpg")

    def drawmode(self):        
        self.viewer.toggleDrawMode()

    def pixInfo(self):
        self.viewer.toggleDragMode()

    def photoClicked(self, pos):
        if self.viewer.dragMode()  == QtWidgets.QGraphicsView.NoDrag:
            self.editPixInfo.setText('%d, %d' % (pos.x(), pos.y()))


if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = ui()
    window.setGeometry(500, 300, 800, 600)
    window.show()
    sys.exit(app.exec_())

您可以使用以下信号,而不是直接缩放视图:

将以下代码添加到PhotoViewer:

class PhotoViewer(QtWidgets.QGraphicsView):
    scaled = QtCore.pyqtSignal(int, int, QtGui.QTransform, int)

    ....

    def scale(self, horz, vert):
        super().scale(horz, vert)
        self.scaled.emit(self.horizontalScrollBar().value(),
                         self.verticalScrollBar().value(), 
                         self.transform(), 
                         self._zoom
                        )

    def set_transform(self, horz_scroll, vert_scroll, transform, zoom):
        # temporary block signals from scroll bars to prevent interference
        horz_blocked = self.horizontalScrollBar().blockSignals(True)
        vert_blocked = self.verticalScrollBar().blockSignals(True)
        self._zoom = zoom
        self.setTransform(transform)
        dx = horz_scroll - self.horizontalScrollBar().value()
        dy = vert_scroll - self.verticalScrollBar().value()
        self.horizontalScrollBar().setValue(dx)
        self.verticalScrollBar().setValue(dy)
        self.horizontalScrollBar().blockSignals(horz_blocked)
        self.verticalScrollBar().blockSignals(vert_blocked)
ui

class ui(QtWidgets.QWidget):
    def __init__(self):
        ....
        self.viewer.scaled.connect(self.viewer2.set_transform)
        self.viewer2.scaled.connect(self.viewer.set_transform)

同时删除对
ui.test()
form
PhotoViewer.wheeleevent

的调用,而不是尝试直接缩放视图,您可以使用以下信号:

将以下代码添加到PhotoViewer:

class PhotoViewer(QtWidgets.QGraphicsView):
    scaled = QtCore.pyqtSignal(int, int, QtGui.QTransform, int)

    ....

    def scale(self, horz, vert):
        super().scale(horz, vert)
        self.scaled.emit(self.horizontalScrollBar().value(),
                         self.verticalScrollBar().value(), 
                         self.transform(), 
                         self._zoom
                        )

    def set_transform(self, horz_scroll, vert_scroll, transform, zoom):
        # temporary block signals from scroll bars to prevent interference
        horz_blocked = self.horizontalScrollBar().blockSignals(True)
        vert_blocked = self.verticalScrollBar().blockSignals(True)
        self._zoom = zoom
        self.setTransform(transform)
        dx = horz_scroll - self.horizontalScrollBar().value()
        dy = vert_scroll - self.verticalScrollBar().value()
        self.horizontalScrollBar().setValue(dx)
        self.verticalScrollBar().setValue(dy)
        self.horizontalScrollBar().blockSignals(horz_blocked)
        self.verticalScrollBar().blockSignals(vert_blocked)
ui

class ui(QtWidgets.QWidget):
    def __init__(self):
        ....
        self.viewer.scaled.connect(self.viewer2.set_transform)
        self.viewer2.scaled.connect(self.viewer.set_transform)
同时删除对
ui.test()
form
PhotoViewer.wheeleevent
的调用