PySide:让 SVG 图像跟随鼠标移动而无需拖放?

PySide: Have an SVG image follow mouse without drag and drop?

我正在尝试将 SVG 图像放置在另一个应用程序中最终将成为 QGroupBox 的位置。然后,在第一次单击 SVG 时,SVG "sticks" 到鼠标(就像在拖放过程中按住鼠标按钮一样)。第二次单击将释放 ("drop") 图像。

我一直在阅读但不太了解小部件、项目、场景和视图之间的性质/关系。我下面的代码可以工作,但不太正确。图像几乎主动避开了鼠标。对于非 C、非 C++、PyQt/PySide 初学者,在某处有明确的解释吗?或者对我哪里出错有简单的解释吗?

#!/usr/bin/env python2
# -*- coding: utf-8 -*-

import sys
from PySide.QtCore import *
from PySide.QtGui  import *
from PySide.QtSvg  import *


class Image(QGraphicsSvgItem):

    def __init__(self, parent=None):
        super(Image, self).__init__("image.svg", parent)
        self.parent = parent

        self.setFlags(QGraphicsItem.ItemIsSelectable |
                      QGraphicsItem.ItemIsMovable)

        self.setAcceptsHoverEvents(True)

        self.svgSize  = self.renderer().defaultSize()
        self.width    = self.svgSize.width()
        self.height   = self.svgSize.height()
        self.absolute = None  # Image's absolute (global) position
        self.mobile   = 0     # Initially immobile
        self.scene    = None  # Not in a scene yet
        self.view     = None  # Not in a view yet

    def hoverEnterEvent(self, event):
        print "Enter"

    def hoverLeaveEvent(self, event):
        print "Leave"

    def hoverMoveEvent(self, event):
        print "Moving"
        self.absolute = QCursor.pos()
        if self.view:
            relative = self.view.mapFromGlobal(self.absolute)
            if self.mobile:
#               self.setPos(relative)
                self.setPos(self.absolute)


class Viewport(QGraphicsView):

    def __init__(self, parent=None):
        super(Viewport, self).__init__(parent)
        self.scene = QGraphicsScene()
        self.image = Image()
        self.image.setPos(100, 100)
        self.scene.addItem(self.image)
        self.setScene(self.scene)
        self.image.scene = self.scene
        self.image.view  = self

    def mousePressEvent(self, event):
        super(Viewport, self).mousePressEvent(event)

        self.image.mobile = (self.image.mobile + 1) % 2  # Toggle mobility

        x = self.image.x()  # + int(self.image.width  / 2)
        y = self.image.y()  # + int(self.image.height / 2)
        QCursor.setPos(x, y)

        relative = self.mapFromGlobal(self.image.absolute)

        print "absolute.x() = {0}  absolute.y() = {1}"\
              .format(self.image.absolute.x(), self.image.absolute.y())

        print "relative.x() = {0}  relative.y() = {1}"\
              .format(relative.x(), relative.y())


class MainWindow(QWidget):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.view = Viewport(self)

        hbox = QHBoxLayout()
        hbox.addWidget(self.view)

        self.setLayout(hbox)


app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())

PySide 邮件列表中的 Jukka 能够通过以下回复帮助我:

You don’t have to do anything in QGraphicsView, you can have mousePressEvent in Image to toggle floating on and off. These events get QGraphicsMouseEvents as parameters and these have the information you need about position of cursor or mouse press. So, in short, remove mousePressEvent from Viewport and replace hoverMoveEvent in your Image with this and it will work:

def hoverMoveEvent(self, event):
    if self.mobile:
        print("Moving")
        self.setPos(event.scenePos() - QPoint(self.width / 2, self.height / 2))

def mousePressEvent(self, event):
    self.mobile = not self.mobile # Toggle mobility
    super().mousePressEvent(event)