Python Qt从接受/完成信号的向导/对话框中检索值的标准方法 我使用PyQt,但我猜同样的问题也适用于Qt C++。< /P>

Python Qt从接受/完成信号的向导/对话框中检索值的标准方法 我使用PyQt,但我猜同样的问题也适用于Qt C++。< /P>,python,qt,pyqt,dialog,signals,Python,Qt,Pyqt,Dialog,Signals,假设我有一个带有按钮的主窗口,该按钮打开一个收集数据的向导,并且在向导关闭后需要在主窗口中使用数据。标准程序 所以有多种方法可以做到这一点。或者我可以将对主窗口的引用传递给向导,它使用主窗口引用完成所有工作,但我认为这破坏了模块化。我还可以将回调连接到向导接受拒绝或完成信号,但在该回调中,我没有向导本身的引用,因此无法访问向导字段中的数据。除非我将对向导的引用存储为实例变量,以便从回调中再次访问它 另一个选项是,即使我还没有完全理解它,也要获取信号发射器的引用,即使用回调中的向导。但这似乎并不可

假设我有一个带有按钮的主窗口,该按钮打开一个收集数据的向导,并且在向导关闭后需要在主窗口中使用数据。标准程序

所以有多种方法可以做到这一点。或者我可以将对主窗口的引用传递给向导,它使用主窗口引用完成所有工作,但我认为这破坏了模块化。我还可以将回调连接到向导接受拒绝或完成信号,但在该回调中,我没有向导本身的引用,因此无法访问向导字段中的数据。除非我将对向导的引用存储为实例变量,以便从回调中再次访问它

另一个选项是,即使我还没有完全理解它,也要获取信号发射器的引用,即使用回调中的向导。但这似乎并不可取


那么规范的方法是什么呢?

前提:这是一个基于观点的问题,因为没有一个也是唯一的好方法可以做到这一点。我只是想评论一下,基于意见的答案/问题在这里是不被鼓励的,但是有限的格式并没有太大的帮助

传递引用并不一定会破坏模块化。 相反,这正是QDialog通常初始化的内容:父对象是调用窗口,这也是QDialog对父对象或整个应用程序的模态方式,这意味着只要对话框处于活动状态,就不允许在对话框之外进行交互

好吧,我不知道这是否真的被认为是规范的,但以下是最常用的建议方法。 这个想法是,你有一个子对象作为QDialog,通常在你需要它的时候,它可能会被初始化,也可能不会被初始化,这取决于你;重要的一点是,至少在更新其结果所需的时间内,您需要对其进行引用,这甚至可能发生在单个方法/槽的范围内

from PyQt5 import QtWidgets

class MyWizard(QtWidgets.QDialog):
    def __init__(self, parent=None):
        super().__init__(parent)
        layout = QtWidgets.QVBoxLayout()
        self.setLayout(layout)
        self.checkBox = QtWidgets.QCheckBox('check')
        layout.addWidget(self.checkBox)
        self.input = QtWidgets.QLineEdit()
        layout.addWidget(self.input)
        buttonBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok|QtWidgets.QDialogButtonBox.Cancel)
        layout.addWidget(buttonBox)
        buttonBox.accepted.connect(self.accept)
        buttonBox.rejected.connect(self.reject)

    def setData(self, **data):
        self.checkBox.setChecked(data.get('check', False))
        self.input.setText(data.get('text', ''))

    def getData(self):
        return {'check': self.checkBox.isChecked(), 'text': self.input.text()}

    def exec_(self, **data):
        self.setData(**data)
        return super().exec_()


class MyWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        centralWidget = QtWidgets.QWidget()
        self.setCentralWidget(centralWidget)
        layout = QtWidgets.QHBoxLayout()
        centralWidget.setLayout(layout)
        self.showWizBtn = QtWidgets.QPushButton('Show wizard')
        layout.addWidget(self.showWizBtn)
        self.showWizBtn.clicked.connect(self.getDataFromWizard)
        self.data = {}

    def getDataFromWizard(self):
        wiz = MyWizard(self)
        if wiz.exec_(**self.data):
            self.data.update(wiz.getData())


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())
另一种可能是创建一个持久的子对话框,但请记住,如果父级可以更改数据,则必须找到更新它的方法,至少在执行时是这样;这里的概念是,您可以在需要时执行该对话框,并且您可以将接受的信号连接到一个可以从该对话框获取数据的插槽。这不是一个常见的用途,也不是非常推荐的IMHO,应该仅用于非常特定的场景


正如您已经发现的,不建议使用发送器:信号是异步的,而在正常情况下,发送器是可靠的,除非绝对必要,否则最好避免使用它。

有趣的方法,当然给了我新的想法。但是exec的使用是非常困难的。一个更简洁的方法是使用诸如accept之类的信号,但是缺少对向导的引用。这与您在上一段中所说的不鼓励使用信号的说法完全矛盾。实际上,文档中的内容是自相矛盾的,因为它建议在“常规用法”部分中使用exec进行模态对话框。。。