首页 > 解决方案 > 如何为具有可以访问主 GUI 功能的子窗口/类的窗口创建 GUI 类?

问题描述

如何为具有可以访问主 GUI 功能的子窗口/类的窗口创建 GUI 类?

我有下面的代码,它修改了设计师编译的 .ui 代码。我想要它做的是,当单击右上角的“X”或使用 File -> Exit 函数时,关闭包含 Window_SecondWindow 类的窗口,并再次显示主窗口——有效地show()从子类。我想一次只显示一个窗口。

当代码按原样运行时,Window_SecondWindow 类隐藏,但立即再次显示,让我相信super正在充当self.

from PyQt5 import QtWidgets

from GUI import compiled_MainWindow
from GUI import compiled_SecondWindow

class Window_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.ui = compiled_MainWindow.Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.closeEvent = self.clicked_EXIT

        # connect widgets
        self.ui.Btn.clicked.connect(self.clicked_Btn)
        self.ui.actionExit.triggered.connect(self.clicked_EXIT)

        # add windows
        self.SecondWindow = SecondWindow()
        # more windows attached to main window

    def clicked_Btn(self):
        self.hide()
        self.SecondWindow.show()

    def clicked_EXIT(self):
        self.close()

class Window_SecondWindow(Window_MainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = compiled_SecondWindow.Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.closeEvent = self.clicked_EXIT

        self.ui.actionExit.triggered.connect(self.clicked_EXIT)

    def clicked_EXIT(self):
        self.hide()
        super().show()

标签: pythonuser-interfacepyqt5

解决方案


在回答你的问题之前,我想谈谈一些重要的方面。

  1. 首先,永远不要编辑从 pyuic 生成的代码来创建你的程序。它们旨在用作导入的模块,主要用作“资源”:您将它们导入并集成到您的代码中,但您应该始终保持它们原样。有关这方面的更多信息,请参阅有关使用 Designer的文档。

  2. 重写中的函数要小心__init__:有些函数不是“虚拟的”(因此,不能以这种方式覆盖),并且在某些情况下,Qt 总是调用基类函数名;如果需要,只需覆盖该方法并使用 super() 调用基类实现。此外,closeEvent将关闭事件作为强制参数,您必须将其添加到您的覆盖函数中,即使您不使用它(在以下示例中我只是使用*args)。也就是说,您永远不应该将重写的函数用作具有不同参数的插槽,反之亦然。

  3. 最后,你不应该对属性和变量名使用大写的名字,因为它会混淆并且容易出错(大写通常只用于类名,而不是它们的实例名)。

现在,答案

你几乎是对的,super()充当“自我”,因为它只是针对实例show()调用类的继承方法。所以,它调用了 的 show 方法,但是由于实例是第二个窗口,所以它和做的一样,都是实例完全一样。_Window_MainWindowWindow_MainWindow.show(self)selfWindow_SecondWindow self.show()

有两种(半)可能性。

第一个更明显的解决方案是将主窗口实例的引用提供给第二个:

class Window_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        # ...
        self.secondWindow = Window_SecondWindow()
        self.secondWindow.mainWindow = self

class Window_SecondWindow(Window_MainWindow):
    # ...
    def clicked_EXIT(self, *args):
        self.hide()
        self.mainWindow.show()

请注意,正如@noras 在评论中指出的那样,您可以在 init 参数中将主窗口设置为父窗口,但这仅适用于 QMainWindow 和 QDialog 后代;如果子窗口小部件是任何其他类型的,它将显示父窗口内,而不是作为单独的窗口。

第二个(也是“Qt-wise correct”)是为第二个类创建一个在关闭时发出的信号,并将其连接到主窗口中,以便在发生这种情况时再次显示:

class Window_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        # ...
        self.secondWindow = Window_SecondWindow()
        self.secondWindow.closed.connect(self.show)

class Window_SecondWindow(Window_MainWindow):
    closed = QtCore.pyqtSignal()

    def clicked_EXIT(self, *args):
        self.hide()
        self.closed.emit()

第二种半解决方案是使用事件过滤器

class Window_MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        # ...
        self.secondWindow = Window_SecondWindow()
        self.secondWindow.installEventFilter(self)

    def eventFilter(self, source, event):
        if source == self.secondWindow and event.type() == QtCore.QEvent.Close:
            self.show()
        return super().eventFilter(source, event)

推荐阅读