微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么 PyQt5 小部件有时具有相同的 ID?

如何解决为什么 PyQt5 小部件有时具有相同的 ID?

(示例有问题的代码及其底部输出

使用 PyQt5,我正在编写一个带有 QDialogQTabWidget。 此选项卡小部件具有 qformlayout 布局。 我想遍历表单并将其右侧小部件(“字段”)作为键存储在 weakref.WeakKeyDictionary 中以供以后使用(直到对话框关闭并且相应的键有望自动消失)。

我发现我的弱键字典没有按预期工作:有些小部件被正确存储,有些则没有。 特别是,后来添加的小部件似乎被更频繁地存储(当我多次退出并重新打开应用程序时)。

我为表单中的每个标签小部件 print(hex(id(label)) 调用label。 这表明某些标签具有相同的 Python id,并且我相信只有具有任何特定 id 的最后一次迭代小部件被存储。

这个“id 共享”真的是我的弱键字典不存储所有小部件的原因吗? 为什么每个小部件没有自己的 ID? 我可以更改我的代码,让每个小部件都有一个唯一的 id 吗? 我可以更改我的代码,以便每个小部件可以在我的弱键字典中只存储一次吗?

示例代码

#!/usr/bin/env python3

from weakref import WeakKeyDictionary

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import *


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.weak = WeakKeyDictionary()
        self.clickme = QPushButton("Click me",self)
        self.clickme.clicked.connect(self.open_settings)

    @pyqtSlot()
    def open_settings(self) -> None:
        dialog = QDialog(self)
        self.weak[dialog] = "Settings"
        grid = qgridLayout()
        tabs = QTabWidget(dialog)
        tab0 = QWidget(tabs)
        tabs.addTab(tab0,"Sample")
        form0 = qformlayout()
        for char in "sample":
            form0.addRow(char,QLineEdit(tab0))
        tab0.setLayout(form0)
        # print information
        for row in range(form0.rowCount()):
            label = form0.itemAt(row,form0.LabelRole).widget()
            print(hex(id(label)),type(label).__name__)
            self.weak[label] = "foobar"
        print(flush=True)
        for k,v in self.weak.items():
            print(f"{k!r}: {v!r}")
        print(flush=True)
        grid.addWidget(tabs,1,3)
        dialog.show()
        dialog.exec()


if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec()

当整个应用程序运行时此示例代码输出

0x7f5956285670 QLabel  # this is ok
0x7f5956285700 QLabel  # this is ok
0x7f59562855e0 QLabel  # this is ok
0x7f5956285670 QLabel  # why the repeated id?!
0x7f5956285700 QLabel  # why the repeated id?!
0x7f59562855e0 QLabel  # why the repeated id?!

# the resulting weak-keys dict:
<PyQt5.QtWidgets.QDialog object at 0x7f5956342f70>: 'Settings'
<PyQt5.QtWidgets.QLabel object at 0x7f59562855e0>: 'foobar'

解决方法

这似乎是一个错误,当对象是在 C++ 中创建时(如 QFormLayout 的 QWidgetItem),然后当它从 python 访问时,似乎 pyqt5 重用了对象(在 pyside2 中它确实如此)不会发生)。

一个可能的解决方案是在 python 中创建 QLabels,这样对象就不会被重用。

form0.addRow(QLabel(char),QLineEdit())

此外,您必须访问 QLabel 而不是 QWidgetItem:

# print information
for row in range(form0.rowCount()):
    label = form0.itemAt(row,form0.LabelRole).widget()
    print(hex(id(label)),type(label).__name__)
    self.weak[label] = "foobar"
print(flush=True)

输出:

0x7f756703c0d0 QLabel
0x7f756703c1f0 QLabel
0x7f756703c310 QLabel
0x7f756703c430 QLabel
0x7f756703c550 QLabel
0x7f756703c670 QLabel

<PyQt5.QtWidgets.QDialog object at 0x7f756ef61dc0>: 'Settings'
<PyQt5.QtWidgets.QLabel object at 0x7f756703c0d0>: 'foobar'
<PyQt5.QtWidgets.QLabel object at 0x7f756703c1f0>: 'foobar'
<PyQt5.QtWidgets.QLabel object at 0x7f756703c310>: 'foobar'
<PyQt5.QtWidgets.QLabel object at 0x7f756703c430>: 'foobar'
<PyQt5.QtWidgets.QLabel object at 0x7f756703c550>: 'foobar'
<PyQt5.QtWidgets.QLabel object at 0x7f756703c670>: 'foobar'

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。