Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PYQT - nesting widgets and layouts in multiple levels

Tags:

python

pyqt

pyqt5

I am new to pyqt and trying to create a set of nested containers which hold my controls. I could not find any examples that nest widgets(and keep them layouted). I was able to nest layouts only, but thats not what i want to achieve. One reason i want to do this, is to have controle over the backgroundcolor of my containers. Since layouts do not have a color, i think i need QWidgets or QFrames. This is how far i came:

class AssetCreationWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super(AssetCreationWindow, self).__init__()
        self.create_content()
        self.show()

    def create_content(self):

    # creating main container-frame, parent it to QWindow
        self.main_CF = QtWidgets.QFrame(self)
        self.main_CF.setStyleSheet('background-color: rgba(255, 0, 0, 1);')
        self.setCentralWidget(self.main_CF)
    # creating layout and parent it to main container
    # is it correct, that main_CL now manages children of main_CF ?
        self.main_CL = QtWidgets.QVBoxLayout(self.main_CF)

    # creating the first subcontainer + layout, parenting it
        asset_CGF = QtWidgets.QFrame(self.main_CF)
        asset_CGF.setStyleSheet('background-color: rgba(0, 255, 0, 1);')
        asset_CGL = QtWidgets.QHBoxLayout(asset_CGF)

    # creating label and lineEdit, both are supposed to be on top of asset_CGF    
        asset_label = QtWidgets.QLabel("Assetname: ", asset_CGF)
        asset_CGL.addWidget(asset_label)
        asset_name = QtWidgets.QLineEdit("MyNewAsset", asset_CGF)
        asset_CGL.addWidget(asset_name)

    # doing the same with a second container
        department_CGF = QtWidgets.QFrame(self.main_CF)
        department_CGF.setStyleSheet('background-color: rgba(0, 0, 255, 1);')
        department_CGL = QtWidgets.QHBoxLayout(department_CGF)

        department_label = QtWidgets.QLabel("Department: ", department_CGF)
        department_CGL.addWidget(department_label)

        department_names = QtWidgets.QComboBox(department_CGF)
        department_CGL.addWidget(department_names)

Unfortunatly this approach stacks all Widgets in the top right corner on top of each other. Another one was to remove the ParentWidget from all Layouts except main_CL and use addLayout().

def create_content(self):

    self.main_CF = QtWidgets.QFrame(self)
    self.setCentralWidget(self.main_CF)
    self.main_CL = QtWidgets.QVBoxLayout(self.main_CF)

    asset_CGF = QtWidgets.QFrame(self.main_CF)
    asset_CGF.setStyleSheet('background-color: rgba(255, 0, 0, 1);')
    asset_CGL = QtWidgets.QHBoxLayout()
    self.main_CL.addLayout(asset_CGL)

    asset_label = QtWidgets.QLabel("Asset Name: ", asset_CGF)
    asset_CGL.addWidget(asset_label)
    asset_name = QtWidgets.QLineEdit("MyNewAsset", asset_CGF)
    asset_CGL.addWidget(asset_name)

    department_CGF = QtWidgets.QFrame(self.main_CF)
    department_CGF.setStyleSheet('background-color: rgba(0, 255, 0, 1);')
    department_CGL = QtWidgets.QHBoxLayout()
    self.main_CL.addLayout(department_CGL)

    department_label = QtWidgets.QLabel("Department: ", department_CGF)
    department_CGL.addWidget(department_label)
    department_names = QtWidgets.QComboBox(department_CGF)
    department_CGL.addWidget(department_names)

This looks better in general but the subcontainer layouts seem to no know about the subcontainers. Even though the controlers are parented to the subcontainers, the controlers are not ontop of the subcontainers. The subcontainers are again stacked at the top right corner. I am at my wit's end.

like image 499
Florian Graf Avatar asked Sep 21 '17 19:09

Florian Graf


2 Answers

Including Aleš Erjavecs answer, this is the working codeexample:

class AssetCreationWindow(QtWidgets.QMainWindow):

def __init__(self, controller):
    super(AssetCreationWindow, self).__init__()
    self.controller = controller
    self.create_content()
    self.show()

def create_content(self):

# creating main container-frame, parent it to QWindow
    self.main_CF = QtWidgets.QFrame(self)
    self.main_CF.setStyleSheet('background-color: rgba(150, 0, 0, 1);')
    self.setCentralWidget(self.main_CF)
# creating layout and parent it to main container
# is it correct, that main_CL now manages children of main_CF ?
    self.main_CL = QtWidgets.QVBoxLayout(self.main_CF)


# creating the first subcontainer + layout, parenting it
    asset_CGF = QtWidgets.QFrame(self.main_CF)
    self.main_CL.addWidget(asset_CGF)
    asset_CGF.setStyleSheet('background-color: rgba(0, 150, 0, 1);')
    asset_CGL = QtWidgets.QHBoxLayout(asset_CGF)

# creating label and lineEdit, both are supposed to be on top of asset_CGF    
    asset_label = QtWidgets.QLabel("Assetname: ", asset_CGF)
    asset_CGL.addWidget(asset_label)
    asset_name = QtWidgets.QLineEdit("MyNewAsset", asset_CGF)
    asset_CGL.addWidget(asset_name)

# doing the same with a second container
    department_CGF = QtWidgets.QFrame(self.main_CF)
    self.main_CL.addWidget(department_CGF)
    department_CGF.setStyleSheet('background-color: rgba(0, 0, 150, 1);')
    department_CGL = QtWidgets.QHBoxLayout(department_CGF)

    department_label = QtWidgets.QLabel("Department: ", department_CGF)
    department_CGL.addWidget(department_label)

    department_names = QtWidgets.QComboBox(department_CGF)
    department_CGL.addWidget(department_names)

It results in this: window with nested QWidgets

like image 28
Florian Graf Avatar answered Oct 30 '22 08:10

Florian Graf


You have to set the layout to the widget. E.g

self.main_CL = QtWidgets.QVBoxLayout()
self.main_CF.setLayout(self.main_CL)

Then add the subwidgets into the layout explicitly. E.g.

self.main_CL.addWidget(self.asset_CGF)

Follow the same pattern for sub components.

self.asset_CGF.setLayout(self.asset_CGL)
self.asset_CGL.addWidget(...)

Actually your first example is only missing two calls

self.main_CL.addWidget(self.asset_CGF)
self.main_CL.addWidget(department_CGF)
like image 178
Aleš Erjavec Avatar answered Oct 30 '22 08:10

Aleš Erjavec