繁体   English   中英

从向导/对话框中接受/完成的信号中检索值的Qt规范方法

[英]Qt canonical way of retrieving values from Wizard / Dialog on accepted / finished signal

我正在使用PyQt,但我想同样的问题也适用于Qt C ++。

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

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

另一个选择是(即使我尚未完全理解)使用https://doc.qt.io/qt-5/qobject在回调中获取对信号发射器(即向导)的引用。 html#sender 但这似乎不建议。

那么规范的方式是什么?

前提:这是一个基于观点的问题,因为没有一种且只有一种 “好的”方式可以做到这一点。 我只是想发表评论(SO中不建议基于意见的答案/问题),但是有限的格式不是很有帮助。

“通过引用”并不一定会破坏模块化。
取而代之的是QDialog通常被初始化的内容:父级是“调用”窗口,这也是QDialog如何对父级或整个应用程序进行“模态化”(这意味着只要在对话框外不允许交互,它是活动的)。

AFAIK,我不知道这是否真的被认为是规范的 ,但是以下是最常用的建议方法。
这个想法是,您有一个子对象(通常是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_())

另一种可能性是创建一个持久的子对话框(但请记住,如果父级可以更改数据,则至少在执行时,必须找到一种更新方法); 这里的概念是,您可以在需要时执行对话框,并且将accepted信号连接到可以从对话框获取数据的插槽。 这不是常见用途(也不建议使用IMHO),并且仅应用于非常特殊的情况。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM