【问题标题】:How can I override a pyqt4 QGraphicsView.mousePressEvent?如何覆盖 pyqt4 QGraphicsView.mousePressEvent?
【发布时间】:2017-04-02 18:21:56
【问题描述】:

我正在尝试在 pyqt4 中调整照片查看器(我从本网站的另一个问题中获得了代码)。默认情况下,鼠标滚轮缩放,鼠标左键用于平移/拖动(不知道具体如何调用)图像。我想添加左键单击图像时获取像素信息的功能,所以我打算有一个按钮来从“平移”模式更改为“像素信息”模式。我的尝试如下所示,但它的行为不符合我的预期。

当我使用第一个 GUI 按钮加载图像并放大图像时,如果我不平移/拖动图像,则单击第二个 GUI 按钮会禁用平移/拖动,当我单击图像时,提供我点击的像素的像素信息。这正是我所期望的。

但是,如果我先放大然后平移/拖动图像,当我单击第二个 GUI 按钮时,它不再禁用平移/拖动并且不打印像素信息。

由于某种原因,我不明白(我希望有人能启发我)在缩放后拖动图像似乎锁定了平移/拖动方法并且不允许我更改它。谁能告诉我为什么。

from PyQt4 import QtCore, QtGui

class PhotoViewer(QtGui.QGraphicsView):
    def __init__(self, parent):
        super(PhotoViewer, self).__init__(parent)
        self._zoom = 0
        self._scene = QtGui.QGraphicsScene(self)
        self._photo = QtGui.QGraphicsPixmapItem()
        self._scene.addItem(self._photo)
        self.setScene(self._scene)
        self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30)))
        self.setFrameShape(QtGui.QFrame.NoFrame)

    def fitInView(self):
        rect = QtCore.QRectF(self._photo.pixmap().rect())
        if not rect.isNull():
            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.centerOn(rect.center())
            self._zoom = 0

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

    def wheelEvent(self, event):
        if not self._photo.pixmap().isNull():
            if event.delta() > 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 printPixInfo(self,event):
        print event.pos()

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.viewer = PhotoViewer(self)
        # 'Load image' button
        self.btnLoad = QtGui.QToolButton(self)
        self.btnLoad.setText('Load image')
        self.btnLoad.clicked.connect(self.loadImage)
        # Button to change from drag/pan to getting pixel info
        self.btnPixInfo = QtGui.QToolButton(self)
        self.btnPixInfo.setText('Enter pixel info mode')
        self.btnPixInfo.clicked.connect(self.pixInfo)
        # Arrange layout
        VBlayout = QtGui.QVBoxLayout(self)
        VBlayout.addWidget(self.viewer)
        HBlayout = QtGui.QHBoxLayout()
        HBlayout.setAlignment(QtCore.Qt.AlignLeft)
        HBlayout.addWidget(self.btnLoad)
        HBlayout.addWidget(self.btnPixInfo)
        VBlayout.addLayout(HBlayout)

    def loadImage(self):
        self.viewer.setPhoto(QtGui.QPixmap('pic.jpg'))

    def pixInfo(self):
        print 'Now in pixel info mode'
        self.viewer._photo.mousePressEvent = self.viewer.printPixInfo

if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 800, 600)
    window.show()
    sys.exit(app.exec_())

我还想知道,一旦我成功更改了鼠标单击方法,将鼠标左键单击返回到默认平移/拖动行为的语法是什么。

我是python新手,所以请尽量不要批评我。谢谢。

【问题讨论】:

    标签: python pyqt pyqt4 mouseevent qgraphicsview


    【解决方案1】:

    问题在于,通过完全覆盖 mousePressEvent,您将失去所有默认行为(例如,使用鼠标平移)。最好使用自定义信号来通知照片何时被点击。由于图形视图已经有一个用于更改拖动模式的 API,您可以添加一个用于切换模式的插槽:

    class PhotoViewer(QtGui.QGraphicsView):
        photoClicked = QtCore.pyqtSignal(QtCore.QPoint)    
        ...
    
        def toggleDragMode(self):
            if self.dragMode() == QtGui.QGraphicsView.ScrollHandDrag:
                self.setDragMode(QtGui.QGraphicsView.NoDrag)
            elif not self._photo.pixmap().isNull():
                self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag)
    
        def mousePressEvent(self, event):
            if self._photo.isUnderMouse():
                self.photoClicked.emit(QtCore.QPoint(event.pos()))  
            # keep the default behaviour
            super(PhotoViewer, self).mousePressEvent(event)
    

    这两个新的 API 可用于为您提供所需的功能:

    class Window(QtGui.QWidget):
        def __init__(self):
            ...
            # add a line-edit to display the position info
            self.editPixInfo = QtGui.QLineEdit(self)
            self.editPixInfo.setReadOnly(True)
            self.viewer.photoClicked.connect(self.photoClicked)
            ...
            HBlayout.addWidget(self.editPixInfo)
    
        def pixInfo(self):
            # switch modes
            self.viewer.toggleDragMode()
    
        def photoClicked(self, pos):
            # handle photo-click signals
            if self.viewer.dragMode() == QtGui.QGraphicsView.NoDrag:
                self.editPixInfo.setText('%d, %d' % (pos.x(), pos.y()))
    

    【讨论】:

    • 嗯,这正是我想要的,所以非常感谢你,你是明星。正如我所提到的,我是一个 python 新手,我仍然习惯于整个 OOP 的做事方式,我需要很长时间才能知道哪些类方法可用.我能理解你是如何使它工作的(大部分)所以感谢你的教训。但是请你澄清一点。您修改后的 mousePressEvent 方法中超级函数的确切用途是什么?
    • @AndrewBirch。它调用基类方法以保持默认行为。
    • 所以通过调用超级函数,你的mousePressEvent代码本质上是附加到基类方法代码的开头而不是替换它?对吗?
    • @AndrewBirch。是的 - 您只是在观察事件并提供一些额外的功能,然后再将其传递不变。
    • 您能否将代码限制为仅更改了的部分,还是到处都是?文字表明它应该只是几个变化,但我没有仔细检查。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2015-09-09
    • 1970-01-01
    • 2012-12-17
    • 2020-07-28
    相关资源
    最近更新 更多