2

我有一个 QGraphicsItem 的子类,我想在“Control+LMB click”上将它的实例添加到场景中。问题是该项目被添加到坐标比它们应该大两倍的位置。同时使用 scene.addEllipse(...) 添加椭圆效果很好。

#!/usr/bin/env python

import sys
from PyQt4.QtCore import (QPointF, QRectF, Qt, )
from PyQt4.QtGui import (QApplication, QMainWindow, QGraphicsItem, 
                         QGraphicsScene, QGraphicsView, QPen, QStyle)

MapSize = (512, 512)

class DraggableMark(QGraphicsItem):
    def __init__(self, position, scene):
        super(DraggableMark, self).__init__(None, scene)
        self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsMovable)
        self.rect = QRectF(position.x(), position.y(), 15, 15)
        self.setPos(position)
        scene.clearSelection()

    def boundingRect(self):
        return self.rect

    def paint(self, painter, option, widget):
        pen = QPen(Qt.SolidLine)
        pen.setColor(Qt.black)
        pen.setWidth(1)
        if option.state & QStyle.State_Selected:
            pen.setColor(Qt.blue)
        painter.setPen(pen)
        painter.drawEllipse(self.rect)


class GraphicsScene(QGraphicsScene):
    def __init__(self, parent=None):
        super(GraphicsScene, self).__init__(parent)
        self.setSceneRect(0, 0, *MapSize)

    def mousePressEvent(self, event):
        super(GraphicsScene, self).mousePressEvent(event)
        if event.button() != Qt.LeftButton:
            return

        modifiers = QApplication.keyboardModifiers()
        pos = event.scenePos()
        if modifiers == Qt.ControlModifier:
            print("Control + Click: (%d, %d)" % (pos.x(), pos.y()))
            DraggableMark(pos, self)
            self.addEllipse(QRectF(pos.x(), pos.y(), 10, 10))
        else:
            print("Click: (%d, %d)" % (pos.x(), pos.y()))


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.scene = GraphicsScene(self)
        self.scene.addRect(QRectF(0, 0, *MapSize), Qt.red)
        self.view = QGraphicsView()
        self.view.setScene(self.scene)
        self.view.resize(self.scene.width(), self.scene.height())
        self.setCentralWidget(self.view)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    rect = QApplication.desktop().availableGeometry()
    window.resize(int(rect.width()), int(rect.height()))
    window.show()
    app.exec_()
4

2 回答 2

6

我看到你已经回答了你自己的问题。但是,我想解释一下为什么会这样。

每个QGraphicsItem都有自己的局部坐标系。所以当你这样做时

self.rect = QRectF(position.x(), position.y(), 15, 15)

您基本上从(0, 0)项目的本地坐标系开始,然后转到给定的xyposition. 这基本上意味着您的矩形将被绘制在position.x() + position.x()position.y() + position.y()一个position.x()/position.y()QGraphicsItem场景内部的位置,第二个position.x()/position.y()是项目本地坐标系内的位置。

如果你想从 的起源开始QGraphicsItem,你必须使用

 self.rect = QRectF(0, 0, 15, 15)

这可确保您从本地坐标系的原点开始。

这个问题特别棘手,因为默认情况下对象被添加到(0, 0)场景中。所以position.x() + position.x()andposition.y() + position.y()在这种情况下实际上不会显示手头的问题,因为0+0总是等于0。当问题发生时,您将默认位置更改为其他位置。

这是一个 3D 图,可视化了我上面描述的内容(我无法找到 2D 示例,但原理相同:P):

在此处输入图像描述

这里world是现场,而那里objectQGraphicsItem居住scene

于 2016-02-28T20:22:47.870 回答
1

改变

self.rect = QRectF(position.x(), position.y(), 15, 15)

self.rect = QRectF(0, 0, 15, 15)

解决了问题

于 2013-10-02T09:21:47.920 回答