在PyQt中对QGraphicsRectItem进行子类化

时间:2017-11-06 20:23:04

标签: python pyqt pyqt5

我正在编写一个应用程序,我希望能够通过单击并拖动它们来移动矩形。到目前为止,下面的代码正确地执行了此操作

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

import sys

class Memory(QWidget):

    grid = None
    scene = None

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

        self.layout = QGridLayout(self)

        self.scene = QGraphicsScene(self)
        self.scene.setSceneRect(geometry.x(), geometry.y(), geometry.width(), geometry.height())
        self.scene.setBackgroundBrush(Qt.white)

        self.view = QGraphicsView()
        self.view.setScene(self.scene)

        self.layout.addWidget(self.view)

        rect = QRectF(40, 40, 220, 110)
        self.make_proxy(rect)

        rect2 = QRectF(300, 40, 220, 110)
        self.make_proxy(rect2)

    def make_proxy(self, rect):

        label = QLabel('World')
        label.setAlignment(Qt.AlignCenter | Qt.AlignCenter)

        # create proxy
        proxy = QGraphicsProxyWidget()
        proxy.setWidget(label)
        proxy.setGeometry(rect)
        self.scene.addItem(proxy)

        # create parent item
        rectangle = QGraphicsRectItem(rect)
        rectangle.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.scene.addItem(rectangle)

        # set parent
        proxy.setParentItem(rectangle)


def main():

    app = QApplication(sys.argv)
    form = Memory(QRect(10, 10, 550, 180))
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

然而,第一个矩形始终位于场景的底部,因为它首先被添加到场景的底部。但是当我点击它时,它应该转到场景的顶部,使它出​​现在第二个矩形的上方。这就是我想要继承QGraphicsRectItem并为其添加新功能的原因。但是当我按照以下方式实施时

class RectItem(QGraphicsRectItem):

    def __init__(self, rect):
        QGraphicsRectItem.__init__(self)
        self.rectangle = rect

    def boundingRect(self):
        super(RectItem, self).boundingRect()
        return self.rectangle

并将rectangle变量定义为

        rectangle = RectItem(rect)

项目不再可移动,即QGraphicsItem.ItemIsMovable标志无效。

是否有一种简单的子类化QGraphicsRectItem的方法,并且仍然保留setFlag(QGraphicsItem.ItemIsMovable, True)等所有便利功能?

修改

正如eyllanesc指出的那样,没有必要覆盖boundingRect方法。当我尝试将QGraphicsRectItem子类化为

class RectItem(QGraphicsRectItem):

    def __init__(self, rect):
        QGraphicsRectItem.__init__(self)

并将rectangle定义为

        rectangle = RectItem(rect)

我没有与

相同的行为
        rectangle = QGraphicsRectItem(rect)

这是什么原因?

1 个答案:

答案 0 :(得分:0)

从类继承时,必须调用父类的构造函数并传递一些参数,在这种情况下,使用以下代码:

QGraphicsRectItem.__init__(self)

审核docs

QGraphicsRectItem(QGraphicsItem *parent = Q_NULLPTR)
QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent = Q_NULLPTR)
QGraphicsRectItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent = Q_NULLPTR)

您正在使用第一个没有父级和QRect的构造函数。

检查docs

  

[...] QGraphicsRectItem使用矩形和笔宽来合理实施boundingRect()shape()contains()。 [...]

从我们看到他使用QRect进行boundingRect(),此方法用于其他方法,如移动,调整大小等。

由于这个原因我不建议以这种方式覆盖父级,除了无意之外,当我覆盖一个类时,我总是添加信息,即新参数或我将默认值设置为现有的,一般继承方式如下:

class RectItem(QGraphicsRectItem):
    def __init__(self, *args, **kwargs):
        QGraphicsRectItem.__init__(self, *args, **kwargs)

如果我想添加参数,我可以使用以下模板:

class RectItem(QGraphicsRectItem):
    def __init__(self, new_param, *args, **kwargs):
        QGraphicsRectItem.__init__(self, *args, **kwargs)
        self.new_param = new_param

或设置默认值:

class RectItem(QGraphicsRectItem):
    def __init__(self, parent):
        QGraphicsRectItem.__init__(self, rect=QRect(0, 0, 100,100), parent=parent)