QLayout Additem - 阻止所有权转让

时间:2016-10-23 15:47:51

标签: python qt pyqt qlayout

使用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)

我已经读过某个地方,当作为项添加时,布局取得了小部件的所有权。一旦我超出布局参考的范围(在这种情况下是本地的),我就松开了小部件。所以我的集合中的widget-item似乎也被删除了。

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

2 个答案:

答案 0 :(得分: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被替换,前一个窗口保持活动状态,因此子窗口小部件也可以保持活动状态。

答案 1 :(得分:-1)

我自己解决了: - )

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

mc = MyClass()
mc.spawn()

第一个好的。现在我想在inst1内生成另一个。为此,我使用了

self.spawn()

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

必须是以下

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

我必须创建另一个MyClass实例,与所有其他实例共享widgetCollection。根据需要......