Qt Designer 和 PyQt 程序中垂直布局的大小不同 [英] Size of verticalLayout is different in Qt Designer and PyQt program

查看:224
本文介绍了Qt Designer 和 PyQt 程序中垂直布局的大小不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Qt Designer 5.9中,test.ui中的verticalLayout与窗口边缘有一定的距离,但是在加载test.ui 在 main.py 中使用 PyQt 5.11.3,verticalLayout 扩展到窗口的边缘.

In Qt Designer 5.9 the verticalLayout in test.ui had a certain distance to the edge of the window, but after loading test.ui with PyQt 5.11.3 in main.py the verticalLayout extend to the edge of the window.

ma​​in.py:

    #!/usr/bin/python3
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.uic import loadUi

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__()
        loadUi("test.ui", self)

def main():
    app = QApplication(sys.argv)
    main_window = MainWindow(app)
    main_window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
main()

test.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>350</width>
    <height>257</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Test</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout_2">
    <item row="0" column="0">
     <layout class="QVBoxLayout" name="verticalLayout">
      <property name="leftMargin">
       <number>0</number>
      </property>
      <property name="topMargin">
       <number>0</number>
      </property>
      <item>
       <spacer name="verticalSpacer_2">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox">
        <layout class="QGridLayout" name="gridLayout">
         <item row="1" column="1">
          <widget class="QSpinBox" name="spinBox">
           <property name="maximum">
            <number>100000</number>
           </property>
           <property name="value">
            <number>1000</number>
           </property>
          </widget>
         </item>
         <item row="1" column="0">
          <widget class="QLabel" name="label_2">
           <property name="text">
            <string>Test</string>
           </property>
           <property name="alignment">
            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
           </property>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QComboBox" name="comboBox">
           <property name="currentText">
            <string/>
           </property>
          </widget>
         </item>
         <item row="0" column="0">
          <widget class="QLabel" name="label1">
           <property name="text">
            <string>Test</string>
           </property>
           <property name="alignment">
            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
           </property>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <spacer name="verticalSpacer">
        <property name="orientation">
         <enum>Qt::Vertical</enum>
        </property>
        <property name="sizeHint" stdset="0">
         <size>
          <width>20</width>
          <height>40</height>
         </size>
        </property>
       </spacer>
      </item>
      <item>
       <widget class="QPushButton" name="pushButton">
        <property name="layoutDirection">
         <enum>Qt::LeftToRight</enum>
        </property>
        <property name="text">
         <string>Test</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>350</width>
     <height>28</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

<小时>

Qt Designer 5.9 中 test.ui 的屏幕截图:

main.py 加载 test.ui 的截图:

这种行为的原因是什么?

What's the reason for this behavior?

推荐答案

如果你查看uic.loadUi()的代码,你会发现如下代码:

If you check the code of uic.loadUi() you will find the following code:

uiparser.py

class UIParser(object):  
    # ...
    def createLayout(self, elem):
        # ...
        margin = -1 if self.stack.topIsLayout() else self.defaults['margin']
        margin = self.wprops.getProperty(elem, 'margin', margin)
        left = self.wprops.getProperty(elem, 'leftMargin', margin)
        top = self.wprops.getProperty(elem, 'topMargin', margin)
        right = self.wprops.getProperty(elem, 'rightMargin', margin)
        bottom = self.wprops.getProperty(elem, 'bottomMargin', margin)
        # A layout widget should, by default, have no margins.
        if self.stack.topIsLayoutWidget():
            if left < 0: left = 0
            if top < 0: top = 0
            if right < 0: right = 0
            if bottom < 0: bottom = 0

    def topIsLayoutWidget(self):
        # A plain QWidget is a layout widget unless it's parent is a
        # QMainWindow or a container widget.  Note that the corresponding uic
        # test is a little more complicated as it involves features not
        # supported by pyuic.

        if type(self[-1]) is not QtWidgets.QWidget:
            return False

        if len(self) < 2:
            return False

        parent = self[-2]

        return isinstance(parent, QtWidgets.QWidget) and type(parent) not in (
                QtWidgets.QMainWindow,
                QtWidgets.QStackedWidget,
                QtWidgets.QToolBox,
                QtWidgets.QTabWidget,
                QtWidgets.QScrollArea,
                QtWidgets.QMdiArea,
                QtWidgets.QWizard,
                QtWidgets.QDockWidget)

问题是由 topIsLayoutWidget() 函数引起的,因为父级将引用用作基础的小部件,在这种情况下 MainWindow 符合 isinstance(parent, QtWidgets.QWidget) 和类型 (parent) 不在 (QtWidgets.QMainWindow, ...) 所以 topIsLayoutWidget() 将返回 True,所以左、上、右、下为 -1由于这些属性不存在将被更新为 0,因此应用到 contentsMargins 将通过消除默认值 (9, 9, 9, 9) 来建立,但在 Qt Designer 的情况下,contentsMargins 尚未更新,保持其默认值.

The problem is caused by the topIsLayoutWidget() function since the parent will refer to the widget that is used as a base, in this case MainWindow complies with isinstance(parent, QtWidgets.QWidget) and type (parent) not in (QtWidgets.QMainWindow, ...) so topIsLayoutWidget() will return True, so to be left, top, right, bottom be -1 since those properties do not exist will be updated to 0 so the apply to contentsMargins will be established by eliminating the default value (9, 9, 9, 9), but in the case of Qt Designer the contentsMargins have not been updated maintaining their default value.

所以结论是一个 pyqt 错误,也在评论中指出:

So in conclusion is a pyqt bug that also points in the comments:

# ... Note that the corresponding uic
# test is a little more complicated as it involves features not
# supported by pyuic.*

所以有几种解决方案:

  • 删除:

if self.stack.topIsLayoutWidget():
    if left < 0: left = 0
    if top < 0: top = 0
    if right < 0: right = 0
    if bottom < 0: bottom = 0

  • 使用uic.loadUiType():

    #!/usr/bin/python3
    import sys
    from PyQt5 import QtCore, QtWidgets, uic
    
    Ui_Interface, _ = uic.loadUiType('test.ui')
    
    class MainWindow(QtWidgets.QMainWindow, Ui_Interface):
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setupUi(self)
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        main_window = MainWindow()
        main_window.show()
        sys.exit(app.exec_())
    
    if __name__ == "__main__":
        main()
    

  • 我更喜欢第二种解决方案,因为不应修改源代码.

    I prefer the second solution since the source code should not be modified.

    这篇关于Qt Designer 和 PyQt 程序中垂直布局的大小不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆