2

I can't find good explanations about the different usage of QMainWindow vs. QWidget in PyQt5 (and Qt in general, I guess). From what I've read, QMainWindow inherits from QWidget, so should be able to do everything QWidget can and more. But when I try to convert an example I've found from QWidget into QMainWindow, the layout gets screwed up.

The example I'm trying to work off is from https://www.tutorialspoint.com/pyqt/pyqt_qstackedwidget.htm. (My GUI will have a StackedWidget as central widget, with a sidepanel for navigation, so getting this example to work in a QMainWidget would be a great basis for my own code.)

PyQT5-converted and slightly shortened version:

#!/usr/bin/env python3
import sys
from PyQt5.QtWidgets import (QApplication, QFormLayout, QLabel, QRadioButton, QCheckBox,
                             QListWidget, QStackedWidget, QLineEdit,
                             QHBoxLayout, QGridLayout
                             )
from PyQt5.Qt import QWidget, QMainWindow

class StackedExample(QMainWindow):
    def __init__(self):
        super(stackedExample, self).__init__()
        self.leftlist = QListWidget ()
        self.leftlist.insertItem (0, 'Contact' )
        self.leftlist.insertItem (1, 'Personal' )

        self.stack1 = QWidget()
        self.stack2 = QWidget()

        self.stack1UI()
        self.stack2UI()

        self.Stack = QStackedWidget (self)
        self.Stack.addWidget (self.stack1)
        self.Stack.addWidget (self.stack2)
        grid = QGridLayout()
        self.setLayout(grid)
        grid.addWidget(self.leftlist,0,0)
        grid.addWidget(self.Stack,0,1)

        self.leftlist.currentRowChanged.connect(self.display)
        self.resize(300,100)
        self.show()

    def stack1UI(self):
        layout = QFormLayout()
        layout.addRow("Name",QLineEdit())
        layout.addRow("Address",QLineEdit())
        self.stack1.setLayout(layout)

    def stack2UI(self):
        layout = QFormLayout()
        sex = QHBoxLayout()
        sex.addWidget(QRadioButton("Male"))
        sex.addWidget(QRadioButton("Female"))
        layout.addRow(QLabel("Sex"),sex)
        layout.addRow("Date of Birth",QLineEdit())

        self.stack2.setLayout(layout)

    def display(self,i):
        self.Stack.setCurrentIndex(i)

def main():
    app = QApplication(sys.argv)
    ex = StackedExample()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

This code worked fine while it was based on QWidget, but when it's based on QMainWidget (like in the above version), everything gets crammed into the upper left corner.

What changes are neccessary to show a layout that works for QWidget in a QMainWindow?

CodingCat
  • 4,999
  • 10
  • 37
  • 59

1 Answers1

8

A QMainWindow must have a central widget to display correctly. You need to define a central widget and then add any layouts to it instead of the main window.

class StackedExample(QMainWindow):

def __init__(self):
    QMainWindow.__init__(self)
    self.leftlist = QListWidget()
    self.leftlist.insertItem(0, 'Contact' )
    self.leftlist.insertItem(1, 'Personal' )

    self.central_widget = QWidget()               # define central widget
    self.setCentralWidget(self.central_widget)    # set QMainWindow.centralWidget

    self.stack1 = QWidget()
    self.stack2 = QWidget()

    self.stack1UI()
    self.stack2UI()

    self.Stack = QStackedWidget (self)
    self.Stack.addWidget (self.stack1)
    self.Stack.addWidget (self.stack2)
    grid = QGridLayout()
    self.centralWidget().setLayout(grid)          # add the layout to the central widget
    grid.addWidget(self.leftlist,0,0)
    grid.addWidget(self.Stack,0,1)

    self.leftlist.currentRowChanged.connect(self.display)
    self.resize(300,100)
    self.show()

There are also other areas besides centralWidget defined for a QMainWindow. Here is the documentation for QMainWindow. It explains this in more detail.

MalloyDelacroix
  • 2,193
  • 1
  • 13
  • 17