【问题标题】:How to identify a QGraphicsItem?如何识别 QGraphicsItem?
【发布时间】:2022-01-18 01:15:53
【问题描述】:

我想知道是否有办法获取 QGraphicsItem 的 id。没什么复杂的。假设我有一个 QGraphicsScene,并在其中创建了许多相同大小和颜色的矩形。即使没有 id,我如何识别它们?

更新 这是我的一些代码

class Test(QtWidgets.QDialog):

    def __init__(self):
        super(Test, self).__init__()
        
        loader = QtUiTools.QUiLoader()
        self.ui = loader.load(ui_path, self)
        self.variables()
        
        self.ui.create_button.clicked.connect(self.creator)
        self.scene.focusItemChanged.connect(self.nameDisplay)
        
    def variables(self):        
        self.scene = QtWidgets.QGraphicsScene()
        self.ui.canvas_area.setScene(self.scene)
        
         
    def creator(self):
        rect = self.scene.addRect(-20,-20,40,40, QPen(Qt.red), QBrush(Qt.gray))
        rect.setFlag(QGraphicsItem.ItemIsMovable)
        rect.setFlag(QGraphicsItem.ItemIsFocusable)
        rect.setFlag(QGraphicsItem.ItemIsSelectable)
        
    def nameDisplay(self, newFocusItem, oldFocusItem, reason):
        self.ui.name_line.setText(str(self.scene.focusItem()))       
                
if __name__ == '__main__':
    test_window = Test()
    test_window.ui.show()

提前致谢!

【问题讨论】:

  • 您何时/如何需要“识别”这些项目?这些项目是动态添加的吗?
  • @musicamante 感谢您的快速回复!我提供了一些代码,以便您更清楚地了解正在发生的事情。如果您将运行代码,您将看到一个按钮,当您单击它时,将创建 QGraphicsItem。我想将这些 QGraphicsItems 连接到某些功能。所以,当我选择其中一个时,会发生一些事情(没关系)。对于 QPushButtons,我们只需执行 myPushButton.clicked.connect(myFunction)。我可以用 QGraphicsItems 做类似的事情吗?
  • 注意:QUiLoader 的最大限制之一是它不能在现有小部件上“安装” UI(PyQt 允许通过 uic.loadUi 代替)。创建 QMainWindow 和 QDialog 时应格外小心:如果您使用 QUiLoader,则不应在 Designer 中创建主窗口或对话框,因为您实际上会将它们重新设置为您正在使用的小部件实例(这也可能会产生严重的问题);您应该始终使用基本表单(QWidget),最重要的是,将其添加到父级的主布局集中。

标签: python pyqt5 pyside2 qgraphicsitem


【解决方案1】:

QGraphicsItem 不是 QObject,所以不支持属性系统,但对通过setData() 存储属性的支持有限。

class Test(QtWidgets.QDialog):
    count = 0
    # ...

    def creator(self):
        rect = self.scene.addRect(-20,-20,40,40, QPen(Qt.red), QBrush(Qt.gray))
        rect.setFlag(QGraphicsItem.ItemIsMovable)
        rect.setFlag(QGraphicsItem.ItemIsFocusable)
        rect.setFlag(QGraphicsItem.ItemIsSelectable)
        rect.setData(0, self.count)
        self.count += 1

    def nameDisplay(self, newFocusItem, oldFocusItem, reason):
        if newFocusItem and newFocusItem.data(0) is not None:
            self.ui.name_line.setText('Item {}'.format(newFocusItem.data(0)))

注意:setData()data()key 参数必须是整数,并且无法知道是否设置了(以及设置了哪些)键:您只能检查键值是否不是 @987654328 @。如果您需要更复杂的数据映射,您可以使用字典作为值,或者只是子类(见下文)。

重要的是要考虑到,虽然可能会尝试为addRect() 返回的项目设置属性,但它不会起作用:我们应该记住 PyQt 是对 Qt 的绑定,并且所有 python 对象都用于 Qt 对象是包装器

考虑以下几点:

    def creator(self):
        # ...
        rect.id = self.count

    def nameDisplay(self, newFocusItem, oldFocusItem, reason):
        print(hasattr(newFocusItem, 'id')

这将始终打印False,这是因为我们只为creator 中的包装器引用创建了一个属性,但由于该引用只是本地的,并且该属性设置在那个 引用上(不是被包裹的对象),它会被垃圾回收并且属性会丢失。

一个可能的选择是为每个项目添加一个持久引用:

class Test(QtWidgets.QDialog):
    def __init__(self):
        # ...
        self.items = []

    def creator(self):
        # ...
        rect.id = self.count
        self.items.append(rect)

但我建议坚持使用 setData() 选项,因为它更符合 Qt 的工作方式。

或者,我们可以创建一个自定义的 QGraphicsRectItem 子类,并使用self.scene.addItem() 添加它。在这种情况下,python 包装器将是持久的,并且属性将被保留:

class MyRect(QtWidgets.QGraphicsRectItem):
    def __init__(self, id, x, y, w, h, pen, brush):
        super().__init__(x, y, w, h)
        self.id = id
        self.setPen(pen)
        self.setBrush(brush)

class Test(QtWidgets.QDialog):
    # ...
    def creator(self):
        rect = MyRect(self.count, -20, -20, 40, 40, QPen(Qt.red), QBrush(Qt.gray))
        self.scene.addItem(rect)
        # ...

    def nameDisplay(self, newFocusItem, oldFocusItem, reason):
        if hasattr(newFocusItem, 'id'):
            self.name_line.setText('Item {}'.format(newFocusItem.id))

【讨论】:

  • 抱歉我的回复晚了。我尝试了你建议的所有方法,我想我会跟上最后一个。这是一些很好的解释,它对我帮助很大,所以谢谢!
  • 嗨!很抱歉再次打扰您。我有点搞砸了。您能否告诉我如何通过我们应用在它们上的那些名称(item1、item2 等)来选择这些 QGraphicsItems 中的任何一个?还是不可能?
  • “选择”是什么意思?在任何情况下,您都可以使用items() 访问所有项目,因此只需遍历它们并检查hasattr(item, 'id') 是否返回True(或isinstance(item, MyRect)),或者使用第三个示例中的列表;然后只需验证 id 是否与您需要的匹配。或者,使用字典,但您必须确保所有项目都有唯一的 ID。
  • 好的,非常感谢!当我尝试这个时,我会告诉你。
猜你喜欢
  • 2014-12-08
  • 1970-01-01
  • 2010-11-12
  • 2012-10-29
  • 2011-12-11
  • 2014-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多