(sample problematic code and its output at the bottom)
Using PyQt5, I'm writing a QDialog
with QTabWidget
in it. This tab widget has a QFormLayout
layout. I want to iterate over the form and store its right-side widgets (the "fields") as keys in a weakref.WeakKeyDictionary
for later use (until the dialog is closed and the respective keys hopefully vanish automatically).
I found out that my weak-keys dict don't work as expected: some widgets are correctly stored, some are not. In particular, widgets added later seem to be stored more often (when I quit and reopen the app many times).
I called print(hex(id(label))
for each label widget label
in the form. This showed that some labels have the same Python id
, and I believe that only the last iterated over widget with any particular id is being stored.
Is this "id sharing" really the reason why my weak-keys dict doesn't store all widgets? Why doesn't each widget have its own id? Can I change my code such that each widget has a unique id? Can I change my code such that each widget can be stored exactly once in my weak-keys dict?
Sample code:
#!/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, 0, 0, 1, 3) dialog.show() dialog.exec() if __name__ == "__main__": app = QApplication([]) window = MainWindow() window.show() app.exec()
Output of this sample code when the whole app is running:
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'
https://stackoverflow.com/questions/67013014/why-pyqt5-widgets-sometimes-have-the-same-id April 09, 2021 at 07:10AM
没有评论:
发表评论