Pedro Monteiro
Pedro Monteiro

Reputation: 357

Wizard-like user interface with buttons next and back

I'm developing an application using the Qt Designer and PyQt4, I need to make several screens where each screen I capture user-specific data, for that I need to implement a next button and a back button similar to

https://files.support.epson.com/htmldocs/pho825/pho825f1/images/2knhw1.gif

where the current screen closes and the following opens when the user clicks next or if he clicks back, the screen closes and opens the previous screen, I made an example with only the next buttons and back to exemplify, if I was not clear:

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class Frm(QWidget):
    def __init__(self, parent = None):
        super(Frm, self).__init__(parent)

        next = QPushButton('Next >', self)
        back = QPushButton('< Back', self)

        hbox = QHBoxLayout()

        hbox.addWidget(back)
        hbox.addWidget(next)

        self.setLayout(hbox)

if __name__ == '__main__':
    import sys
    root = QApplication(sys.argv)
    app = Frm(None)
    app.show()
    root.exec_()

In short: How do I implement a function that calls another screen and close the current at the click of a button?

Upvotes: 3

Views: 4771

Answers (2)

Mad Physicist
Mad Physicist

Reputation: 114330

There is a QWizard class that allows you to create wizards in Qt and PyQt. It implements all the functionality you want, and lots more. All you do is design your pages by extending QWizardPage, and add them to the wizard. This is much simpler than doing the whole thing from scratch as you propose.

Upvotes: 0

NoDataDumpNoContribution
NoDataDumpNoContribution

Reputation: 10859

First about a misconception: you do usually not create/show one screen (window) and close another, you usually only exchange the content of a wizard-like dialog window upon actions like pressing the buttons. The window is alive the whole time until the multiple page task is finished.

So I take it your question is really about:

How to exchange a widget in a layout?

Since you may still use PyQt4 which does not yet have QLayout.replaceWidget, it's best to just use methods removeWidget and addWidget of QLayout and since addWidget adds a widget to the end of the layout items list, I prefer a dedicated layout just for the interchangeable content of your wizard (see also: How to add an Item to the specific index in the layout).

Example code using PyQt5 but easily transferrable to PyQt4. Only the next button is implemented.

from PyQt5 import QtWidgets

class MyWizard(QtWidgets.QWidget):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # vertical layout, wraps content layout and buttons layout
        vertical_layout = QtWidgets.QVBoxLayout()
        self.setLayout(vertical_layout)

        # content widget and layout
        self.content_layout = QtWidgets.QVBoxLayout() # could be almost any layout actually
        self.content = QtWidgets.QLabel('Page1') # customize with your content
        self.content_layout.addWidget(self.content)
        vertical_layout.addLayout(self.content_layout)

        # back, forward buttons wraped in horizontal layout
        button_layout = QtWidgets.QHBoxLayout()
        button_layout.addStretch()
        back_button = QtWidgets.QPushButton('Back')
        back_button.clicked.connect(self.back_button_clicked)
        button_layout.addWidget(back_button)
        forward_button = QtWidgets.QPushButton('Forward')
        forward_button.clicked.connect(self.forward_button_clicked)
        button_layout.addWidget(forward_button)
        vertical_layout.addLayout(button_layout)

    def back_button_clicked(self):
        """
        The back button is clicked.
        """
        pass

    def forward_button_clicked(self):
        """
        The forward button is clicked.
        """

        # remove old content
        self.content_layout.removeWidget(self.content)
        self.content.deleteLater()

        # create new content
        self.content = QtWidgets.QLabel('Another Page')

        # add new content
        self.content_layout.addWidget(self.content)

app = QtWidgets.QApplication([])

wizard = MyWizard()
wizard.setWindowTitle('MyWizard Example')
wizard.setFixedSize(600, 400)
wizard.show()

app.exec_()

And it looks like:

enter image description here

However, as already written in the comment by Marius, there is quite extensive support for such dialogs in Qt using QWizard. So I strongly recommend to use that instead. The example above is only to demonstrate the ability of inserting and removing widgets in layouts.

You should definitely use QWizard for such problems!

Upvotes: 5

Related Questions