在不违反类封装的情况下在两个窗口之间进行通信

2024-09-25 08:38:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我创建了一个小pyqt5项目。以下是运行时应用程序的打印屏幕:

{1美元^

当用户在主窗口中单击QPushButton时,将出现一个对话框窗口,用户在QlineEdit中写入内容。然后,当单击对话框窗口的QPushButton时,对话框窗口向主窗口发送一个信号并被删除。信号包含用户键入的文本。在

下面是对我的两个类的描述,它们非常简单:

  • 主窗口类。

  • DialogWindow类(我想在不使用预先存在的对话框窗口的情况下创建自己的Dialog类)。

  • 我的主脚本

enter image description here

我有几个问题:

使用信号在窗口之间进行通信是正确的吗?我不认为我违反了类封装。但是,我不喜欢通过编写以下内容来连接子类上的信号:

self.mySignal.connect(parent.updatelabelAnswer)

在这一行中,我使用属性parent-可以吗?在我看来,这不是使用信号的好方法。在

我的第二个问题是:

我在DialogWindowon_pushButton_clicked槽中调用self.deleteLater()对吗?似乎不是这样,因为我已经用python交互式shell检查过了,对象myDialogWindow仍然可以访问。在


Tags: 项目用户文本self应用程序内容键入屏幕
2条回答

好吧,我想我应该发布一个答案,而不是写一些夸张的评论:p

关于删除,我将引用Qt documentation

As with QWidget::close(), done() deletes the dialog if the Qt::WA_DeleteOnClose flag is set. If the dialog is the application's main widget, the application terminates. If the dialog is the last window closed, the QApplication::lastWindowClosed() signal is emitted.

但是,如果您想从打开对话框的其他窗口小部件中处理关闭(和删除)对话框窗口,应该使用插槽和信号。只需将主窗口小部件中的一个按钮或任何东西与其clicked()信号连接到对话框的done()插槽,就可以开始了。在

在这一点上,我还想指出,删除一个对话框可能没有必要。根据对话框的内存占用(创建和运行它所用的内存),您可能希望考虑在开始时创建对话框,并将其保留在内存中,直到主应用程序关闭。除此之外,您可以使用hide()show()在屏幕上显示它。对于那些足够小的东西,这实际上是一个很好的实践,因为删除然后创建一个窗口比简单地隐藏和显示窗口要花费更多的时间。在


现在关于信号和插槽,它们有非常直接的语义。正如我在评论和我的另一个answer中所说的那样,为了将一个插槽连接到一个信号,你需要让它们出现在同一个范围内。如果不是这样的话,把一个(或两个)传给一个情况已经解决的地方。在你的情况下,你必须有一个共同的地方。如果两者都是顶级小部件,则必须在main()内进行连接。我宁愿将对话框作为扩展添加到您的MainWindow类(作为类成员)和实例化以及那里的连接-例如在MainWindow的构造函数中:

class MainWindow(QMainWindow, Ui_MainWindow):

  def __init__(self, parent=None):
    super(MainWindow, self).__init__(parent)
    self.setupUi(self)
    self.dialog = DialogWindow(self)

    # Connect mainwindow's signals to dialog's slots
    # Connect dialog's signals to mainwindow's slots
    # And even connect dialog's signals to dialog's slots

通常,父节点应该始终是执行信号连接的那个。让子控件在父控件上建立连接是有问题的,因为它对父控件设置了限制并导致副作用,并且在父控件的所有权被转换为子控件的情况下会完全中断。在

在您的例子中,有两个选项我认为是“正确的”。如果对话框至少应该是持久的,而不是要以模式运行,那么它应该定义一个父类连接到的信号。对话框不应该删除自己,这应该是父类在接收到信号后的责任。在

main窗口

def on_pushbutton_clicked(self):
    if not self.dlg:
        self.dlg = DialogWindow(self)
        self.dlg.mySignal.connect(self.on_mySignal)
        self.dlg.show()

def on_mySignal(value):
    self.dlg.mySignal.disconnect()
    self.dlg.close()
    self.dlg.deleteLater()
    self.dlg = None
    self.updateLabelAnswer(value)

您的对话似乎是一个临时的对话,它的存在只是为了收集输入,可能应该以模式运行。在这种情况下,你甚至不需要定义任何信号。只需创建类并提供一个API来获取文本框的值。在

对话框窗口

^{pr2}$

在主窗口中

def on_pushbutton_clicked(self):
    dlg = DialogWindow(self)
    if dlg.exec_():
        value = dlg.getValue()

相关问题 更多 >