Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在不违反类封装的情况下在两个窗口之间通信_Python_Dialog_Pyqt_Encapsulation_Qt Signals - Fatal编程技术网

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

Python 在不违反类封装的情况下在两个窗口之间通信,python,dialog,pyqt,encapsulation,qt-signals,Python,Dialog,Pyqt,Encapsulation,Qt Signals,我创建了一个小pyqt5项目。以下是运行时应用程序的打印屏幕: 当用户从主窗口单击QPushButton时,会出现对话框窗口,用户会在QlineEdit中写入内容。然后,当单击对话框窗口的QPushButton时,对话框窗口向主窗口发送信号并被删除。信号包含用户键入的文本 下面是我的两个类的描述,非常简单: 主窗口类 DialogWindow类(我想在不使用预先存在的对话框窗口的情况下创建自己的对话框类) 我的主要剧本 我有几个问题: 这是使用信号在windows之间进行通信的正确方式吗

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

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

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

  • 主窗口类

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

  • 我的主要剧本

我有几个问题:

这是使用信号在windows之间进行通信的正确方式吗?我不认为我违反了类封装。但是,我不喜欢通过以下方式连接子类上的信号:

self.mySignal.connect(parent.updatelabelAnswer)
在这一行中,我使用属性
parent
-可以吗?在我看来,这不是使用信号的好方法

我的第二个问题是:


单击对话框窗口的
插槽上的
按钮,调用
self.deleteLater()
对吗?似乎不是,正如我在python交互式shell中检查过的那样,对象
myDialogWindow
仍然可以访问

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

关于删除,我将引用以下内容:

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

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

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


现在关于信号和插槽,它们有非常直接的语义。正如我在评论和其他文章中所说,为了将插槽连接到信号,您需要将它们显示在相同的范围内。如果情况并非如此,则将其中一个(或两个)传递到情况固定的地方。在你的情况下,你必须有一个共同的地方。如果两者都是顶级小部件,则必须在
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

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

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

主窗口

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)
class DialogWindow(...)
    ...
    def on_pushbutton_clicked(self):
        self.accept()

    def getValue(self):
        return self.lineEdit.text()
def on_pushbutton_clicked(self):
    dlg = DialogWindow(self)
    if dlg.exec_():
        value = dlg.getValue()
您的对话框似乎是一个临时对话框,它的存在只是为了收集输入,可能应该以模式运行。在这种情况下,您甚至不必定义任何信号。只需创建类并提供API即可获得文本框的值

对话框窗口

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)
class DialogWindow(...)
    ...
    def on_pushbutton_clicked(self):
        self.accept()

    def getValue(self):
        return self.lineEdit.text()
def on_pushbutton_clicked(self):
    dlg = DialogWindow(self)
    if dlg.exec_():
        value = dlg.getValue()
主窗口中的

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)
class DialogWindow(...)
    ...
    def on_pushbutton_clicked(self):
        self.accept()

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

检查我关于这个话题的答案。至于
deleteLater()
,即使可以手动调用插槽而不发出一个命令,但通常也不需要,也不知道为什么要在这里这样做:P也请避免张贴您的代码截图时,您可以简单地复制粘贴在这里。让人们更容易使用它,更快地解决您的问题。谢谢您的回答。在我看来,我不能使用第三个脚本来连接这两个小部件,因为对话框窗口的实例只能在单击主窗口的按钮时创建,因此我必须在单击按钮时的插槽中创建此实例。对于删除问题,如何删除对话框窗口的实例?我粘贴了代码,因为我是从另一台计算机获得的:p。但是你是对的,一定有更好的解决办法。非常感谢你的回答!正如您所说,我已经在主窗口的init中编写了self.dialog=DialogWindow(self),在它的正下方我还编写了:self.dialog.getMySignal().connect(self.updateLabelAnswer)。这是访问self.dialog的mySignal属性的好方法吗?因为我不想直接编写self.dialog.mySignal来破坏封装。然而,我的解决方案让我想起了丑陋。关于删除对话框窗口,我听从了你的建议,并不在意。我只是写show()和