首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >弹出后PySide2主窗口无法工作

弹出后PySide2主窗口无法工作
EN

Stack Overflow用户
提问于 2022-11-09 18:18:42
回答 1查看 29关注 0票数 0

我正在为使用PySide2的应用程序构建一个图形界面。我的主窗口是一个QMainWindow,每当在主窗口上执行特定的操作时,我都试图打开一个弹出窗口,即QDialog。

弹出窗口开得很好。但是,打开后,主窗口就不再响应了。我认为问题在于我的应用程序正在用弹出窗口覆盖主窗口。每当我试图更改主窗口的stackedWidget索引时,错误消息是:

AttributeError:“Ui_popupHideSuccess”对象没有属性“stackedWidget”

我用来打开主窗口的代码如下:

代码语言:javascript
复制
if __name__ == '__main__':
    app = QApplication(sys.argv)
    myWindow = MainWindow()
    myWindow.show()
    sys.exit(app.exec_())

我用来打开弹出窗口的代码如下:

代码语言:javascript
复制
def showPopupSuccessHide(self):
        self.window = QDialog()
        self.ui = Ui_popupHideSuccess()
        self.ui.setupUi(self.window)
        self.window.show()

窗口本身的代码在其他文件上(因为我正在使用QtDesigner来开发它们)。我认为没有必要解决这个问题,但如果需要,我可以提供。我在这里做错什么了?我需要打开弹出窗口,然后仍然与主窗口交互。

我不知道怎么才能真正解决这个问题。我相信我在打开弹出窗口所用的代码中有错误,但我不知道如何调整它才能正常工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-10 15:55:09

TL;DR

不要覆盖self.ui

解释

uic组合是如何工作的

正确使用pyuic生成的文件的常见方法之一是使用组合(相对于多重继承):

代码语言:javascript
复制
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog
from ui_mainWindow import Ui_MainWindow

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.myLineEdit.setText('some text')

这很好,而且很有意义:概念是创建pyuic类的实例(有时称为"form class"),然后使用该实例“设置”实际窗口,self.ui对象包含对所有小部件的引用。

请注意,使ui持久(使用实例属性)实际上并不是一个严格的要求,但要能够直接访问小部件通常是必需的,这对于创建信号连接或读取属性通常很重要。

但是,如果这不是必需的,它还是会起作用的:小部件自动“修复”到主窗口(或它们的直接父窗口),垃圾收集不是问题,因为Qt将在内部保留它自己的引用(就Qt而言,“窗口具有所有权”)。

从技术上讲,这是完全正确的:

代码语言:javascript
复制
class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        Ui_MainWindow().setupUi(self)

然后,我们仍然可以使用findChild及其对象名称(在Designer中设置的对象名称)访问这些小部件:

代码语言:javascript
复制
        self.findChild(QLineEdit, 'myLineEdit').setText('some text')

显然,这是不太实际的。

创建“子”窗口

当需要创建子窗口(通常是对话框)时,通常建议使用实例属性来避免垃圾收集:

代码语言:javascript
复制
    def createWindow(self):
        self.window = QDialog()
        self.window.show()

如果该对话框也有一个设计器文件,我们需要做一些类似于在开始时所做的事情。不幸的是,一个非常常见的错误是使用相同的名称创建ui实例:

代码语言:javascript
复制
    def createWindow(self):
        self.window = QDialog()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self.window)
        self.ui.anotherLineEdit.setText('another text')
        self.window.show()

这在理论上是很好的:所有的工作都如预期的那样。但是有一个很大的问题:上面的内容覆盖了self.ui,这意味着我们失去了对主窗口小部件的所有引用。

假设您希望根据主窗口中写入的文本在对话框中设置行编辑的文本;以下内容可能会崩溃:

代码语言:javascript
复制
    def createWindow(self):
        self.window = QDialog()
        self.ui = Ui_Dialog()
        self.ui.setupUi(self.window)
        self.ui.anotherLineEdit.setText(self.ui.myLineEdit.text())
        self.window.show()

这清楚地显示了一个重要的方面:在分配可能已经存在的属性之前,必须始终进行思考。

在上面的代码中,这实际上已经完成了两次:我们不仅重写了之前创建的self.ui,而且还重写了window(),这是所有Qt小部件的现有函数(它返回调用它的小部件的顶级祖先窗口)。

根据经验,一定要花时间决定如何命名对象,使用智能名称,并考虑到大多数常见的名称可能已经被采用:请记住在您使用的小部件类型的文档中检查“所有成员的列表,包括继承的成员”链接,直到您有足够的经验来记住它们。

解决方案

显而易见的解决方案是为对话框的ui使用不同的名称:

代码语言:javascript
复制
    def createWindow(self):
        self.dialog = QDialog()
        self.dialog_ui = Ui_Dialog()
        self.dialog_ui.setupUi(self.dialog)
        self.dialog_ui.anotherLineEdit.setText(self.ui.myLineEdit.text())
        self.dialog.show()

更好的解决方案是为对话框创建一个子类,而不是:

代码语言:javascript
复制
class MyDialog(QDialog):
    def __init__(self, parent=None)
        super().__init__(parent)
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)


class MyWindow(QMainWindow):
    # ...
    def createWindow(self):
        self.dialog = MyDialog()
        self.dialog.ui.anotherLineEdit.setText(self.ui.myLineEdit.text())
        self.dialog.show()

还请记住,另一个常见的方法(在我的经验中,更简单、更直观)是使用多重继承而不是组合:

代码语言:javascript
复制
class MyDialog(QDialog, Ui_Dialog):
    def __init__(self, parent=None)
        super().__init__(parent)
        self.setupUi(self)


class MyWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.myLineEdit.setText('some text')

    def createWindow(self):
        self.dialog = MyDialog()
        self.dialog.anotherLineEdit.setText(self.myLineEdit.text())
        self.dialog.show()

这种方法的唯一问题是,它可能会无意中覆盖“主”小部件的函数名称:例如,如果您在Designer中创建了一个子小部件并将其重命名为“窗口”。如前所述,如果您总是仔细考虑分配给对象的名称,这可能永远不会发生(将小部件命名为“窗口”没有多大意义)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74379650

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档