Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Can't get QLabel, QComboBox, and QSpinBox to align in form layout



  • In Qt Creator 4.13.3:

    I'd like to group a QComboBox and QSpinBox in a Widget Container, and make that the "Field" corresponding to a QLabel in a Form Layout. However, I can't get the 3 widgets to line up. If I set the Widget Container to a Form Layout, the ComboBox is above the SpinBox (top image in attachment). If I set the Widget Container to a Horizontal or Grid Layout, the ComboBox and Spinbox are aligned, but they're below the Label (even setting the layoutTopMargin of the Widget Container to 0) (bottom image in attachment). What's going on here?

    Screen Shot 2020-12-29 at 1.45.22 PM.png


  • Lifetime Qt Champion

    Hi and welcome to the forums.
    What platform is this?
    ComboBox seems to have some sort of extra space around it.



  • I'm developing on a Mac. Given your follow-up, I just booted up my Ubuntu desktop and tried it out on there, and it seems to work just fine. So this is some kind of Mac problem?



  • Looks like it is. Per https://stackoverflow.com/questions/41452512/how-to-remove-margins-of-qlayout-completely-mac-os-specific, setting the Qt::WA_LayoutUsesWidgetRect attribute on the ComboBox widget should solve this. Now I just need to figure out how to do that in Designer or in PySide2...



  • Well, it doesn't look like this can be done in Designer. I tried doing this in my Python script, but it doesn't seem to have any effect. Minimal working example below.

    main.py:

    import sys
    import os
    
    from PySide2.QtWidgets import QApplication, QMainWindow
    from PySide2.QtCore import Qt
    
    from Ui_MainWindow import Ui_MainWindow
    
    
    class MainWindow(QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            self.ui = Ui_MainWindow()
            self.ui.setupUi(self)
    
            self.ui.comboBox.setAttribute(Qt.WA_LayoutUsesWidgetRect)
            self.ui.comboBox_2.setAttribute(Qt.WA_LayoutUsesWidgetRect)
    
    if __name__ == "__main__":
        app = QApplication([])
        widget = MainWindow()
        widget.show()
        sys.exit(app.exec_())
    

    Ui_MainWindow.py:
    (I didn't touch this file; I just generated it via pyside2-uic form.ui -o Ui_MainWindow.py):

    from PySide2.QtCore import *
    from PySide2.QtGui import *
    from PySide2.QtWidgets import *
    
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            if not MainWindow.objectName():
                MainWindow.setObjectName(u"MainWindow")
            MainWindow.resize(800, 600)
            self.centralwidget = QWidget(MainWindow)
            self.centralwidget.setObjectName(u"centralwidget")
            self.widget = QWidget(self.centralwidget)
            self.widget.setObjectName(u"widget")
            self.widget.setGeometry(QRect(240, 100, 279, 52))
            self.formLayout_2 = QFormLayout(self.widget)
            self.formLayout_2.setObjectName(u"formLayout_2")
            self.formLayout_2.setContentsMargins(0, 0, 0, 0)
            self.radioButton = QRadioButton(self.widget)
            self.radioButton.setObjectName(u"radioButton")
    
            self.formLayout_2.setWidget(0, QFormLayout.LabelRole, self.radioButton)
    
            self.widget_1 = QWidget(self.widget)
            self.widget_1.setObjectName(u"widget_1")
            self.formLayout = QFormLayout(self.widget_1)
            self.formLayout.setObjectName(u"formLayout")
            self.formLayout.setContentsMargins(-1, 0, -1, -1)
            self.doubleSpinBox = QDoubleSpinBox(self.widget_1)
            self.doubleSpinBox.setObjectName(u"doubleSpinBox")
    
            self.formLayout.setWidget(0, QFormLayout.LabelRole, self.doubleSpinBox)
    
            self.comboBox = QComboBox(self.widget_1)
            self.comboBox.setObjectName(u"comboBox")
    
            self.formLayout.setWidget(0, QFormLayout.FieldRole, self.comboBox)
    
    
            self.formLayout_2.setWidget(0, QFormLayout.FieldRole, self.widget_1)
    
            self.widget1 = QWidget(self.centralwidget)
            self.widget1.setObjectName(u"widget1")
            self.widget1.setGeometry(QRect(260, 240, 281, 52))
            self.formLayout_3 = QFormLayout(self.widget1)
            self.formLayout_3.setObjectName(u"formLayout_3")
            self.formLayout_3.setContentsMargins(0, 0, 0, 0)
            self.radioButton_2 = QRadioButton(self.widget1)
            self.radioButton_2.setObjectName(u"radioButton_2")
    
            self.formLayout_3.setWidget(0, QFormLayout.LabelRole, self.radioButton_2)
    
            self.widget_2 = QWidget(self.widget1)
            self.widget_2.setObjectName(u"widget_2")
            self.horizontalLayout = QHBoxLayout(self.widget_2)
            self.horizontalLayout.setObjectName(u"horizontalLayout")
            self.horizontalLayout.setContentsMargins(-1, 0, -1, -1)
            self.doubleSpinBox_2 = QDoubleSpinBox(self.widget_2)
            self.doubleSpinBox_2.setObjectName(u"doubleSpinBox_2")
    
            self.horizontalLayout.addWidget(self.doubleSpinBox_2)
    
            self.comboBox_2 = QComboBox(self.widget_2)
            self.comboBox_2.setObjectName(u"comboBox_2")
    
            self.horizontalLayout.addWidget(self.comboBox_2)
    
    
            self.formLayout_3.setWidget(0, QFormLayout.FieldRole, self.widget_2)
    
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QMenuBar(MainWindow)
            self.menubar.setObjectName(u"menubar")
            self.menubar.setGeometry(QRect(0, 0, 800, 22))
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QStatusBar(MainWindow)
            self.statusbar.setObjectName(u"statusbar")
            MainWindow.setStatusBar(self.statusbar)
    
            self.retranslateUi(MainWindow)
    
            QMetaObject.connectSlotsByName(MainWindow)
        # setupUi
    
        def retranslateUi(self, MainWindow):
            MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
            self.radioButton.setText(QCoreApplication.translate("MainWindow", u"RadioButton", None))
            self.radioButton_2.setText(QCoreApplication.translate("MainWindow", u"RadioButton", None))
        # retranslateUi
    

    Running python main.py on my Mac generates:
    Screen Shot 2020-12-29 at 8.35.30 PM.png

    Running those exact same files on my Ubuntu Box makes it look fine, even if I remove the setAttribute(Qt.WA_LayoutUsesWidgetRect) lines.

    Any idea how I can get this to work on my Mac?


  • Lifetime Qt Champion

    Use a grid layout.



  • There are 2 things you might mean by that:

    If you mean to use a GridLayout for the Widget Container holding the ComboBox and SpinBox (as opposed to a FormLayout or HorizontalLayout), that gives the same result as using the HorizontalLayout, so that doesn't fix things.

    If you mean to get rid of the Widget Container, and to use a GridLayout for all 3 objects (the Label, the ComboBox, and the SpinBox), this does result in them being aligned properly. However, my actual UI is a form, and this group of 3 items is one of several items I want to be part of a larger FormLayout. I could work around this by making the entire form using a GridLayout instead of a FormLayout, but then I would lose out on the advantages of a FormLayout that are specified here: https://doc.qt.io/qt-5/qformlayout.html#details. E.g., I wouldn't get the "Adherence to the different platform's look and feel guidelines."

    If there's no other way out, I can do that, but I'd like to keep the FormLayout if possible.


  • Lifetime Qt Champion

    If it's not properly aligned in QGridLayout I would consider it as a bug - please provide a minimal (c++) example and open a bug report at bugreports.qt.io/



  • Bug report generated (https://bugreports.qt.io/browse/QTBUG-89741).

    The minimal C++ example would just be:

    project.pro:

    QT       += core gui
    
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    
    CONFIG += c++11
    
    # You can make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
        main.cpp \
        mainwindow.cpp
    
    HEADERS += \
        mainwindow.h
    
    FORMS += \
        mainwindow.ui
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    

    mainwindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    private:
        Ui::MainWindow *ui;
    };
    #endif // MAINWINDOW_H
    

    main.cpp:

    #include "mainwindow.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        w.show();
        return a.exec();
    }
    

    mainwindow.cpp:

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        ui->comboBox->setAttribute(Qt::WA_LayoutUsesWidgetRect);
        ui->comboBox_2->setAttribute(Qt::WA_LayoutUsesWidgetRect);
        ui->comboBox_3->setAttribute(Qt::WA_LayoutUsesWidgetRect);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    mainwindow.ui:

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>800</width>
        <height>600</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralwidget">
       <widget class="QWidget" name="">
        <property name="geometry">
         <rect>
          <x>170</x>
          <y>160</y>
          <width>261</width>
          <height>52</height>
         </rect>
        </property>
        <layout class="QFormLayout" name="formLayout_2">
         <item row="0" column="0">
          <widget class="QRadioButton" name="radioButton">
           <property name="text">
            <string>RadioButton</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QWidget" name="widget" native="true">
           <layout class="QFormLayout" name="formLayout">
            <property name="topMargin">
             <number>0</number>
            </property>
            <item row="0" column="0">
             <widget class="QSpinBox" name="spinBox"/>
            </item>
            <item row="0" column="1">
             <widget class="QComboBox" name="comboBox"/>
            </item>
           </layout>
          </widget>
         </item>
        </layout>
       </widget>
       <widget class="QWidget" name="">
        <property name="geometry">
         <rect>
          <x>160</x>
          <y>240</y>
          <width>263</width>
          <height>52</height>
         </rect>
        </property>
        <layout class="QFormLayout" name="formLayout_3">
         <item row="0" column="0">
          <widget class="QRadioButton" name="radioButton_2">
           <property name="text">
            <string>RadioButton</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QWidget" name="widget_2" native="true">
           <layout class="QHBoxLayout" name="horizontalLayout">
            <property name="topMargin">
             <number>0</number>
            </property>
            <item>
             <widget class="QSpinBox" name="spinBox_2"/>
            </item>
            <item>
             <widget class="QComboBox" name="comboBox_2"/>
            </item>
           </layout>
          </widget>
         </item>
        </layout>
       </widget>
       <widget class="QWidget" name="">
        <property name="geometry">
         <rect>
          <x>160</x>
          <y>310</y>
          <width>263</width>
          <height>52</height>
         </rect>
        </property>
        <layout class="QFormLayout" name="formLayout_4">
         <item row="0" column="0">
          <widget class="QRadioButton" name="radioButton_3">
           <property name="text">
            <string>RadioButton</string>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QWidget" name="widget_3" native="true">
           <layout class="QGridLayout" name="gridLayout">
            <property name="topMargin">
             <number>0</number>
            </property>
            <item row="0" column="0">
             <widget class="QSpinBox" name="spinBox_3"/>
            </item>
            <item row="0" column="1">
             <widget class="QComboBox" name="comboBox_3"/>
            </item>
           </layout>
          </widget>
         </item>
        </layout>
       </widget>
      </widget>
      <widget class="QMenuBar" name="menubar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>800</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
      <widget class="QStatusBar" name="statusbar"/>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

  • Lifetime Qt Champion

    Thx, can you please attach the c++ testcase to the bug report?



  • Sorry, I'm afraid I don't know what that means...


  • Lifetime Qt Champion

    You should create a zip file containing your source and append it to the bug report.



  • Done. Thanks.


Log in to reply