Search code examples
pysideqstackedwidget

PySide - How to reset the CentralWidget after closing of a widget using QStackedWidget


I'm using a QTabWidget for some postprocessing. Initially, the content of the tab is a button to open a txt file. Once this button is clicked, the content of the tab changes and a plot is made based on the data inside the txt file. In addition, there is a button to close the plot.

With QStackedWidget, the "openFileWidget" is a CentralWidget, which is replaced by the "newWindow" widget after opening the txt file. If I close the "newWindow" widget, I get back to the (empty) tab. If I want to have the "openFileWidget" re-appear, what is the best way to do so? As the newWindow is closed, is it still necessary to use takeAt?

import os, sys
from PySide import QtCore, QtGui

class MainStartTabWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MainStartTabWindow, self).__init__(parent)
        tabWidget = QtGui.QTabWidget()
        tabWidget.addTab(tab1Tab(), self.tr("tab 1"))

        mainLayout = QtGui.QVBoxLayout()
        mainLayout.addWidget(tabWidget)
        self.setLayout(mainLayout)


class tab1Tab(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(tab1Tab, self).__init__(parent)
        self.initTab1Content()

    def initTab1Content(self):
        self.centralOpenFile = QtGui.QStackedWidget()
        self.setCentralWidget(self.centralOpenFile)
        widgetOpenFile = openFileWidget(self)
        widgetOpenFile.openFileButton.clicked.connect(self.setOpenFile)
        widgetOpenFile.openFileButton.clicked.connect(self.FileOpened)
        self.centralOpenFile.addWidget(widgetOpenFile)

    def FileOpened(self):
        FileOpened_widget = newWindow(self.path)
        self.centralOpenFile.addWidget(FileOpened_widget)
        self.centralOpenFile.setCurrentWidget(FileOpened_widget)

    def setOpenFile(self):
        options = QtGui.QFileDialog.Options()
        fileChoice = "txt (*.txt)"
        self.path, filtr = QtGui.QFileDialog.getOpenFileName(self, "Open file", "", fileChoice, "", options)

        return self.path


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

        self.openFileButton = QtGui.QPushButton("click to open")
        self.openFileButton.setFixedSize(150,150)
        layoutNoFileYet = QtGui.QGridLayout()
        layoutNoFileYet.addWidget(self.openFileButton, 1, 1)
        self.setLayout(layoutNoFileYet)


class newWindow(QtGui.QMainWindow):
    def __init__(self, PathToPlanFile, parent=None):
        super(newWindow, self).__init__(parent)
        self.createFrameUI()

    def createFrameUI(self):
        self.frameUI = QtGui.QWidget()
        self.buttonClose = QtGui.QPushButton("close")
        self.buttonClose.clicked.connect(self.close)

        self.label = QtGui.QLabel("plot based on openend file")

        layoutFileLoaded = QtGui.QGridLayout()
        layoutFileLoaded.addWidget(self.buttonClose, 1, 1)
        layoutFileLoaded.addWidget(self.label, 2, 1)

        self.frameUI.setLayout(layoutFileLoaded)
        self.setCentralWidget(self.frameUI)


def main():
    app = QtGui.QApplication(sys.argv)
    testPlot = MainStartTabWindow()
    testPlot.show()
    sys.exit(app.exec_())




if __name__ == "__main__":
    main()

Solution

  • I would change your approach entirely. You only want one QMainWindow. There is no need for the openFileWidget; it is just a button. The next thing I would do is simply create a custom QTabWidget editing the addTab to open a file.

    import os, sys
    from PySide import QtCore, QtGui
    
    class MainWindow(QtGui.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.main_widget = QtGui.QTabWidget()
            self.setCentralWidget(self.main_widget)
    
            self.main_widget.addTab(Page1(), "Tab 1")
            self.main_widget.addTab(Page2(), "Tab 2")
            self.main_widget.addTab(Page3(), "Tab 3")
            self.main_widget.addTab(Page4(), "Tab 4")
    
            self.main_widget.setCurrentIndex(0)
        # end Constructor
    # end MainWindow
    
    class Page1(QtGui.QWidget):
        """First page to display."""
    
        def __init__(self):
            super().__init__()
    
            self.main_layout = QtGui.QVBoxLayout()
            self.setLayout(self.main_layout)
    
            # Widgets
            self.hlayout = QtGui.QHBoxLayout()
            self.hlayout.setContentsMargins(0, 0, 0, 0)
            self.read_btn = QtGui.QPushButton("Open File")
            self.clear_btn = QtGui.QPushButton("Clear Data")
    
            self.hlayout.addWidget(self.read_btn)
            self.hlayout.addWidget(self.clear_btn)
    
            # Display data here
            self.display = DisplayWidget("plot based on openend file")
    
            # Properties
            self.data = None
    
            # Signals
            self.read_btn.clicked.connect(self.read_file)
            self.clear_btn.clicked.connect(self.display.clearData)
    
            # Layout
            self.main_layout.addLayout(self.hlayout)
            self.main_layout.addWidget(self.display)
        # end Constructor
    
        def read_file(self, path=""):
            """Read file dialog."""
            if path == "":
                options = QtGui.QFileDialog.Options()
                fileChoice = "txt (*.txt)"
                path, _ = QtGui.QFileDialog.getOpenFileName(self, "Open file", "",
                                                                 fileChoice, "", options)
    
            # Cancel button was pressed
            if path == "":
                return
    
    
            with open(path, "r") as file:
                lines = file.readlines()
            # close file
    
            self.display.setData(lines)
        # end read_file
    
        def set_data(self, data=None):
            """Set the data to display here."""
    
        # end set_data
    # end class Page1
    
    class DisplayWidget(QtGui.QWidget):
        def __init__(self, text=""):
            super().__init__()
    
            # Layout
            self.main_layout = QtGui.QVBoxLayout()
            self.setLayout(self.main_layout)
    
            # Widgets Have all of your display stuff here
            self.label = QtGui.QLabel(text)
    
            # Properties
            self.data = None
    
            # Add Layout
            self.main_layout.addWidget(self.label)
        # end Constructor
    
        def setData(self, data):
            """Set the data to show the plot."""
            self.data = data
    
            # Plot stuff here
            self.label.setText(str(data))
        # end setValue
    
        def clearData(self):
            """Clear the plot data."""
            self.data = None
    
            # Clear data here
            self.label.setText("Open a file to display data")
        # end clearData
    # end class DisplayWidget
    
    class Page2(QtGui.QWidget): 
        pass
    # end class Page2
    
    class Page3(QtGui.QWidget):
        pass
    # end class Page3
    
    class Page4(QtGui.QWidget):
        pass
    # end class Page4
    
    
    def main():
        app = QtGui.QApplication(sys.argv)
        testPlot = MainWindow()
        testPlot.show()
        sys.exit(app.exec_())
    
    
    
    
    if __name__ == "__main__":
        main()
    

    I would not let the user close the tab. Just have them be able to clear and reload the data if they wish. If you really want them to close then have the clear data button close the displaywidget and have the read file button create a new widget every time. I don't think you need to create a new widget every time. If you don't like the tabs you may want to look into the QToolBox.