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

PyQt5 QMainWindow用setCentralWidget切换界面重复操作崩溃如何解决

崩溃原因

QMainWindow的setCentralWidget()方法存在默认销毁逻辑:当你传入新的中央控件时,Qt会自动释放原本挂载在中央部件位置的旧控件对象。
你代码中screen2、screen3对象仅在main()函数中初始化了一次:第一次切换到screen2后再切换到screen3时,screen2就被Qt自动销毁了,后续再调用setCentralWidget(self._screen2)时访问的是已被回收的无效内存,触发野指针错误导致程序崩溃。

修复方案

推荐使用Qt原生的QStackedWidget堆叠组件实现多页面切换,该组件会保存所有已添加的页面实例,仅通过索引切换显示,不会自动销毁页面,稳定性更高。

修复后完整可运行代码

import sys
from PyQt5.QtWidgets import (
    QWidget, QMenuBar, QMenu, QApplication,
    QAction, QMainWindow,
    QVBoxLayout, QLabel, QStackedWidget
)


class mainwindow(QMainWindow):
    def __init__(self, screen2, screen3):
        super().__init__()
        self._screen2 = screen2
        self._screen3 = screen3
        # 初始化堆叠控件,保存所有页面
        self.stacked_widget = QStackedWidget()
        self.tela()
        self.acoes()
        self.sinais()

    def tela(self):
        # 初始化screen1
        screen1 = QWidget()
        layout = QVBoxLayout()
        label = QLabel('screen 1')
        layout.addWidget(label)
        screen1.setLayout(layout)
        # 所有页面添加到堆叠控件
        self.stacked_widget.addWidget(screen1) # index 0
        self.stacked_widget.addWidget(self._screen2) # index 1
        self.stacked_widget.addWidget(self._screen3) # index 2
        # 堆叠控件设为中央部件,永远不会被替换
        self.setCentralWidget(self.stacked_widget)

    def acoes(self):
        self.action_screen1 = QAction('screen 1')
        self.action_screen2 = QAction('screen 2')
        self.action_screen3 = QAction('screen 3')

        menu_opt = QMenuBar(self)
        self.setMenuBar(menu_opt)
        menu = QMenu("avaliable screens", self)
        menu_opt.addMenu(menu)
        screen_menu = menu.addMenu("screens")
        screen_menu.addAction(self.action_screen1)
        screen_menu.addAction(self.action_screen2)
        screen_menu.addAction(self.action_screen3)

    def sinais(self):
        # 切换仅修改堆叠控件的显示索引
        self.action_screen1.triggered.connect(lambda: self.stacked_widget.setCurrentIndex(0))
        self.action_screen2.triggered.connect(lambda: self.stacked_widget.setCurrentIndex(1))
        self.action_screen3.triggered.connect(lambda: self.stacked_widget.setCurrentIndex(2))


class widget1(QWidget):
    def __init__(self):
        super().__init__()
        self.screen()

    def screen(self):
        layout = QVBoxLayout()
        label = QLabel('screen 2')
        layout.addWidget(label)
        self.setLayout(layout)


class widget2(QWidget):
    def __init__(self):
        super().__init__()
        self.screen()

    def screen(self):
        layout = QVBoxLayout()
        label = QLabel('screen 3')
        layout.addWidget(label)
        self.setLayout(layout)


def main():
    applic = QApplication(sys.argv)
    screen2 = widget1()
    screen3 = widget2()
    app = mainwindow(screen2, screen3)
    app.show()
    sys.exit(applic.exec_())


if __name__ == '__main__':
    main()

其他可选修复方式

如果你不想修改现有结构,也可以在每次调用setCentralWidget()前,手动将旧的中央控件的父对象设为None,避免Qt自动销毁:

def tela2(self):
    # 先把旧控件取出来,设为无父对象,避免被销毁
    old_widget = self.centralWidget()
    if old_widget:
        old_widget.setParent(None)
    self.setCentralWidget(self._screen2)

def tela3(self):
    old_widget = self.centralWidget()
    if old_widget:
        old_widget.setParent(None)
    self.setCentralWidget(self._screen3)

该方式不需要新增依赖组件,但需要注意自行管理所有页面的生命周期,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:54:00