动态 add/remove 根据 QWizardPage 内容的变化从 QWizardPage 完成

Dynamically add/remove Finish from QWizardPage based on change in its content

我正在按照 license wizard(使用 PyQt5)上的教程尝试学习如何创建非线性向导。但是我似乎陷入了一个问题。

我想要一个带有 QComboBox 的页面,其中所选项目确定包含组合框的当前 QWizardPage 是否是最终页面。

到目前为止页面包含以下内容:

class CalibrationPageSource(QWizardPage):
    def __init__(self, parent):
        super(CalibrationPageSource, self).__init__(parent)
        self.setTitle('Calibration Wizard')
        self.setSubTitle('Select the source for the calibration')

        layout = QVBoxLayout()
        label = QLabel('''
            <ul>
                <li><b>From calibration file</b>: browse and select an existing YAML calibration file that contains the camera matrix and distortion coefficients (for example from a previous calibration)</li>
                <li><b>From image files</b>: browse and select one or more image files with the calibration pattern visible inside each</li>
                <li><b>From stream</b> - if the calibration node is connected to an active <b><i>Device node</i></b> you can use its image stream to interactively calibrate your device</li>
            </ul>
        ''')
        label.setWordWrap(True)
        layout.addWidget(label)

        layout_sources = QHBoxLayout()
        label_sources = QLabel('Source:')
        self.selection_sources = QComboBox()
        self.selection_sources.addItem('Calibration file')
        self.selection_sources.addItem('Image files')
        self.selection_sources.addItem('Stream')
        self.selection_sources.currentIndexChanged['QString'].connect(self.source_changed)
        self.selection_sources.setCurrentIndex(1)
        layout_sources.addWidget(label_sources)
        layout_sources.addWidget(self.selection_sources)
        layout.addLayout(layout_sources)

        self.setLayout(layout)

    @pyqtSlot(str)
    def source_changed(self, source):
        if source == 'Calibration file':
            self.setFinalPage(True)
            # TODO Add file dialog
        else:
            self.setFinalPage(False)
            # TODO Remove file dialog (if present)

每当 self.selection_sources 的当前项目更改为 Calibration file 时,我想跳过使页面最终化的向导的其余部分。在这种情况下,我想删除 Next 按钮。在所有其他情况下(目前只有两种情况:Image filesStream)我想让向导正常运行,而不是最后一页。

我尝试实现一个自定义isComplete(...),但问题在于选择NextFinish时,选择Calibration file。我可以忍受禁用 Next 按钮(而不是完全隐藏它),但禁用 Finish 基本上对我来说没有意义。 Next 按钮的存在让我感到非常惊讶。当到达最后一页时,它不是应该完全消失吗?

有什么办法解决这个问题吗?我考虑过遍历 QWizardPage 中的项目并手动 disabling/hiding Next 按钮,但我希​​望有一种更简单、开箱即用的方法来做到这一点。在当前状态下,Finish 的动态插入正在运行,但是由于 Next 按钮,向导的转换设置不正确。

在您的代码中,您已经使用 QWizardPage.setFinalPage(True) 将完成按钮添加到中间页面。现在下一个按钮仍然存在。删除它的一种方法(不确定这是否是最好的方法)是通过调用 QWizard.removePage()QWizard.nextId().

来删除所有后续页面

示例:

from PyQt5.QtWidgets import *

def end_wizard_after_page_two():
    # add finish button to wizard
    p2.setFinalPage(True)
    # remove all over buttons
    while True:
        id = w.nextId()
        if id == -1:
            break
        w.removePage(id)

app = QApplication([])

# page 1
p1 = QWizardPage()
p1.setTitle('Page 1')

# page 2
p2 = QWizardPage()
p2.setTitle('Page 2')

b = QPushButton('No further pages')
b.clicked.connect(end_wizard_after_page_two)
l = QVBoxLayout(p2)
l.addWidget(b)

# page 3
p3 = QWizardPage()
p3.setTitle('Page 3')

# wizard
w = QWizard()
w.addPage(p1)
w.addPage(p2)
w.addPage(p3)
w.show()

app.exec_()

参见本示例中的方法 end_wizard_after_page_two()

如果您想反转效果,则必须反向执行所有操作(再次添加剩余的页面并将 setFinalPage 设置为 False)。

这几乎晚了一年,但我想我弄清楚了问题所在。您对 setFinalPage(True) 的调用只是在您的 QWizardPage 中设置了一个状态标志。它不会自动传播回您的 QWizard.

只有一种信号会向后传播信息:completeChanged。这个名字有点误导,但文档似乎表明如果你正确阅读它们,它就会做你想做的事情:

If you reimplement isComplete(), make sure to emit completeChanged() whenever the value of isComplete() changes, to ensure that QWizard updates the enabled or disabled state of its buttons.

事实上,运行 遇到了同样的问题,我可以通过

解决它
if source == 'Calibration file':
    self.setFinalPage(True)
    ...
else:
    self.setFinalPage(False)
    ...
self.completeChanged.emit()

粗体线是新的。在这两种情况下都需要调用它,并将按钮从 "Next" 切换到 "Finish",然后再返回 select 不同的选项。