Search code examples
pythonconstructorparent-childpysideqstackedwidget

PySide multi-window, get QStackWidget to work


I need to create multi-window GUI, first I tried it with QWidgets, but finally I discover QStackWidget tool I need to use. So Im trying to, but Ive got some problems. Thanks for Your time.

class MainWindow(QMainWindow):

    def __init__(self):

        super(MainWindow,self).__init__()

        self.mainWidget = MainWidget()
        self.searchWidget = SearchWidget()
        self.sWidget = QStackedWidget()
        self.sWidget.addWidget(self.mainWidget)
        self.sWidget.addWidget(self.searchWidget)

        self.initUI() 

and calling setCurrentWidget from the sub_widget class:

class MainWidget(QWidget):

    def __init__(self, parent=MainWindow):

        super(MainWidget,self).__init__()
        self.initUI()

    def initUI(self):

        searchButton = QPushButton('searchButton',self)
        optionButton = QPushButton('optionButton',self)
        quitButton = QPushButton('quitButton',self)
        listButton = QPushButton('listButton',self)

        searchButton.clicked.connect(self.goSearch)

        hbox = QHBoxLayout()
        hbox.addWidget(listButton)
        hbox.addWidget(quitButton)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addWidget(searchButton)
        vbox.addWidget(optionButton)
        vbox.addLayout(hbox)

        self.setLayout(vbox)

    def goSearch(self):
        self.parent().sWidget.setCurrentWidget(self.parent().searchWidget)

Ive got this message from IDE:

  self.parent().sWidget.setCurrentWidget(self.parent().searchWidget)
  AttributeError: 'PySide.QtGui.QStackedWidget' object has no attribute 'sWidget'

What is the thing Im doing wrong?


Solution

  • I'm going to comment on the code you posted here: http://pastebin.com/fBfS1X5m

    An important thing to know is that you can put widgets within widgets and so on. For example:

    class Widget(QWidget):
        def __init__(self, parent=None):
            layout = QVBoxLayout(self)
            childWidget = QWidget(parent=self)
            layout.addWidget(childWidget)
    

    Just a quick note: You don't need setLayout if you pass self to the main layout constructor - via the docs.

    Anyways, what I'm trying to illustrate here is that the QStackedWidget and the SearchWidget really shouldn't be a part of the MainWindow, but should live inside their own relevant widget that will handle switching between the QStackedWidget pages.

    For example the MainWindow.__init__ would only look like this:

    class MainWindow(QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
    
            self.mainWidget = MainWidget(self)
            self.setCentralWidget(self.mainWidget)
    
            self.initUI()
    

    Your MainWidget would then look something like:

    class MainWidget(QtGui.QWidget):
        ...
    
        def initUI(self):
            ...
    
            self.stack = QtGui.QStackedWidget(parent=self)
    
            self.searchWidget = SearchWidget(parent=self)
            self.searchWidget.searchButton.clicked.connect(self.goSearch)
            self.backWidget = BackWidget(parent=self)
            self.backWidget.backButton.clicked.connect(self.goBack)
    
            ...
    
        def goSearch(self):
            self.stack.setCurrentWidget(self.backWidget)
    
        def goBack(self):
            self.stack.setCurrentWidget(self.searchWidget)
    

    I've renamed some of the class names to make a little more sense (To me at least). SearchWidget was your old MainWidget. BackWidget was your old SearchWidget. Following those changes SearchWidget would look the same as your old MainWidget with one exception - we save a reference to the search button so we can access it in the MainWidget class as seen above (when we connect their signals to our slots). We do the same for the button in BackWidget.

    The two renamed "child" widgets:

    class SearchWidget(QtGui.QWidget):
        ...
    
        def initUI(self):
            self.searchButton = QtGui.QPushButton('searchButton', parent=self)
            optionButton = QtGui.QPushButton('optionButton', parent=self)
            quitButton = QtGui.QPushButton('quitButton', parent=self)
            listButton = QtGui.QPushButton('listButton', parent=self)
    
            vbox = QtGui.QVBoxLayout(self)
            vbox.addStretch(1)
            vbox.addWidget(self.searchButton)
            vbox.addWidget(optionButton)
    
            hbox = QtGui.QHBoxLayout()
            hbox.addWidget(listButton)
            hbox.addWidget(quitButton)
    
            vbox.addLayout(hbox)
    
    class BackWidget(QtGui.QWidget):
        ...
    
        def initUI(self):
            self.backButton = QtGui.QPushButton('GoBack', parent=self)
    

    So now we have something like:

    MainWindow  
       |---MainWidget  
              |---QStackedWidget  
                     |---SearchWidget  
                     |---BackWidget  
    

    You can find the full working code here.