首页 文章

如何在QGraphicsView中启用平移和缩放

提问于
浏览
6

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

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

QGraphicsScene,QImage,QGraphicsView

我有三个班(只是测试)

具有QGraphicsView元素的

  • ViewerDemo:
"""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
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)正是应用程序执行的地方:

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中获取坐标) .

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

或者,有没有更好的Qt课程来做这个,还有一些更好的方法你能帮我吗?

这是我到目前为止使用此代码

2 回答

  • 0

    使用 QGraphicsView 的内置功能并不难 .

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

    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(QtCore.QPoint(event.pos()))
            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(QtCore.QPoint(event.pos()))
            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_())
    
  • 20

    使用普通的PIL(枕头)库可以打开高达几千兆字节的TIFF文件 . 它不是很容易,但它确实有效 .

    你可以看到example here,第二个例子是粗体 EDIT 字符串可以打开,移动和缩放TIFF文件 .

相关问题