如何在 QGraphicsView 中启用平移和缩放 [英] How to enable Pan and Zoom in a QGraphicsView

查看:177
本文介绍了如何在 QGraphicsView 中启用平移和缩放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 python 和 Qt Designer 来实现加载 tiff 图像并在某些鼠标事件(滚轮 - 缩放,按下滚轮 - 平移)上启用平移和缩放.

I am using python and Qt Designer to implement loading tiff images and to enable Pan and Zoom on some mouse event (wheel - zoom, press wheel - pan).

我正在研究一些可以处理图像等的选项和类,到目前为止我发现:

I was looking into some options and classes that can work with images etc, and so far I have found:

QGraphicsScene、QImage、QGraphicsView

QGraphicsScene, QImage, QGraphicsView

我有三个班级(只是测试)

I have three classes (just testing)

  1. ViewerDemoQGraphicsView 元素:

    """description of class"""
    # Form implementation generated from reading ui file 'GraphicsViewdemo.ui'
    try:
    _fromUtf8 = QtCore.QString.fromUtf8
    except AttributeError:
        def _fromUtf8(s):
            return s
        class Ui_Dialog(object):
            def setupUi(self, Dialog):
                Dialog.setObjectName(("Dialog"))
                Dialog.resize(500, 500)
            self.graphicsView = QtGui.QGraphicsView(Dialog)
            self.graphicsView.setGeometry(QtCore.QRect(0, 0, 500, 500))
            self.graphicsView.setObjectName(("graphicsView"))
            self.retranslateUi(Dialog)
            QtCore.QMetaObject.connectSlotsByName(Dialog)
        def retranslateUi(self, Dialog):
            Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None,
QtGui.QApplication.UnicodeUTF8))

  • MyForm类,也就是QDialog,这里我调用类ViewerDemo,加载Image,把图片放入QGraphicsView

  • MyForm class, that is QDialog, where I call class ViewerDemo, loading Image, and put image into QGraphicsView

        import sys
        from ViewerDemo import *
        from PyQt4 import QtGui
        class MyForm(QtGui.QDialog):
            def __init__(self, url, parent=None):
                QtGui.QWidget.__init__(self, parent)
    
    
                self.ui = Ui_Dialog()
                self.ui.setupUi(self)
                self.scene = QtGui.QGraphicsScene(self)
               self.image = QtGui.QImage(url)
                pixmap= QtGui.QPixmap.fromImage(self.image)
                item=QtGui.QGraphicsPixmapItem(pixmap)
                self.scene.addItem(item)
                self.ui.graphicsView.setScene(self.scene)
                self.scale = 1
                QtCore.QObject.connect(self.scene, QtCore.SIGNAL('mousePressEvent()'),self.mousePressEvent)
    
        def mousePressEvent(self, event):
            print ('PRESSED : ',event.pos())
    

  • (3) 就是应用程序执行的地方:

    (3) is just where the application is executing:

        from PyQt4 import QtGui, QtCore
        import sys
        from MyForm import MyForm
        if __name__ == "__main__":
            app = QtGui.QApplication(sys.argv)
            url = "D:/probaTiff"
            myapp = MyForm(url)
            myapp.show()
            sys.exit(app.exec_())
    

    我找到了如何通过单击鼠标(左键和滚轮单击)来打印像素坐标(例如,我需要它来获取图片 WGS84 坐标系中的坐标).

    I found how to do something on mouse-click (left and wheel click), to print pixel coordinates (I will need that to get the coordinates in the Coordinate System of the picture WGS84, for example).

    我更需要的是如何缩放图片(滚轮或双击,等等)和平移图片(按住鼠标左键或按住滚轮).

    What I need more, is how to zoom picture (wheel or double click, whatever) and to pan picture (holding left mouse click or holding wheel).

    或者,是否有一些更好的 Qt 类可以做到这一点,以及一些更好的方法你能帮我吗?

    Or, is there some better Qt classes for doing this, and some better way Can you help me please?

    这是我目前使用的代码

    推荐答案

    使用 QGraphicsView 的内置功能,这并不难做到.

    This is not too difficult to do using the built in capabilities of QGraphicsView.

    下面的演示脚本具有左键平移和滚轮缩放(包括锚定到当前光标位置).fitInView 方法已被重新实现,因为内置版本添加了一个无法删除的奇怪的固定边距.

    The demo script below has left-button panning and wheel zoom (including anchoring to the current cursor position). The fitInView method has been reimplemented because the built in version adds a weird fixed margin that can't be removed.

    PyQt4 版本:

    from PyQt4 import QtCore, QtGui
    
    class PhotoViewer(QtGui.QGraphicsView):
        photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
    
        def __init__(self, parent):
            super(PhotoViewer, self).__init__(parent)
            self._zoom = 0
            self._empty = True
            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 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(QtGui.QGraphicsView.ScrollHandDrag)
                self._photo.setPixmap(pixmap)
            else:
                self._empty = True
                self.setDragMode(QtGui.QGraphicsView.NoDrag)
                self._photo.setPixmap(QtGui.QPixmap())
            self.fitInView()
    
        def wheelEvent(self, event):
            if self.hasPhoto():
                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 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(self.mapToScene(event.pos()).toPoint())
            super(PhotoViewer, self).mousePressEvent(event)
    
    
    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)
            self.editPixInfo = QtGui.QLineEdit(self)
            self.editPixInfo.setReadOnly(True)
            self.viewer.photoClicked.connect(self.photoClicked)
            # 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)
            HBlayout.addWidget(self.editPixInfo)
            VBlayout.addLayout(HBlayout)
    
        def loadImage(self):
            self.viewer.setPhoto(QtGui.QPixmap('image.jpg'))
    
        def pixInfo(self):
            self.viewer.toggleDragMode()
    
        def photoClicked(self, pos):
            if self.viewer.dragMode()  == QtGui.QGraphicsView.NoDrag:
                self.editPixInfo.setText('%d, %d' % (pos.x(), pos.y()))
    
    
    if __name__ == '__main__':
        import sys
        app = QtGui.QApplication(sys.argv)
        window = Window()
        window.setGeometry(500, 300, 800, 600)
        window.show()
        sys.exit(app.exec_())
    

    PyQt5 版本:

    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class PhotoViewer(QtWidgets.QGraphicsView):
        photoClicked = QtCore.pyqtSignal(QtCore.QPoint)
    
        def __init__(self, parent):
            super(PhotoViewer, self).__init__(parent)
            self._zoom = 0
            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)
    
        def mousePressEvent(self, event):
            if self._photo.isUnderMouse():
                self.photoClicked.emit(self.mapToScene(event.pos()).toPoint())
            super(PhotoViewer, self).mousePressEvent(event)
    
    
    class Window(QtWidgets.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.viewer = PhotoViewer(self)
            # 'Load image' button
            self.btnLoad = QtWidgets.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 = 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)
            VBlayout.addWidget(self.viewer)
            HBlayout = QtWidgets.QHBoxLayout()
            HBlayout.setAlignment(QtCore.Qt.AlignLeft)
            HBlayout.addWidget(self.btnLoad)
            HBlayout.addWidget(self.btnPixInfo)
            HBlayout.addWidget(self.editPixInfo)
            VBlayout.addLayout(HBlayout)
    
        def loadImage(self):
            self.viewer.setPhoto(QtGui.QPixmap('image.jpg'))
    
        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__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.setGeometry(500, 300, 800, 600)
        window.show()
        sys.exit(app.exec_())
    

    这篇关于如何在 QGraphicsView 中启用平移和缩放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆