从按钮单击 Pyside2 触发消息框关闭整个应用程序

Pyside2 trigger messagebox from button click closes whole application

我想在不关闭整个应用程序的情况下通过单击按钮触发 messagebox,我在之前的项目中设法做到了这一点,但这次的行为确实出乎意料。当我点击 okmessagebox 上的叉号时,应用程序也没有任何错误地关闭。这是最小的例子

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.set_and_load_ui()

    def set_and_load_ui(self):
        self.ui = QUiLoader().load('main.ui', self)

    def trigger_messagebox(self):
        self.messagebox()

    def messagebox(self,x=""):
        msg = QMessageBox(self)
        msg.setIcon(QMessageBox.Information)
        msg.setText("{}".format(x))
        msg.setInformativeText("test")
        msg.setWindowTitle("test")
        msg.exec_()

app = QtWidgets.QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.ui.show()
# mainWindow.trigger_messagebox() #this is fine
mainWindow.ui.mainmenuButton.clicked.connect(lambda: mainWindow.trigger_messagebox()) #this is not fine
exit_code = (app.exec_())

只是为了检查一下,如果消息框本身导致了问题,我尝试直接在我的代码中调用它,但结果很好,但当我尝试通过单击按钮触发它时却不行

问题与 QUiLoader 使用给定的父对象作为参数加载 UI 这一事实有关,并且由于 UI 已经是 QMainWindow,您实际上是在将 QMainWindow 加载到另一个,不受支持:QMainWindows 是非常特殊的 QWidget 类型,旨在用作 顶级小部件

我不清楚 技术 静默 quit 的原因,但这肯定与加载的 window 实际上有父项(MainWindow 实例),即使未显示该父项(因为您显示的是 ui)。

不幸的是,与 PyQt 不同(通过 uic.loadUi 函数),PySide 不提供将 UI 文件“安装”到现有实例的方法,因此如果您想继续使用PySide只有两个选项:

  1. 不要在 Designer 中使用主 window,而是使用普通小部件(Designer 的“新建表单”对话框中的“小部件”),使用 QUiLoader 加载它并使用 setCentralWidget()(这是 强制性 ,因为,正如文档也 notes,“不支持创建没有中央小部件的主要 window "):

     self.ui = QUiLoader().load('main.ui', self)
     self.setCentralWidget(self.ui)
    

    这种方法的缺点是您无法再使用 Designer 中的主要 window 功能(因此,没有菜单、状态栏、停靠小部件或工具栏)。

  2. 使用pyside-uic生成python代码,并使用多重继承方式“安装”;以下假设您将 ui 文件导出为 mainWindow.py:

     from mainWindow import ui_mainWindow
    
     class MainWindow(QtWidgets.QMainWindow, ui_mainWindow):
         def __init__(self):
             super(MainWindow, self).__init__()
             self.setupUi(self)
             # no "set_and_load_ui"
             self.mainmenuButton.clicked.connect(self.trigger_messagebox)
    
         # ...
    
     app = QtWidgets.QApplication(sys.argv)
     mainWindow = MainWindow()
     mainWindow.show()
     exit_code = (app.exec_())
    

    如您所见,现在您可以直接访问小部件(没有 ui 对象)。这种方法的缺点是您必须记住每次修改相关的 ui.

    总是 生成 python 文件