简体   繁体   English

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

[英]Trying to toggle between mouse events in pyqt5

I am trying to make a gui where the user can move the image around in drag mode and switch to draw mode to draw on an image in a qgraphicsview. 我正在尝试制作一个gui,用户可以在其中以拖动模式移动图像并切换到绘制模式以在qgraphicsview中绘制图像。 I have the code from examples I have found but I can't figure out how to toggle between the two mouse events. 我有找到的示例中的代码,但无法弄清楚如何在两个鼠标事件之间切换。 I'm also struggling with how to link the two qgraphicsview objects so that drag and zoom events are shared between the two. 我也在努力链接两个qgraphicsview对象,以便在两个对象之间共享拖动和缩放事件。 My code is below if anything doesnt make any sense dont hesitate to ask. 我的代码在下面,如果没有任何意义请不要犹豫。 Thanks in advance. 提前致谢。

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_())

There's a typo in def drawmode , which calls "toggleDra w Mode" instead of "toggleDra g Mode". def drawmode有一个错字,它称为“ toggleDra w Mode”而不是“ toggleDra g Mode”。 Besides that, it's better to avoid painting on a view (unless you really need to and know what you're doing) or directly on an image while moving the mouse, and a better approach may be to add a QGraphicsPathItem on mouse press and actually paint on the image after releasing the mouse button: 除此之外,最好避免在视图上绘画(除非您确实需要并知道自己在做什么)或在移动鼠标时直接在图像上绘画,并且更好的方法可能是在鼠标按下时添加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)

About the "linking" of the two views, if the drag is referred to the view scrolling, just link the two relative scrollbars valueChanged with setValue on the other, and remember that whenever you want to apply a transform you have to blockSignals(True) for all 4 scrollbars, apply the same transform on both views, and then un-block signals for the scrollbars again. 关于两个视图的“链接”,如果拖动涉及视图滚动,则只需将两个相对滚动条的valueChangedsetValue链接在一起,并记住,每当您要应用转换时,都必须使用blockSignals(True)对于所有4个滚动条,在两个视图上应用相同的变换,然后再次取消阻止滚动条的信号。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM