问题
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.
main.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>
Screenshot of test.ui
in Qt Designer 5.9:
Screenshot of main.py
loading test.ui
:
What's the reason for this behavior?
回答1:
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)
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.
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.*
So there are several solutions:
Remove:
if self.stack.topIsLayoutWidget(): if left < 0: left = 0 if top < 0: top = 0 if right < 0: right = 0 if bottom < 0: bottom = 0
Use
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.
来源:https://stackoverflow.com/questions/53469563/size-of-verticallayout-is-different-in-qt-designer-and-pyqt-program