Please nominate your Qt Champions for 2021! https://forum.qt.io/topic/132134/looking-for-the-2021-qt-champions

Problem with QtFormLayout



  • Hello, guys!

    I'm new to PyQt5 and I have a basic question that I couldn't solve. I use pyqt designer to organize the layout and widgets.

    Im trying to make a form like this (a space between the Label and the LineEdit):
    1.PNG
    But evey time I remove the first line it stays like this:
    2.PNG
    I don't why this is happening. The first row ("TextLabel") I made using the designer and only changed the MaximumWidth and MinimumWidth for the label text and the LineEdit.

    I did the same thing in the code. I only modified the MaximumWidth and MinimumWidth for each component in the row.

    Here is my code:

        def main():
            variable_names=["test1","test2"]
            self.create_form(variable_names)
            self.clear_layout(self.formLayout_output)
            self.create_form(variable_names)
    
        def create_form(self, variable_names: list):
            self.lineEdit_out_objs = [QLineEdit() for i in range( (len(variable_names) ) )]
            self.label_out_objs = [QLineEdit() for i in range( (len(variable_names) ) )]
            print(self.label_outTemplate.minimumWidth())
    
            for i in range(len(variable_names)):
                self.formLayout_output.addRow(variable_names[i], self.lineEdit_out_objs[i])
    
                #config Labels proprieties here:
                self.label_out_objs[i].setMinimumWidth(self.label_outTemplate.minimumWidth())
                self.label_out_objs[i].setMaximumWidth(self.label_outTemplate.maximumWidth())
    
                #config LineEdit proprieties here:
                self.lineEdit_out_objs[i].setMinimumWidth(self.lineEdit_outTemplate.minimumWidth())
                self.lineEdit_out_objs[i].setMaximumWidth(self.lineEdit_outTemplate.maximumWidth())
        
        def clear_layout(self, layout):
                for i in reversed(range(layout.count())): 
                    widgetToRemove = layout.itemAt(i).widget()
                    # remove it from the layout list
                    layout.removeWidget(widgetToRemove)
                    # remove it from the gui
                    widgetToRemove.setParent(None)
    

    And here is the layout configuration in Qt Desginer:
    3.PNG
    Ps: Im using Python 3.8.2 and PyQt5 5.13.2

    Thanks for your attention!


  • Lifetime Qt Champion

    Hi,

    You should be able to get what you want using both formAlignment and labelAlignment.



  • Thanks SGaist for you answer but I already tryed adding these two lines of code:

    self.formLayout_output.setFormAlignment(QtCore.Qt.AlignRight)
    self.formLayout_output.setLabelAlignment(QtCore.Qt.AlignLeft)
    

    And it took no effect. So now it looks like this:

        def main():
            variable_names=["test1","test2"]
            self.create_form(variable_names)
            self.clear_layout(self.formLayout_output)
            self.create_form(variable_names)
    
        def create_form(self, variable_names: list):
            self.lineEdit_out_objs = [QLineEdit() for i in range( (len(variable_names) ) )]
            self.label_out_objs = [QLineEdit() for i in range( (len(variable_names) ) )]
            print(self.label_outTemplate.minimumWidth())
    
            for i in range(len(variable_names)):
                self.formLayout_output.addRow(variable_names[i], self.lineEdit_out_objs[i])
    
                #config Labels proprieties here:
                self.label_out_objs[i].setMinimumWidth(self.label_outTemplate.minimumWidth())
                self.label_out_objs[i].setMaximumWidth(self.label_outTemplate.maximumWidth())
    
                #config LineEdit proprieties here:
                self.lineEdit_out_objs[i].setMinimumWidth(self.lineEdit_outTemplate.minimumWidth())
                self.lineEdit_out_objs[i].setMaximumWidth(self.lineEdit_outTemplate.maximumWidth())
    
        self.formLayout_output.setFormAlignment(QtCore.Qt.AlignRight)
        self.formLayout_output.setLabelAlignment(QtCore.Qt.AlignLeft)
        
        def clear_layout(self, layout):
                for i in reversed(range(layout.count())): 
                    widgetToRemove = layout.itemAt(i).widget()
                    # remove it from the layout list
                    layout.removeWidget(widgetToRemove)
                    # remove it from the gui
                    widgetToRemove.setParent(None)
    

  • Lifetime Qt Champion

    Then please provide a complete minimal example to allow testing.



  • @SGaist

    Here is a test code:

    import sys, os
    from PyQt5 import QtCore, QtGui, QtWidgets, uic
    from PyQt5.QtGui import QIcon, QDoubleValidator
    from PyQt5.QtWidgets import QPushButton, QFileDialog, QLabel, QMessageBox, QTextBrowser, QButtonGroup, QFormLayout, QLineEdit, QSizePolicy, QSpacerItem
    
    class MyWindow(QtWidgets.QMainWindow):
        def __init__(self):
            super(MyWindow,self).__init__()
            self.setFixedSize(800, 600)
            self.window_title="GALIA"
            self.unitCell_ui()
    
    #SCREEN
    
        def unitCell_ui (self):
            uic.loadUi('interface.ui',self)
            self.setWindowTitle(self.window_title)
    
            variable_names=["test1","test2"]
            
            self.create_form(variable_names)
            self.clear_layout(self.formLayout_output)
            self.create_form(variable_names)
    
    #FUNCTIONS
    
        def clear_layout(self, layout):
                for i in reversed(range(layout.count())): 
                    widgetToRemove = layout.itemAt(i).widget()
                    # remove it from the layout list
                    layout.removeWidget(widgetToRemove)
                    # remove it from the gui
                    widgetToRemove.setParent(None)
    
        def create_form(self, variable_names: list):
            self.lineEdit_out_objs = [QLineEdit() for i in range( (len(variable_names) ) )]
            self.label_out_objs = [QLineEdit() for i in range( (len(variable_names) ) )]
            print(self.label_outTemplate.minimumWidth())
    
            for i in range(len(variable_names)):
                self.formLayout_output.addRow(variable_names[i], self.lineEdit_out_objs[i])
                
                #config Labels proprieties here:
                self.label_out_objs[i].setMinimumWidth(self.label_outTemplate.minimumWidth())
                self.label_out_objs[i].setMaximumWidth(self.label_outTemplate.maximumWidth())
    
                self.label_out_objs[i].setFixedSize(QtCore.QSize(200, 25))
    
                #config LineEdit proprieties here:
                self.lineEdit_out_objs[i].setMinimumWidth(self.lineEdit_outTemplate.minimumWidth())
                self.lineEdit_out_objs[i].setMaximumWidth(self.lineEdit_outTemplate.maximumWidth())
        
            new_height = self.scrollArea_output.viewportSizeHint().height()
            self.scrollArea_output.resize(370,new_height+2)
    
    
    app = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    window.show()
    app.exec()
    

    and here is the code of the "interface.ui" file that I'm using made in QT Deseginer:

    <?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="sizePolicy">
       <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
        <horstretch>0</horstretch>
        <verstretch>0</verstretch>
       </sizepolicy>
      </property>
      <property name="font">
       <font>
        <stylestrategy>PreferDefault</stylestrategy>
       </font>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <property name="autoFillBackground">
       <bool>false</bool>
      </property>
      <widget class="QWidget" name="centralwidget">
       <widget class="QScrollArea" name="scrollArea">
        <property name="geometry">
         <rect>
          <x>0</x>
          <y>50</y>
          <width>801</width>
          <height>511</height>
         </rect>
        </property>
        <property name="font">
         <font>
          <pointsize>12</pointsize>
         </font>
        </property>
        <property name="widgetResizable">
         <bool>true</bool>
        </property>
        <widget class="QWidget" name="scrollAreaWidgetContents">
         <property name="geometry">
          <rect>
           <x>0</x>
           <y>0</y>
           <width>799</width>
           <height>509</height>
          </rect>
         </property>
         <widget class="QScrollArea" name="scrollArea_output">
          <property name="geometry">
           <rect>
            <x>200</x>
            <y>40</y>
            <width>370</width>
            <height>76</height>
           </rect>
          </property>
          <property name="sizePolicy">
           <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
            <horstretch>0</horstretch>
            <verstretch>0</verstretch>
           </sizepolicy>
          </property>
          <property name="widgetResizable">
           <bool>true</bool>
          </property>
          <widget class="QWidget" name="formLayout_area_out">
           <property name="geometry">
            <rect>
             <x>0</x>
             <y>0</y>
             <width>351</width>
             <height>74</height>
            </rect>
           </property>
           <property name="sizePolicy">
            <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
             <horstretch>0</horstretch>
             <verstretch>0</verstretch>
            </sizepolicy>
           </property>
           <layout class="QVBoxLayout" name="verticalLayout_out">
            <property name="topMargin">
             <number>9</number>
            </property>
            <item>
             <layout class="QFormLayout" name="formLayout_output">
              <property name="formAlignment">
               <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
              </property>
              <property name="horizontalSpacing">
               <number>6</number>
              </property>
              <property name="verticalSpacing">
               <number>6</number>
              </property>
              <property name="leftMargin">
               <number>0</number>
              </property>
              <property name="topMargin">
               <number>0</number>
              </property>
              <property name="rightMargin">
               <number>0</number>
              </property>
              <property name="bottomMargin">
               <number>0</number>
              </property>
              <item row="0" column="0">
               <widget class="QLabel" name="label_outTemplate">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>200</width>
                  <height>0</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>200</width>
                  <height>16777215</height>
                 </size>
                </property>
                <property name="autoFillBackground">
                 <bool>false</bool>
                </property>
                <property name="text">
                 <string>TextLabel:</string>
                </property>
               </widget>
              </item>
              <item row="0" column="1">
               <widget class="QLineEdit" name="lineEdit_outTemplate">
                <property name="sizePolicy">
                 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
                  <horstretch>0</horstretch>
                  <verstretch>0</verstretch>
                 </sizepolicy>
                </property>
                <property name="minimumSize">
                 <size>
                  <width>125</width>
                  <height>0</height>
                 </size>
                </property>
                <property name="maximumSize">
                 <size>
                  <width>125</width>
                  <height>16777215</height>
                 </size>
                </property>
                <property name="text">
                 <string/>
                </property>
               </widget>
              </item>
             </layout>
            </item>
           </layout>
          </widget>
         </widget>
        </widget>
       </widget>
      </widget>
      <widget class="QMenuBar" name="menubar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>800</width>
         <height>21</height>
        </rect>
       </property>
      </widget>
      <widget class="QStatusBar" name="statusbar"/>
     </widget>
     <resources/>
     <connections/>
    </ui>
    

  • Banned

    Okay first you really ought not to be using the Designer unless you plan to port your code to numerous languages other than Python -- that being said I first started by creating your initial design in a sort of dynamic fashion then realized that you wanted to be add and delete this objects which means it should use a QListTree or QListWidget instead of this way but I thought I would share this with you to perhaps help you get started down a more Python-Qt path by showing you how Python-Qt does this (aka without the designer). I will try to put up a QListView/QListWidget version of this up tomorrow.

    from PyQt5.QtWidgets import QApplication, QMainWindow, QHBoxLayout, QVBoxLayout
    from PyQt5.QtWidgets import QWidget, QLabel, QLineEdit, QPushButton
    
    class MyWidget(QWidget):
        def __init__(self, parent, Desc):
            self.CntrPane = parent
            QWidget.__init__(self)
            self.setContentsMargins(0, 0, 0, 0)
            
            self.lblDesc = QLabel(Desc)
            self.lneData = QLineEdit()
            self.lneData.setFixedWidth(125)
    
            HBox = QHBoxLayout()
            HBox.addWidget(self.lblDesc)
            HBox.addStretch(1)
            HBox.addWidget(self.lneData)
            
            self.setLayout(HBox)
    
    class CenterPanel(QWidget):
        def __init__(self, parent, AddLines):
            self.MainWin = parent
            QWidget.__init__(self)
    
            self.NxtIdx = 1
            self.ViewLines = {}
    
            self.ViewLines[self.NxtIdx] = MyWidget(self, 'Text Label:')
            self.NxtIdx += 1
    
            for Desc in AddLines:
                self.ViewLines[self.NxtIdx] = MyWidget(self, Desc)
                self.NxtIdx += 1
    
            VBox = QVBoxLayout()
            for Key in self.ViewLines.keys():
                LineObj = self.ViewLines[Key]
                VBox.addWidget(LineObj)
            VBox.addStretch(1)
            
            self.btnDoThis = QPushButton()
            self.btnDoThis.clicked.connect(self.DoThis)
            
            self.setLayout(VBox)
    
        def DoThis(self):
            print('This will do something')
    
    class MyWindow(QMainWindow):
        def __init__(self):
          # Note do not use super( ) in Python as it introduces 4 known issues that 
          # must be handled properly. Further there are still actual bugs within
          # the usage of super( ) when used in Python. Now while super( ) does work 
          # fine within C++ it does not work as seamlessly within Python due to the 
          # major differences between these 2 languages. Next the reason it was 
          # created was to handle a rather rare inheritance issue and unless you are 
          # doing some complicated inheritance you will most likely never run into 
          # this extremely rare issue, however the 4 major issues that get included 
          # by using super( ) are much more likely to occur than that rare issue its 
          # meant for to solve. Of course using the basic explicit method (as shown), 
          # does not cause these issues and is as just as simple as using `super( )` 
          # further you do not actually gain anything useful by using `super( )` in 
          # Python that could not be done in a much simpler and safer manner.
          # super(MyWindow,self).__init__()
            QMainWindow.__init__(self)
            self.setWindowTitle('Galia')
            WinLeft = 150; WinTop = 150; WinWidth = 500; WinHigh = 500
            self.setGeometry(WinLeft, WinTop, WinWidth, WinHigh)
            
            VariableLines = ['Test 1', 'Test 2']
    
          # QMainWindow contains a Central Widget, Menu/Tool Bar, Status Bar, and 
          # dockable window border this covers the Central Widget
            self.CenterPane = CenterPanel(self, VariableLines)
            self.setCentralWidget(self.CenterPane)
    
    # Python standard starter line
    if __name__ == "__main__":
      # If you are not going to handle Command Line arguements
      # do not receive them further if you do decide to support
      # Command Line arguements looking into using the argparser
      # library as it handles them more cleanly, intuitively and
      # efficiently. Note I also call this the Main Event Handler
      # because that is what it is so it helps to denote this
      #
      # app = QApplication(sys.argv)
      #
        MainEventHandler = QApplication([])
    
        MainApplication = MyWindow()
        MainApplication.show()
        
        MainEventHandler.exec()
    
      # If anyone wants more extensive free help I run an online lab-like classroom-like 
      # message server feel free and drop by you will not be able to post until I clear 
      # you as a student as this prevents spammers so if interested here is the invite
      # https://discord.gg/3D8huKC
    


  • @Denni-0 ,

    Thanks for the help! I will wait for the QListTree/QListWidget version


  • Banned

    Okay here be the above using a QListWidget as promised ;) I hope you find it useful -- I think it can be done also with a QListView but most feel that using the QListWidget is easier. Of course there are other ways to do this as well but this to me seemed like the simplest

    from PyQt5.QtCore    import Qt
    from PyQt5.QtGui     import QFont
    from PyQt5.QtWidgets import QApplication, QMainWindow, QHBoxLayout, QVBoxLayout
    from PyQt5.QtWidgets import QWidget, QListWidget, QLabel, QLineEdit, QPushButton, QListWidgetItem
    
    class MyWidget(QWidget):
        def __init__(self, parent, Desc):
            self.CntrPane = parent
            QWidget.__init__(self)
            self.setContentsMargins(0, 0, 0, 0)
            
            self.lblDesc = QLabel(Desc)
            self.lneData = QLineEdit()
            self.lneData.setFixedWidth(125)
    
            HBox = QHBoxLayout()
            HBox.addWidget(self.lblDesc)
          # Using Stretch here created odd unexplainable behavior
            HBox.addWidget(QLabel(' '))
            HBox.addWidget(self.lneData)
            
            self.setLayout(HBox)
    
    class CenterPanel(QWidget):
        def __init__(self, parent, AddLines):
            self.MainWin = parent
            QWidget.__init__(self)
    
            HdrFont = QFont()
            HdrFont.setPointSize(16)
            HdrFont.setBold(True)
          # Static Header Outside List Widget
            lblHeadr = QLabel('Text Label')
            lblHeadr.setFont(HdrFont)
    
          # The 2 Stretches Centers the Header Label
            HBox1 = QHBoxLayout()
            HBox1.addStretch(1)
            HBox1.addWidget(lblHeadr)
            HBox1.addStretch(1)
    
          # Create the List Widget
            self.lswWidgts = QListWidget()
    
            self.WdgtCnt = 0
          # This is in case you need to do something with the
          # contents of your Custom Widget you have an easy
          # Handle to each Widget
            self.WdgtList = {}
            for Desc in AddLines:
                self.WdgtCnt += 1
                self.WdgtList[self.WdgtCnt] = MyWidget(self, Desc)
    
              # Create an Item for the ListWidget
                lswItem = QListWidgetItem()
              # Set the Row to the Size of the Custom Widget
                lswItem.setSizeHint(self.WdgtList[self.WdgtCnt].minimumSizeHint())
    
              # Add the Item to the ListWidget
                self.lswWidgts.addItem(lswItem)
    
              # Pass Handle of the Custom Widget to the List Widget Item
                self.lswWidgts.setItemWidget(lswItem, self.WdgtList[self.WdgtCnt])
    
            self.btnDoThis = QPushButton('Do This')
            self.btnDoThis.clicked.connect(self.DoThis)
    
            HBox2 = QHBoxLayout()
            HBox2.addWidget(self.btnDoThis)
            HBox2.addStretch(1)
    
            VBox = QVBoxLayout()
            VBox.addLayout(HBox1)
            VBox.addWidget(self.lswWidgts)
            VBox.addLayout(HBox2)
            VBox.addStretch(1)
            
            self.setLayout(VBox)
    
        def DoThis(self):
            self.WdgtList[1].lneData.setText('Changing Things Up')
    
    class MyWindow(QMainWindow):
        def __init__(self):
          # Note do not use super( ) in Python as it introduces 4 known issues that 
          # must be handled properly. Further there are still actual bugs within
          # the usage of super( ) when used in Python. Now while super( ) does work 
          # fine within C++ it does not work as seamlessly within Python due to the 
          # major differences between these 2 languages. Next the reason it was 
          # created was to handle a rather rare inheritance issue and unless you are 
          # doing some complicated inheritance you will most likely never run into 
          # this extremely rare issue, however the 4 major issues that get included 
          # by using super( ) are much more likely to occur than that rare issue its 
          # meant for to solve. Of course using the basic explicit method (as shown), 
          # does not cause these issues and is as just as simple as using `super( )` 
          # further you do not actually gain anything useful by using `super( )` in 
          # Python that could not be done in a much simpler and safer manner.
          # super(MyWindow,self).__init__()
            QMainWindow.__init__(self)
            self.setWindowTitle('Galia')
            WinLeft = 250; WinTop = 250; WinWidth = 300; WinHigh = 250
            self.setGeometry(WinLeft, WinTop, WinWidth, WinHigh)
            
            VariableLines = ['Test 1', 'Test 2']
    
          # QMainWindow contains a Central Widget, Menu/Tool Bar, Status Bar, and 
          # dockable window border this covers the Central Widget
            self.CenterPane = CenterPanel(self, VariableLines)
            self.setCentralWidget(self.CenterPane)
    
    # Python standard starter line
    if __name__ == "__main__":
      # If you are not going to handle Command Line arguements
      # do not receive them further if you do decide to support
      # Command Line arguements looking into using the argparser
      # library as it handles them more cleanly, intuitively and
      # efficiently. Note I also call this the Main Event Handler
      # because that is what it is so it helps to denote this
      #
      # app = QApplication(sys.argv)
      #
        MainEventHandler = QApplication([])
    
        MainApplication = MyWindow()
        MainApplication.show()
        
        MainEventHandler.exec()
    
      # If anyone wants more extensive free help I run an online lab-like classroom-like 
      # message server feel free and drop by you will not be able to post until I clear 
      # you as a student as this prevents spammers so if interested here is the invite
      # https://discord.gg/3D8huKC
    

Log in to reply