QGraphicsItem添加在错误的位置

时间:2023-02-02 00:11:11

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.

我有一个QGraphicsItem的子类,我想在'Control+LMB click'的场景中添加它的实例。麻烦的是,项目被添加到坐标比它们应该大两倍的位置。同时添加带有场景的省略号。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_()

2 个解决方案

#1


4  

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

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

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.

你基本上从项目的局部坐标系的(0,0)开始到给定的x和y从位置开始。这基本上意味着你的矩形将被绘制在位置。x() +位置。x()和位置。y() +位置。y()第一个位置。

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

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

 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.

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

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):

这是一个3D图形,可以显示我上面描述的内容(我找不到2D的例子,但原理是一样的:P):

QGraphicsItem添加在错误的位置

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

这里的世界是场景,而对象是场景中的QGraphicsItem。

#2


1  

Changing

改变

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

to

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

solved the problem

解决了这个问题

#1


4  

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

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

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.

你基本上从项目的局部坐标系的(0,0)开始到给定的x和y从位置开始。这基本上意味着你的矩形将被绘制在位置。x() +位置。x()和位置。y() +位置。y()第一个位置。

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

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

 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.

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

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):

这是一个3D图形,可以显示我上面描述的内容(我找不到2D的例子,但原理是一样的:P):

QGraphicsItem添加在错误的位置

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

这里的世界是场景,而对象是场景中的QGraphicsItem。

#2


1  

Changing

改变

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

to

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

solved the problem

解决了这个问题