【问题标题】:QLayout Additem - prevent transfer of ownershipQLayout Additem - 防止所有权转移
【发布时间】:2016-10-24 17:43:22
【问题描述】:

在使用 QLayout 将我的小部件排列在彼此相邻的较大窗口中时,我遇到了对象引用问题。

我有以下情况

class MyClass(QObject):
     widgetCollection = []

     def spawn(self):
         widget = MyQWidget() #containing a QLineWidget called "nameEdit"
         self.widgetCollection.append(widget)
         self._window = QtGui.QWidget()
         layout = QtGui.QHBoxLayout()

         listView = QtGui.QListWidget()            
         for equation in self.wigdetCollection:
              equationName = equation.nameEdit.text()
              item = QtGui.QListWidgetItem(equationName)
              listView.addItem(item)

         layout.addWidget(listView)
         layout.addWidget(widget)

         self._window.setWindowTitle("Equation Editor")
         self._window.setLayout(layout)

         self._window.show()

    def respawn(self):
         self.spawn()

每次调用 spawn() 时,我都想向集合中添加一个新的小部件。另外,我想打开一个新窗口,其中有一个 ListView,左侧是所有小部件名称,右侧是新创建的小部件。

现在对 spawn() 方法的第一次调用按预期工作。但是第二次调用会引发异常:

equationName = widget.nameEdit.text()
RuntimeError: wrapped C/C++ object of type QLineEdit has been deleted

我觉得跟台词有关系

layout.addWidget(widget)

我在某处读到,当添加为项目时,布局会获得小部件的所有权。这样,一旦我超出布局参考的范围(在这种情况下是本地的),我就会松开小部件。所以看来我收藏中的小部件项目也被删除了。

有人可以帮忙吗?我该如何防止这种情况发生。

【问题讨论】:

  • 您需要显示MyQWidget 类的代码。

标签: python qt pyqt qlayout


【解决方案1】:

问题在于每次 spawn() 关闭时都会替换 self._window:Python 会丢弃旧的窗口小部件,而 self._window 会引用一个新的 QWidget 实例。由于旧的窗口小部件是列表视图和 qlineedit 小部件(在代码中被称为 - 令人困惑 - 只是“小部件”)的父级,因此这些将在 Qt 术语的意义上被破坏 - 即它们的 C++ 部分将被破坏.列表视图在显示的代码中的其他任何地方都没有引用,因此列表视图的 Python 部分也将被破坏,这就是它应该的方式。

但是,qlineedit 在类范围的注册表 (widgetCollection) 中被引用,因此 qlineedit 的 Python 部分不会被破坏。这意味着每次调用 spawn() 时,之前的 QLineEdit 实例(通过类范围 widgetCollection 中的 MyQWidget)变成了僵尸:它在 C++ Qt 级别已死,但在 Python 级别仍然存在。僵尸的方法仍然可以被访问,但是在很多情况下你会看到关于 C/C++ 被删除的 Qt 错误,你可能会遇到崩溃或其他未定义的行为。

从贴出的代码中并不清楚 widgetCollection 的意图是什么,但由于之前附加的项目将在 spawn() 期间变成僵尸,widgetCollection 如图所示是无用的。问题的解决取决于集合如何使用的细节,但既然可以假设集合是有目的的,那么问题就是窗口小部件的替换:也许小部件集合应该是一个窗口集合,那么当self._window 被替换,前一个窗口保持活动状态,因此子小部件也保持活动状态。

【讨论】:

  • MyQWidget() - 是一个对话框窗口,带有一些用于用户输入的 QLineEdits。每个对话框窗口都有一个连接到 Respawn() 方法的按钮。 _window 结合所有先前添加的对话框的列表显示此对话框。一切都由超类 MyClass() 处理,这是一种由另一个程序调用的主函数。此类保留所有引用。因为我需要来自不同 Dialog-Windows 的输入,所以它们都收集在 widgetCollection 中,然后由爬虫进行分析。 Respawn 正在从 Dialog 中生成 Dialog。
【解决方案2】:

自己解决了:-)

我最初对 spawn() 方法的调用是这样的:

mc = MyClass()
mc.spawn()

第一个没问题。现在我想从inst1 中生成另一个。为此我使用过

self.spawn()

respawn()-方法中抛出上述错误。

必须是下面的

 def respawn(self):
     mc = MyClass()
     mc.spawn()

我必须创建另一个MyClass 实例,它与所有其他实例共享widgetCollection。随心所欲....

【讨论】:

  • 您可以接受自己的答案,表明您已经自己解决了问题 - 这是一种常见情况。
  • 我知道 :) 但接下来两天不会。我收到消息“您可以在 2 天内接受自己的答案”....
  • 这个很不清楚。一方面,spawn() 不返回任何内容,因此 inst1 和 2 将为 None。请澄清。
猜你喜欢
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 2013-02-11
  • 1970-01-01
  • 2010-11-30
  • 2014-10-10
  • 1970-01-01
相关资源
最近更新 更多