PyQt: QGraphicsItem added at a wrong position

老子叫甜甜 提交于 2021-01-28 19:09:38

问题


I have a subclass of QGraphicsItem and I want to add instances of it to the scene on 'Control+LMB click'. The trouble is that the item is added at the position with coordinates that are two times larger than they should be. At the same time adding ellipses with scene.addEllipse(...) works fine.

#!/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_()

回答1:


I see you have answered your own question. However I would like to explain why this works.

Every QGraphicsItem has its own local coordinate system. So when you do

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

you basically start from the (0, 0) of the item's local coordinate system and go to the given x and y which you take from position. This basically means that your rectangle will be drawn at position.x() + position.x() and position.y() + position.y() with the first position.x()/position.y() being the position of the QGraphicsItem inside your scene and the second position.x()/position.y() being the position inside the local coordinate system of your item.

If you want to start from the origin of the QGraphicsItem, you have to use

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

This ensures that you start from the origin of the local coordinate system.

This issue is particularly tricky due to the fact that by default objects are added to the (0, 0) of a scene. So position.x() + position.x() and position.y() + position.y() in this case will actually not show the issue at hand since 0+0 is always equal to 0. It is the moment you change the default position to something else when the problem will occur.

Here is a 3D figure that visualizes what I'm describing above (I was unable to find a 2D example but the principle is the same :P):

The world here is the scene while the object is the QGraphicsItem residing in that scene.




回答2:


Changing

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

to

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

solved the problem



来源:https://stackoverflow.com/questions/19121309/pyqt-qgraphicsitem-added-at-a-wrong-position

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!