Search code examples
pythonuser-interfacepyqtqstackedwidget

Switching between frames without erasing contents of each frame


I've been writing a GUI using the below setCentralWidget method (simplified here) for transitioning between frames - but didn't realize until pretty far in that it erased each window upon moving to the next (which I need to avoid). My actual code has entry boxes that need to be kept in their completed state for when the user goes back to that frame to revise, etc.

I'd like to rewrite with as little change to my hierarchy as possible - most likely using QStackedWidget or something similar. The only examples I've found online are not written within the class hierarchy (each page within its own class) which my program needs. Does anyone see a simple / elegant solution within this sample text below?

import sys
from PyQt4.QtGui import QApplication, QMainWindow, QPushButton, QWidget

class UIWindow(QWidget):
    def __init__(self, parent=None):
        super(UIWindow, self).__init__(parent)
        self.ToolsBTN = QPushButton('go P1', self)
        self.ToolsBTN.move(50, 350)

class UIToolTab(QWidget):
    def __init__(self, parent=None):
        super(UIToolTab, self).__init__(parent)
        self.CPSBTN = QPushButton("go P2", self)
        self.CPSBTN.move(100, 350)

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setGeometry(50, 50, 400, 450)
        self.setFixedSize(400, 450)
        self.gotoP2()

    def gotoP2(self):
        self.ToolTab = UIToolTab(self)
        self.setWindowTitle("Page1")
        self.setCentralWidget(self.ToolTab)
        self.ToolTab.CPSBTN.clicked.connect(self.gotoP1)
        self.show()

    def gotoP1(self):
        self.Window = UIWindow(self)
        self.setWindowTitle("Page2")
        self.setCentralWidget(self.Window)
        self.Window.ToolsBTN.clicked.connect(self.gotoP2)
        self.show()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    sys.exit(app.exec_())

Solution

  • Instead of switching the centralwidget, because:

    Note: QMainWindow takes ownership of the widget pointer and deletes it at the appropriate time.

    you also can't use instances, because they would get deleted after first use as well, you should use a QStackedWidget and set the centralwidget just once.

    class MainWindow(QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.setGeometry(50, 50, 400, 450)
    
            ToolTab = UIToolTab( self )
            ToolTab.CPSBTN.clicked.connect( self.gotoP1 )
            Window = UIWindow( self )
            Window.ToolsBTN.clicked.connect( self.gotoP2 )
            self.stack = QStackedWidget(self)
            self.stack.addWidget(ToolTab)
            self.stack.addWidget( Window )
            self.setCentralWidget( self.stack )
            self.show()
    
        def gotoP2(self):
            self.setWindowTitle("Page1")
            self.stack.setCurrentIndex(0)
    
        def gotoP1(self):
            self.setWindowTitle("Page2")
            self.stack.setCurrentIndex( 1 )