Search code examples
pythonpyside2

How to align 2 QVBoxLayout in QHBoxLayout with 50% area each and how to align combo_test11 and txt_test22 so that they look proper in line


As you can see from the image 2 QVBoxLayout looks bad so how can we design it so that both takes 50% of the QHBoxLayout size each.

As you can see combo_test11(QComboBox) and txt_test22(QLineEdit) both does not look aligned properly. both widget should be equally stacked/aligned so how can we design it .

I cannot add any fixed width since I need the whole box and the widgets to be responsive so any fixedwidth solution is not acceptable

Below is my implementation :

from PySide2.QtCore import Qt
from PySide2 import QtWidgets, QtCore, QtGui
from PySide2.QtGui import QStandardItemModel
from PySide2.QtWidgets import QHBoxLayout, QVBoxLayout, QAbstractItemView, QDesktopWidget, QPushButton


class WizardTkFrame(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.init_window()

    def init_window(self):

        self.widget = QtWidgets.QWidget()
        self.scroll = QtWidgets.QScrollArea()

        v1_layout = QtWidgets.QVBoxLayout(self)
        v2_layout = QtWidgets.QVBoxLayout(self)

        self.label_test1 = QtWidgets.QLabel()
        self.label_test1.setText('Test1<font color=\"red\"> *</font>')
        self.combo_test1 = QtWidgets.QComboBox(self)
        v1_layout.addLayout(self.horiz_layout([self.label_test1, self.combo_test1]))

        self.label_test11 = QtWidgets.QLabel()
        self.label_test11.setText('Test1 value<font color=\"red\"> *</font>')
        self.combo_test11 = QtWidgets.QComboBox(self)
        v2_layout.addLayout(self.horiz_layout([self.label_test11, self.combo_test11]))

        self.label_test2 = QtWidgets.QLabel("Test2 By")
        self.combo_test2 = QtWidgets.QComboBox(self)
        v1_layout.addLayout(self.horiz_layout([self.label_test2, self.combo_test2]))

        self.label_test22 = QtWidgets.QLabel()
        self.label_test22.setText('Test2 Value<font color=\"red\"> *</font>')
        self.txt_test22 = QtWidgets.QLineEdit(self)
        v2_layout.addLayout(self.horiz_layout([self.label_test22, self.txt_test22]))

        layout = QtWidgets.QHBoxLayout(self)
        layout.addLayout(v1_layout)
        layout.addLayout(v2_layout)
        self.widget.setLayout(layout)

        self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.scroll.setWidgetResizable(True)
        self.scroll.setWidget(self.widget)
        self.setCentralWidget(self.scroll)

    def horiz_layout(self, controls: list, type="widget"):
        temp_obj = QHBoxLayout()
        for x in controls:
            if type == "widget":
                temp_obj.addWidget(x)
            elif type == "layout":
                temp_obj.addLayout(x)
        return temp_obj


def center(widget):
    qRect = widget.frameGeometry()
    centerPoint = QDesktopWidget().availableGeometry().center()
    qRect.moveCenter(centerPoint)
    widget.move(qRect.topLeft())


if __name__ == "__main__":
    app = QtWidgets.QApplication([])
    widget = WizardTkFrame()
    widget.setGeometry(200, 100, 600, 500)
    widget.setWindowTitle("Test")
    center(widget)
    widget.show()
    app.exec_()

enter image description here


Solution

  • Whether you do it in Designer (recommended) or in code, you'll probably want to play with the stretch parameters. To make this particular form look good, a 1:2 ratio of label:control isn't bad.

    Also, you probably want the label text to be right aligned. You can do this in HTML markup or in the alignment property.

    I modified your horiz_layout function to have stretch:

    def horiz_layout(self, controls: list, type="widget"):
        temp_obj = QHBoxLayout()
        for x in controls:
            if type == "widget":
                temp_obj.addWidget(x)
            elif type == "layout":
                temp_obj.addLayout(x)
        temp_obj.setStretch(0,1)  # 0th col stretch is 1
        temp_obj.setStretch(1,2)  # 1th col stretch is 2
        return temp_obj
    

    and I ecapsulated all of your label texts with <div align=right> and </div>. This is what I got:

    enter image description here