Question

I'm creating a new QWidget in Qt Designer, with a frame which contains a QLabel and a QTextEdit. I can set the geometry of all these elements, and set them to be fixed so that their height/width never change:

enter image description here

In this example, my QLabel and QLineEdit are in the top right-hand corner of their parent frame. If I now set a layout to the frame (which I need to do to ensure elements remain in their correct place when resizing windows, or if the frame is the main widget of a QScrollArea), then the elements are moved, even within the reference of the frame:

enter image description here

In this instance, a Form Layout was applied to the frame; we can see the (X,Y) coords of the QLabel have changed from (0,0) to (10,10). This happens whether I wrap the two elements in a vertical frame beforehand or not.

Given I'm trying to create a very precise layout by manually setting the element coords, to have them move a seemingly random amount when applying a layout is hugely frustrating. What should I be doing?! I assume I've misunderstood something, but I don't know what!

Was it helpful?

Solution

Layouts have a default margin and spacing, the precise values of which are provided by the current widget style.

You can override the defaults by clicking on the parent widget of the layout, and scrolling down to the bottom of the Property Editor, where you'll see a Layout section with the relevant values (-1 means "use the default").

EDIT:

One thing I didn't make clear was that the layout margins and spacing will go back to their defaults every time you break and reset the layout! This can be very annoying at times, but does make sense, because a new layout is created every time you do this.

Anyway, I think the real source of the problem is actually that you are using a Form Layout, which can be much less flexible than the other layouts. What I think you should do is put the label and line-edit in an Horizontal Layout with a Horizontal Spacer at the end. Then put a Vertical Spacer below the Horizontal Layout, and add a Vertical Layout to the Frame. This arrangement will keep the label and line-edit in the top-left corner of the Frame. With that in place, you can finally set the Vertical Layout margins to zero to get the desired result.

Here is a .ui file you can test to see how it all goes together:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>316</width>
    <height>150</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QFrame" name="frame">
     <property name="frameShape">
      <enum>QFrame::StyledPanel</enum>
     </property>
     <property name="frameShadow">
      <enum>QFrame::Raised</enum>
     </property>
     <layout class="QVBoxLayout" name="verticalLayout">
      <property name="spacing">
       <number>0</number>
      </property>
      <property name="margin">
       <number>0</number>
      </property>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout">
        <property name="spacing">
         <number>0</number>
        </property>
        <item>
         <widget class="QLabel" name="label">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="minimumSize">
           <size>
            <width>75</width>
            <height>0</height>
           </size>
          </property>
          <property name="text">
           <string>TextLabel</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="lineEdit">
          <property name="sizePolicy">
           <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="minimumSize">
           <size>
            <width>100</width>
            <height>0</height>
           </size>
          </property>
         </widget>
        </item>
        <item>
         <spacer name="horizontalSpacer">
          <property name="orientation">
           <enum>Qt::Horizontal</enum>
          </property>
          <property name="sizeHint" stdset="0">
           <size>
            <width>40</width>
            <height>20</height>
           </size>
          </property>
         </spacer>
        </item>
       </layout>
      </item>
      <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>106</height>
         </size>
        </property>
       </spacer>
      </item>
     </layout>
    </widget>
   </item>
  </layout>
 </widget>
 <resources/>
 <connections/>
</ui>

OTHER TIPS

The key elements that influence positioning and size that you need to pay attention to are:

  1. the layout of your base form
  2. layouts within your form
  3. widget sizepolicy and widget min and max size values

All of the elements work in conjunction in a cascading fashion. It usually takes a lot a trials and CTRL+R to evaluate the appearance and resize nature of the form, but it is usually these 3 things.

The point of layouts is that they control the size and position of the elements in them. This is how they work. If they weren't in control of the widget geometry, what would they do when resized?

Instead of trying to rigidly control the size and position of everything, use layouts to convey design intent: These two controls belong together, these identical items should be in a column, and so on.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top