0

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?

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
user4175226
  • 23
  • 1
  • 7

2 Answers2

0

This line:

    def __init__(self, parent=MainWindow):

sets the MainWindow class as a default argument, when you actually need an instance. But even if it was an instance, in the next line, you also fail to pass it on to the base-class:

    super(MainWidget,self).__init__()

What you need to do instead is something like this:

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow,self).__init__()
        # pass an instance of MainWindow here
        self.mainWidget = MainWidget(self)
        ...

class MainWidget(QWidget):
    def __init__(self, parent):
        # pass the parent to the base-class
        super(MainWidget, self).__init__(parent)
        ...

UPDATE:

The stack-widget will re-parent any widgets added to it, so that it becomes the parent. There are ways of working around this, but I think the real problem with your code is that you have the structure backwards. The buttons that set the current widget should be controlled by the main-window, and the widgets in the stack should work completely independantly of that.

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • Well, I still can't figure it out. Ive got a problem with getting to widget 'searchWidget' in MainWindow from MainWidget 'def goSearch'. I set all like u show me. the IDE yells at me: File "/home/maze/Develop/StartApp/startapp.py", line 71, in goSearch self.parent().swidget.setCurrentWidget(self.parent().searchWidget) AttributeError: 'PySide.QtGui.QStackedWidget' object has no attribute 'swidget' – user4175226 Oct 31 '14 at 18:11
0

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.

  • I would ask a one thing. Could You somehow explain, why we shouldnt run the QStacked and other Widgets in a main window instance? It was making a sense to me, to put those there. – user4175226 Nov 08 '14 at 21:10
  • You could do it that way, but I just like to keep things separate. I like to handle the general UI things in my main window like handling the status bar, the menu bar, etc. And thus keep widget specific things separate (except for connecting signals/slots). It also keeps things a little more contained and neater. – Stephen Lam Nov 09 '14 at 19:07