2021年4月8日星期四

Why PyQt5 widgets sometimes have the same id?

(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

没有评论:

发表评论