pythonpyqtpyqt5qwizardqwizardpage

Update information on QWizardPage based on information from other pages when IndependentPages option is used


I want to build a QWizard that takes information in some initial pages, then summarizes this info on the final page. The user should be able to navigate back and update values on initial pages, without losing information. Thus I am using the QWizard.IndependentPages option. This prevents Qt from running the cleanupPage() which clears previously input data. However, an issue is that initializePage() is also only called the first time the page is visited.

I cannot seem to find a clean method to allow the information on the final page to always be updated with whatever has been input on previous pages.

I have attached a small piece of code, with 3 pages, to illustrate the functionality as-is. When navigating to the second page, inputting data, then reviewing this data on page 3. When going back to page 2, the previous data is still shown (as required), when navigating to page 1 and then to page 2, still the initial data is shown (as required). Then the data op page 2 is changed and the user moves to page 3, the old data is still shown. This is because not the constructor or the initializePage() function is called, and nothing triggers an update of this label.

from os import terminal_size
import sys
import csv
from PyQt5 import QtCore

from PyQt5.QtCore import QDir
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QFrame, QWizard, QWizardPage, QVBoxLayout, QLabel, QFormLayout, QRadioButton, QLineEdit, QComboBox, \
    QGroupBox, QApplication, QCheckBox, QHBoxLayout, QScrollArea, QWidget



wizard_page_index = {
    "IntroPage": 0,
    "EvalPage": 1,
    "RegisterPage": 2
}


TEST = ""

class LicenseWizard(QWizard):
    def __init__(self):
        super().__init__()
        self.setPage(wizard_page_index["IntroPage"], IntroPage())
        self.setPage(wizard_page_index["EvalPage"], EvalPage())
        self.setPage(wizard_page_index["RegisterPage"], RegisterPage())

        self.setStartId(wizard_page_index["IntroPage"])

        self.setWindowTitle("Test Wizard")
        self.setOption(QWizard.IndependentPages)



class IntroPage(QWizardPage):
    def __init__(self):
        super().__init__()

        self.setTitle("Intro Page")

        data_source_layout = QFormLayout() 

        eval_btn = QRadioButton("evaluate")
        self.registerField("evaluate_btn", eval_btn)
        data_source_layout.addWidget(eval_btn)

        register_btn = QRadioButton("register")
        self.registerField("register_btn", register_btn)
        data_source_layout.addWidget(register_btn)

        register_btn.setChecked(True)

        layout = QVBoxLayout()
        layout.addWidget(eval_btn)
        layout.addWidget(register_btn)

        self.setLayout(layout)

    def nextId(self) -> int:
        if self.field("evaluate_btn"):
            return wizard_page_index["EvalPage"]
        else:
            return wizard_page_index["RegisterPage"]
            

class EvalPage(QWizardPage):
    def __init__(self):
        super().__init__()
        self.setTitle("EvalPage")

        layout = QFormLayout()
        model_name = QLineEdit(TEST)
        layout.addRow("Model Name:", model_name)
        self.registerField("model_name*", model_name)

        self.setLayout(layout)

    def nextId(self) -> int:
        return wizard_page_index["RegisterPage"]



class RegisterPage(QWizardPage):
    def __init__(self):
        super().__init__()
        self.setTitle("RegisterPage")
        self.label2 = QLabel()
        self.label2.setFrameStyle(QFrame.Panel)
        self.label2.setText(self.field("model_name"))

        layout = QFormLayout()
        
        layout.addRow("name:", self.label2)

        self.setLayout(layout)

        

    def initializePage(self) -> None:
        self.label2.setText(self.field("model_name"))
        

    def nextId(self) -> int:
    #    self.label2.setText(self.field("model_name"))
        return wizard_page_index["EvalPage"]



if __name__ == "__main__":

    application = QApplication(sys.argv)
    wizard = LicenseWizard()
    wizard.show()
    return_code = application.exec_()

    
    input('Press ENTER to exit')
    sys.exit(return_code)

Solution

  • One possible solution is to not use QWizard::IndependentPages and override the QWizard::cleanupPage() method:

    class LicenseWizard(QWizard):
        def __init__(self):
            super().__init__()
            self.setPage(wizard_page_index["IntroPage"], IntroPage())
            self.setPage(wizard_page_index["EvalPage"], EvalPage())
            self.setPage(wizard_page_index["RegisterPage"], RegisterPage())
    
            self.setStartId(wizard_page_index["IntroPage"])
    
            self.setWindowTitle("Test Wizard")
            # self.setOption(QWizard.IndependentPages)
    
        def cleanupPage(self, _id):
            pass