使用 .ui 文件的 PySide 小部件意外被垃圾回收

PySide widgets using .ui files being garbage-collected unexpectedly

我有一个 PySide QMainWindow,我在 Nuke 中 运行。应用程序使用的一些小部件使用 .ui 在 Qt Designer 中创建的文件。

直到最近,QMainWindow class 还没有父级。因此,当 Nuke 最小化或更改焦点时,QMainWindow 不会随之最小化或获得焦点。

为了解决这个问题,在创建 QMainWindow 时,我使用了 QApplication.activeWindow() 方法来获取一个对象作为父级提供给 QMainWindow。

parent = QApplication.activeWindow()
window = MyMainWindow(parent)

如果我这样做,QMainWindow 将最小化并使用 Nuke 改变焦点。但是,当访问使用 .ui 文件创建的任何小部件的子小部件时,它将引发异常

Traceback (most recent call last):
    ...
RuntimeError: Internal C++ object (PySide.QtGui.QPushButton) already deleted.

我正在使用方法 very similar to this.ui 文件加载到我的 QWidget classes

为什么 C++ 对象被删除(垃圾收集)?为什么当我为 QMainWindow 指定父级时行为会改变?是否有另一种方法将 QMainWindow 设置为 Nuke 的父级,以便正确地最小化和聚焦或以不同的方式加载 .ui 文件而不会遇到此垃圾收集问题?

当其中一个父小部件因为不存在 python 对象引用而被垃圾回收时,就会出现问题。例如:

def create_window():
    parent = QApplication.activeWindow()
    window = MyMainWindow(parent)
    return window

当函数 returns 时,parent 对象超出范围,它所代表的 C++ pyobject 最终将被垃圾回收。奇怪的是,这只是使用 .ui 文件创建的小部件的问题。解决方案是只保留对所有父对象的引用。我正在使用一个全局变量来存储对它们的引用。

GC_PROTECT = []

def create_window():
    parent = QApplication.activeWindow()
    GC_PROTECT.append(parent)
    window = MyMainWindow(parent)
    return window

如果 window 被声明为 Global,它在 window 本身关闭之前不会被销毁。因此,您希望对 window/widget 本身的引用继续存在于某个地方,而不一定是父级(如前一个答案中所述)

def create_window():
    parent = QApplication.activeWindow()
    # not necesarily the best practice to declare it here, but comfortable
    Global window
    window = MyMainWindow(parent)
    return window