尝试在pyqt5中的鼠标事件之间切换

Trying to toggle between mouse events in pyqt5

我正在尝试制作一个图形用户界面,用户可以在其中以拖动模式移动图像并切换到绘图模式以在 qgraphicsview 中的图像上绘图。我有我找到的示例中的代码,但我不知道如何在两个鼠标事件之间切换。我也在努力研究如何 link 两个 qgraphicsview 对象,以便在两者之间共享拖动和缩放事件。我的代码在下面,如果有任何意义,请不要犹豫。提前致谢。

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):
        super(PhotoViewer, self).__init__(parent)
        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:
                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)


#drawing events that im trying to add

#    def paintEvent(self, event):
#        painter = QPainter(self)
#        painter.drawPixmap(self.rect(), self.image)
#
#    def mousePressEvent(self, event):
#        if event.button() == Qt.LeftButton:
#            self.drawing = True
#            self.lastPoint = event.pos()
#
#    def mouseMoveEvent(self, event):
#        if event.buttons() and Qt.LeftButton and self.drawing:
#            painter = QPainter(self.image)
#            painter.setPen(QPen(Qt.blue, 7, Qt.SolidLine))
#            painter.drawLine(self.lastPoint, event.pos())
#            self.lastPoint = event.pos()
#            self.update()
#
#    def mouseReleaseEvent(self, event):
#        if event.button == Qt.LeftButton:
#            self.drawing = False



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

        self.viewer = PhotoViewer(self)
        self.viewer2 = PhotoViewer(self)
        # '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)

    def loadImage(self):
        self.viewer.setPhoto(QtGui.QPixmap(r'image.jpg'))
        self.viewer2.setPhoto(QtGui.QPixmap(r'image.jpg'))
        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 = Window()
    window.setGeometry(500, 300, 800, 600)
    window.show()
    sys.exit(app.exec_())

def drawmode 中有一个拼写错误,它调用 "toggleDrawMode" 而不是 "toggleDragMode"。除此之外,最好避免在视图上绘画(除非你真的需要并且知道你在做什么)或在移动鼠标时直接在图像上绘画,更好的方法可能是在鼠标按下时添加 QGraphicsPathItem 实际上在释放鼠标按钮 后在图像上绘画:

def mousePressEvent(self, event):
    if (event.button() == Qt.LeftButton and not self._photo.pixmap().isNull() 
        and self.dragMode() == QtWidgets.QGraphicsView.NoDrag):
            self.drawingPath = QtGui.QPainterPath()
            self.drawingPath.moveTo(self.mapToScene(event.pos()))
            self.drawingItem = self.scene().addPath(self.drawingPath)
            self.drawingItem.setPen(QtGui.QPen(Qt.blue, 7, Qt.SolidLine))
    else:
        super(PhotoViewer, self).mousePressEvent(event)

def mouseMoveEvent(self, event):
    if event.buttons() and Qt.LeftButton and self.drawingPath:
        self.drawingPath.lineTo(self.mapToScene(event.pos()))
        self.drawingItem.setPath(self.drawingPath)
    else:
        super(PhotoViewer, self).mouseMoveEvent(event)

def mouseReleaseEvent(self, event):
    if event.button() == Qt.LeftButton and self.drawingPath:
        pm = self._photo.pixmap()
        painter = QtGui.QPainter(pm)
        painter.setPen(QPen(Qt.red, 7, Qt.SolidLine))
        painter.drawPath(self.drawingPath)
        painter.end()
        self._photo.setPixmap(pm)
        self.scene().removeItem(self.drawingItem)
        self.drawingPath = None
    else:
        super(PhotoViewer, self).mouseReleaseEvent(event)

关于两个视图的"linking",如果拖动是指视图滚动,就link两个相对滚动条valueChangedsetValue其他,请记住,无论何时您想要应用转换,您都必须 blockSignals(True) 对所有 4 个滚动条,在两个视图上应用相同的转换,然后再次取消阻止滚动条的信号。