You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5子窗口创建后自动关闭问题求助

问题描述

我正在使用Python和PyQt5开发程序,这是我首次使用PyQt5。程序启动后主窗口弹出,用户可通过两个按钮选择操作;点击按钮会打开新的子窗口供用户填写字段,但子窗口每次打开后都会立刻关闭。以下是我的代码:

main.py

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QFormLayout, QGroupBox, QLabel, QLineEdit, \
    QComboBox, QTextEdit, QPushButton, QTreeView, QMenuBar, QMainWindow
from PyQt5.QtGui import QStandardItemModel
from scelle_window import ScelleWindow
from oe_window import OeWindow


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('''Main Window''')
        self.resize(800, 500)

        main_widget = QWidget()
        self.setCentralWidget(main_widget)

        grid = QGridLayout()

        bt_add_scelle = QPushButton('''Add objetc''')
        bt_add_scelle.clicked.connect(self.add_scelle_dial)
        bt_add_oe = QPushButton('''Add desc''')
        bt_add_oe.clicked.connect(self.add_oe_dial)

        grpbox_tree = QGroupBox('''List''')
        layout_tree = QGridLayout()
        layout_tree.addWidget(case_tree, 0, 0)
        layout_tree.addWidget(bt_add_scelle, 1, 0)
        layout_tree.addWidget(bt_add_oe, 2, 0)
        grpbox_tree.setLayout(layout_tree)
        grid.addWidget(grpbox_tree, 3, 0, 1, 2)

        main_widget.setLayout(grid)

    def add_scelle_dial(self):
        desc_scelle = ScelleWindow()
        desc_scelle.show()

    def add_oe_dial(self):
        desc_oe = OeWindow()
        desc_oe.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    win = MainWindow()
    win.show()

    sys.exit(app.exec_())

scelle_window.py

from PyQt5.QtWidgets import QWidget, QFormLayout, QLabel, QLineEdit, QComboBox

class ScelleWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('''Object informations''')
        self.resize(500, 300)
# ... following code...

oe_window.py

from PyQt5.QtWidgets import QWidget, QFormLayout, QLabel, QLineEdit, QComboBox

class OeWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setWindowTitle('''Object description''')
        self.resize(500, 300)
# ... following code...

请问这是由垃圾回收(garbage collection)导致的,还是其他原因?


问题原因与解决方案

这确实是垃圾回收导致的问题。

在add_scelle_dial和add_oe_dial方法中,你创建的子窗口对象(desc_scelle、desc_oe)是局部变量,当方法执行完毕后,这些变量会失去引用,Python的垃圾回收机制会立即销毁它们,对应的窗口也就随之关闭了。

解决方案1:绑定为实例属性

把子窗口对象绑定到主窗口的实例属性上,让它们始终持有引用:

def add_scelle_dial(self):
    self.desc_scelle = ScelleWindow()
    self.desc_scelle.show()

def add_oe_dial(self):
    self.desc_oe = OeWindow()
    self.desc_oe.show()

解决方案2:支持多窗口同时打开

如果需要允许同时打开多个同类型子窗口,可以用列表存储所有子窗口实例:

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # 初始化子窗口存储列表
        self.child_windows = []
        # ... 其他原有初始化代码 ...

    def add_scelle_dial(self):
        desc_scelle = ScelleWindow()
        self.child_windows.append(desc_scelle)
        desc_scelle.show()

    def add_oe_dial(self):
        desc_oe = OeWindow()
        self.child_windows.append(desc_oe)
        desc_oe.show()

通过以上两种方式,都能保证子窗口不会因为失去引用被垃圾回收,从而正常保持打开状态。


内容的提问来源于stack exchange,提问作者Ju Ctn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 12:45:30