pythonpyside2qwidgetqtwidgetsqstackedwidget

How do I refresh QWidget to display the current information?


I have a PySide2 GUI that accepts a number from the user on page one then does some calculations and displays the results on page two. Each page is a QWidget within a QStackedWidget. There is a pushbutton on page two, the results page, that sends the user back to page one to enter a new number.

My problem is that when I enter a new number the results never change from the first number. I use print statements to confirm that the labels on the results page are updating but the display stays the same.

# importing the module
import os
import sys
from PySide2 import QtWidgets
import PySide2.QtUiTools as QtUiTools


class IncomeScreen(QtWidgets.QMainWindow):
    def __init__(self):
        super(IncomeScreen, self).__init__()

        # Load the IncomeScreen ui
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "main.ui")
        self.main = loader.load(path, self)

        # Connect the signals with custom slots
        self.main.calculate_pushButton.clicked.connect(self.calculate)

    def calculate(self):
        init_amount = self.main.income_lineEdit.text()
        IncomeScreen.init_amount = float(init_amount)
        # Create an instance of DistributionScreen class
        self.distribution = DistributionScreen()
        # Add DistributionScreen to the stacked widget
        widget.addWidget(self.distribution)
        # Change index to show DownloadPage
        widget.setCurrentIndex(widget.currentIndex()+1)


class DistributionScreen(QtWidgets.QMainWindow):
    def __init__(self):
        super(DistributionScreen, self).__init__()
        loader = QtUiTools.QUiLoader()
        path = os.path.join(os.path.dirname(__file__), "dialog.ui")
        self.dialog = loader.load(path, self)

        # Set initial amount to label
        self.dialog.initialAmount_label.setText(str(IncomeScreen.init_amount))
        print("Initial Amount = {:0.2f}".format(IncomeScreen.init_amount))

        # 10 Percent
        ten = IncomeScreen.init_amount * 0.1
        print("10% = {:0.2f}".format(ten))
        self.dialog.label_10percent.setText("{:0.2f}".format(ten))
        print(self.dialog.label_10percent.text())

        # 20 percent
        twenty = IncomeScreen.init_amount * 0.2
        print("20% = {:0.2f}".format(twenty))
        self.dialog.label_20percent.setText("{:0.2f}".format(twenty))
        print(self.dialog.label_20percent.text())

        # Update widget
        self.dialog.update()

        # Connect the signals with custom slots
        self.dialog.reset_pushButton.clicked.connect(self.reset)

    def reset(self):
        print("reset")
        # Change index to show IncomeScreen
        widget.setCurrentIndex(widget.currentIndex()-1)


# main
# if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
income = IncomeScreen()
widget = QtWidgets.QStackedWidget()
widget.addWidget(income)
widget.show()
try:
    sys.exit(app.exec_())
except:
    print("Exiting")

Also I'm using Python 3.7.4

EDIT: You can download the ui files here


Solution

  • There are various problems with your code, but the most important one is that every time calculate is called, a new DistributionScreen is added to the stacked widget, but widget.setCurrentIndex(widget.currentIndex()+1) will always go to the second index of the stacked widget (which is the first instance you created).

    A possible simple workaround could be to use the index of the widget returned by addWidget or use setCurrentWidget:

        def calculate(self):
            init_amount = self.main.income_lineEdit.text()
            IncomeScreen.init_amount = float(init_amount)
            self.distribution = DistributionScreen()
            index = widget.addWidget(self.distribution)
            widget.setCurrentIndex(index)
            # alternatively:
            widget.setCurrentWidget(self.distribution)
    
    

    Unfortunately, while this would make your code work, it's not a valid solution, as there are other important issues that would create other problems sooner or later:

    This is a possible revision of your code (untested, as you didn't provide the ui files).

    import os
    import sys
    from PySide2 import QtWidgets, QtCore
    import PySide2.QtUiTools as QtUiTools
    
    
    class IncomeScreen(QtWidgets.QWidget):
        # a custom signal to notify that we want to show the distribution page
        # with the provided value
        goToDistribution = QtCore.Signal(float)
        def __init__(self):
            super(IncomeScreen, self).__init__()
    
            # Load the IncomeScreen ui
            loader = QtUiTools.QUiLoader()
            path = os.path.join(os.path.dirname(__file__), "main.ui")
            self.main = loader.load(path, self)
    
            # a proper layout that manages the contents loaded with QUiLoader
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.main)
    
            # Connect the signals with custom slots
            self.main.calculate_pushButton.clicked.connect(self.calculate)
    
        def calculate(self):
            init_amount = self.main.income_lineEdit.text()
            self.goToDistribution.emit(float(init_amount))
    
    
    class DistributionScreen(QtWidgets.QWidget):
        reset = QtCore.Signal()
        def __init__(self):
            super(DistributionScreen, self).__init__()
            loader = QtUiTools.QUiLoader()
            path = os.path.join(os.path.dirname(__file__), "dialog.ui")
            self.dialog = loader.load(path, self)
    
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.dialog)
    
            self.dialog.reset_pushButton.clicked.connect(self.reset)
    
        def setIncome(self, value):
            # Set initial amount to label
            self.dialog.initialAmount_label.setText(str(value))
            print("Initial Amount = {:0.2f}".format(value))
    
            # 10 Percent
            ten = value * 0.1
            print("10% = {:0.2f}".format(ten))
            self.dialog.label_10percent.setText("{:0.2f}".format(ten))
            print(self.dialog.label_10percent.text())
    
            # 20 percent
            twenty = value * 0.2
            print("20% = {:0.2f}".format(twenty))
            self.dialog.label_20percent.setText("{:0.2f}".format(twenty))
            print(self.dialog.label_20percent.text())
    
    
    class MainWidget(QtWidgets.QStackedWidget):
        def __init__(self):
            super(MainWidget, self).__init__()
            # create *both* the pages here
            self.income = IncomeScreen()
            self.addWidget(self.income)
            self.distribution = DistributionScreen()
            self.addWidget(self.distribution)
    
            self.income.goToDistribution.connect(self.goToDistribution)
            self.distribution.reset.connect(self.reset)
    
        def goToDistribution(self, value):
            # we received the notification signal, then we set the value and 
            # show the related page by switching to it
            self.distribution.setIncome(value)
            self.setCurrentWidget(self.distribution)
    
        def reset(self):
            self.setCurrentWidget(self.income)
    
    if __name__ == "__main__":
        app = QtWidgets.QApplication(sys.argv)
        mainWidget = MainWidget()
        mainWidget.show()
        sys.exit(app.exec_())
    

    Note that: