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

时间:2016-03-14 15:54:33

标签: python dialog pyqt encapsulation qt-signals

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

application while running

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

以下是我的两个类的描述,非常简单:

  • MainWindow类。

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

  • 我的主要脚本

enter image description here

我有几个问题:

使用信号以便在窗口之间进行通信是否正确?我不认为我违反了类封装。但是,我不喜欢通过写:

来连接子类的信号
self.mySignal.connect(parent.updatelabelAnswer)

在这一行中,我使用属性parent - 它没关系吗?在我看来,这不是一种使用信号的好方法。

我的第二个问题是:

我是否可以在self.deleteLater()的{​​{1}}位置拨打on_pushButton_clicked?似乎没有,因为我已经检查了python交互式shell并且仍然可以访问对象DialogWindow

2 个答案:

答案 0 :(得分:1)

好吧所以我想我应该发一个答案,而不是写臃肿的评论:P

关于删除,我将引用Qt documentation

  

与QWidget :: close()一样,如果是,则done()删除对话框   设置Qt :: WA_DeleteOnClose标志。如果对话框是应用程序的   主要小部件,应用程序终止。如果对话框是最后一个   窗口关闭,发出QApplication :: lastWindowClosed()信号。

但是,如果要从打开它的其他窗口小部件处理对话窗口的关闭(和删除),则应使用插槽和信号。只需将主要小部件中的按钮或其他内容及其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

答案 1 :(得分:1)

通常,父母应始终是执行信号连接的父母。让子窗口小部件在父窗口上建立连接是有问题的,因为它对父窗口施加限制并导致副作用,并且在子窗口小部件的父所有权被转移的情况下完全中断。

在您的示例中,我会考虑两个选项"更正"。如果对话框至少在某种程度上是持久的,并且不打算以模态方式运行,那么它应该定义父类连接到的信号。对话框不应该自行删除,这应该是收到信号后父类的责任。

<强>主窗口

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即可获取文本框的值。

<强> DialogWindow

class DialogWindow(...)
    ...
    def on_pushbutton_clicked(self):
        self.accept()

    def getValue(self):
        return self.lineEdit.text()

在MainWindow

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