QT Designer:在尊重 window 重新缩放 PyQT5 的同时移动和调整小部件
QT Designer: Moving & Resizing widgets while respecting window rescaling PyQT5
TLDR: QT Designer 不允许我在尊重 window 缩放比例的同时移动和调整小部件的大小。当将它从图像 1 拖动到图像 2 时,我想让最右边的按钮更靠近 window 的边缘,也就是保持比例。
我正在将 PyQT5 与 QT Designer 一起使用。我正在尝试手动组织(移动和调整)我的小部件,但我的两种方法(接下来解释)都失败了。
当我使用网格布局时,我可以通过拖动其边缘来更改 window 大小来缩放小部件(正如预期的那样......太棒了!)。但是当我使用布局时,我无法更改小部件的相对位置。使用布局时,我也无法拖动单个小部件的边缘以在 window 内调整它的大小(真可惜,这对于构建我的 UI 很重要)。
另一方面,当我不使用任何布局时,我可以自由移动和调整各个小部件的大小(耶!)。但是如果不使用布局,我的小部件将不再缩放以适应 window 大小。
我的问题是,如何在 QT Designer 中移动和调整小部件的大小?我认为我可以在 QT Designer 本身中做到这一点,而不是依赖于 PyQT5 的混乱,因为即使是微小的变化也会变得复杂,而不是 QT Designer 的拖放功能?
附件是一些屏幕截图,以图形方式显示我的意思。前两张照片显示了在没有布局的情况下发生的情况。我将 window 变大了,但我的小部件仍以相同大小留在同一位置。第三张截图显示了当我使用网格布局时会发生什么。我无法调整任何小部件的大小,也无法移动它们。
换句话说,是否有更有效的方法来使用 QT Designer 移动和调整大小来解决这两个问题?
我希望将最右边的按钮从图像 1 拖动到图像 2 时靠近 window 的边缘,也就是保持比例。
如果要实现比例则:
使用额外的 QWidgets(默认情况下是不可见的,但对于我的演示我会设置背景颜色)或 QSpacerItem,
使用满足条件的拉伸因子,并且
将所有小部件的 sizePolice 设置为忽略。
网格布局将使用该信息来重新缩放几何图形。
对于我的演示,window 的大小为 200x200,按钮的位置为 50x50,大小为 40x40。
对于左侧的小部件,您必须将水平拉伸因子设置为 40
对于右侧的中央,您必须将水平拉伸因子设置为 50,将水平拉伸因子设置为 50。
对于右侧的小部件,您必须将水平拉伸因子设置为 90(200 - 50 -40)
对于顶部的小部件,您必须将垂直拉伸系数设置为 50。
对于底部的小部件,您必须将垂直拉伸系数设置为 90(200 - 50 -40)。
<?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>593</width>
<height>439</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QWidget" name="top" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>50</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(85, 255, 127);</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QWidget" name="left" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>50</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 0, 0);</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>40</horstretch>
<verstretch>40</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QWidget" name="right" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>110</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 85, 255);</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="bottom" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>110</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(85, 255, 255);</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>593</width>
<height>28</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
虽然过度拥挤的 UI 通常不是一个好主意,但有很多空 space 很少会更好。布局管理器考虑了这个方面,并尝试通过使小部件尽可能多地使用 space 来 优化 可用 space(假设它们可以调整大小)。
也就是说,显然有很多情况下 window 和很多 space 是好的(例如,登录访问界面足够大以引起注意)。
重要的是要理解布局管理器,顾名思义,管理布局,它通过很多复杂的计算,基于安装它的小部件和所有其子项的所有大小hints/policies/constraints,递归地。如果您对某些小部件应该如何调整大小有一些要求,则必须指定它们。
每当要创建 任何 界面时,特别是如果正在考虑用户体验问题(这是他们应该考虑的)并且还有很多空的 space要按比例使用,至少有两个重要步骤:
- 准确理解在布局的“正常”条件下应如何放置小部件(位置、大小和比例);
- 考虑一下当调整容器大小时那些尺寸和位置应该改变;
第一点似乎很好解释,但即使创建一个使用布局考虑空白区域的基本界面也不是那么简单。
根据情况,网格布局可能就足够了,但在某些情况下,您可能需要使用 nested 布局。
在您的具体情况下,网格可能就足够了,但要确保保持适当的间距和比例,您需要使用 spacer items.
我已经为您的案例准备了一个基本的 UI 示例:比例可能不完全正确,但这只是一个开始。
这是它在正常尺寸下的样子:
这就是它变大后的样子:
如您所见,我添加了 spacers:靠近边缘的 each 边有一个,这是确保适当的“边界边距”所必需的保持不变,然后另外两个用于两个按钮之间的间距;由于网格变为 5x5,因此两个中心 spacers 的“单元格”位置可能在任何位置,只要垂直在中央行和水平在中央列即可。
现在小部件的比例和间距是通过以下方式实现的:
- 两个按钮都有
Preferred
尺寸政策(垂直和水平);这确保布局知道如果有足够的 space 可以让它们变大,但不会让它们占用 all 可用的 space;
- 左上按钮的大小策略 stretch 为 1(同样,垂直和水平),而右下按钮为 2;这样,他们的第二个按钮将始终 try 是第一个按钮宽度和高度的两倍;
- 布局(通过单击中央小部件可访问)还为第三列(中间的列)设置了 2 的列拉伸;考虑到上述情况,结果将是布局将尝试使中间的 space 与右下按钮一样宽;
请注意,当使用网格时,按钮的行或列拉伸可以(有时 应该)直接在布局上设置。
还要考虑到边缘的 spacers 是基本的 QSpacerItems,它的功能非常有限(最小 width/height 和大小策略),如果你想要更大的比例边距,你必须设置它在拉伸中。另一种可能性是使用空 QWidgets 而不是 spacers.
基于以上,更好的选择是实际设置网格布局的延伸:
vertical (rows): 1, 2, 1, 4, 1
horizontal (columns): 1, 2, 4, 4, 1
请记住,拉伸值是相对比例,如果您想要更精确的尺寸,请使用更大的值。
显然,您还可以为任何小部件设置最大尺寸,以防您不想超过某个尺寸。
我将附上原始文件(仅在小部件上设置了拉伸),所以我会留给您更改这些值,看看会发生什么。
最后,请记住,如果您添加另一个具有 一个 非 Preferred
或 Ignored
大小策略的小部件,布局将做出反应因此。尝试将按钮添加到现有按钮的同一行或同一列的空网格中,您将看到结果。
这是基本的 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>806</width>
<height>507</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,2,0,0">
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<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 row="4" column="3">
<spacer name="verticalSpacer_3">
<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 row="3" column="4">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>2</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<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>
<item row="0" column="1">
<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>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>806</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
虽然基本上只有三个基本布局管理器(QFormLayout 和 QStackedLayout 有点不同),而且它们非常简单,但学习如何使用它们需要大量时间和经验。此外,了解尺寸提示和策略的工作原理对于更好地理解它们的行为 非常 非常重要。我强烈建议您在 Designer 中以及通过从代码创建 UI 来做 大量 实验。
出于 学习 目的,您可以在 Designer 中创建 UI,使用 pyuic
将其导出并研究其内容。但是,请记住,不要 ever、never 编辑生产代码的这些文件。在关于 using Designer.
的官方指南中阅读更多关于它们的用法
TLDR: QT Designer 不允许我在尊重 window 缩放比例的同时移动和调整小部件的大小。当将它从图像 1 拖动到图像 2 时,我想让最右边的按钮更靠近 window 的边缘,也就是保持比例。
我正在将 PyQT5 与 QT Designer 一起使用。我正在尝试手动组织(移动和调整)我的小部件,但我的两种方法(接下来解释)都失败了。
当我使用网格布局时,我可以通过拖动其边缘来更改 window 大小来缩放小部件(正如预期的那样......太棒了!)。但是当我使用布局时,我无法更改小部件的相对位置。使用布局时,我也无法拖动单个小部件的边缘以在 window 内调整它的大小(真可惜,这对于构建我的 UI 很重要)。
另一方面,当我不使用任何布局时,我可以自由移动和调整各个小部件的大小(耶!)。但是如果不使用布局,我的小部件将不再缩放以适应 window 大小。
我的问题是,如何在 QT Designer 中移动和调整小部件的大小?我认为我可以在 QT Designer 本身中做到这一点,而不是依赖于 PyQT5 的混乱,因为即使是微小的变化也会变得复杂,而不是 QT Designer 的拖放功能?
附件是一些屏幕截图,以图形方式显示我的意思。前两张照片显示了在没有布局的情况下发生的情况。我将 window 变大了,但我的小部件仍以相同大小留在同一位置。第三张截图显示了当我使用网格布局时会发生什么。我无法调整任何小部件的大小,也无法移动它们。
换句话说,是否有更有效的方法来使用 QT Designer 移动和调整大小来解决这两个问题?
我希望将最右边的按钮从图像 1 拖动到图像 2 时靠近 window 的边缘,也就是保持比例。
如果要实现比例则:
使用额外的 QWidgets(默认情况下是不可见的,但对于我的演示我会设置背景颜色)或 QSpacerItem,
使用满足条件的拉伸因子,并且
将所有小部件的 sizePolice 设置为忽略。
网格布局将使用该信息来重新缩放几何图形。
对于我的演示,window 的大小为 200x200,按钮的位置为 50x50,大小为 40x40。
对于左侧的小部件,您必须将水平拉伸因子设置为 40
对于右侧的中央,您必须将水平拉伸因子设置为 50,将水平拉伸因子设置为 50。
对于右侧的小部件,您必须将水平拉伸因子设置为 90(200 - 50 -40)
对于顶部的小部件,您必须将垂直拉伸系数设置为 50。
对于底部的小部件,您必须将垂直拉伸系数设置为 90(200 - 50 -40)。
<?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>593</width>
<height>439</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QWidget" name="top" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>50</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(85, 255, 127);</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QWidget" name="left" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>50</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 0, 0);</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>40</horstretch>
<verstretch>40</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QWidget" name="right" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>110</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 85, 255);</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="bottom" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Ignored">
<horstretch>0</horstretch>
<verstretch>110</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(85, 255, 255);</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>593</width>
<height>28</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
虽然过度拥挤的 UI 通常不是一个好主意,但有很多空 space 很少会更好。布局管理器考虑了这个方面,并尝试通过使小部件尽可能多地使用 space 来 优化 可用 space(假设它们可以调整大小)。
也就是说,显然有很多情况下 window 和很多 space 是好的(例如,登录访问界面足够大以引起注意)。
重要的是要理解布局管理器,顾名思义,管理布局,它通过很多复杂的计算,基于安装它的小部件和所有其子项的所有大小hints/policies/constraints,递归地。如果您对某些小部件应该如何调整大小有一些要求,则必须指定它们。
每当要创建 任何 界面时,特别是如果正在考虑用户体验问题(这是他们应该考虑的)并且还有很多空的 space要按比例使用,至少有两个重要步骤:
- 准确理解在布局的“正常”条件下应如何放置小部件(位置、大小和比例);
- 考虑一下当调整容器大小时那些尺寸和位置应该改变;
第一点似乎很好解释,但即使创建一个使用布局考虑空白区域的基本界面也不是那么简单。
根据情况,网格布局可能就足够了,但在某些情况下,您可能需要使用 nested 布局。
在您的具体情况下,网格可能就足够了,但要确保保持适当的间距和比例,您需要使用 spacer items.
我已经为您的案例准备了一个基本的 UI 示例:比例可能不完全正确,但这只是一个开始。
这是它在正常尺寸下的样子:
这就是它变大后的样子:
如您所见,我添加了 spacers:靠近边缘的 each 边有一个,这是确保适当的“边界边距”所必需的保持不变,然后另外两个用于两个按钮之间的间距;由于网格变为 5x5,因此两个中心 spacers 的“单元格”位置可能在任何位置,只要垂直在中央行和水平在中央列即可。
现在小部件的比例和间距是通过以下方式实现的:
- 两个按钮都有
Preferred
尺寸政策(垂直和水平);这确保布局知道如果有足够的 space 可以让它们变大,但不会让它们占用 all 可用的 space; - 左上按钮的大小策略 stretch 为 1(同样,垂直和水平),而右下按钮为 2;这样,他们的第二个按钮将始终 try 是第一个按钮宽度和高度的两倍;
- 布局(通过单击中央小部件可访问)还为第三列(中间的列)设置了 2 的列拉伸;考虑到上述情况,结果将是布局将尝试使中间的 space 与右下按钮一样宽;
请注意,当使用网格时,按钮的行或列拉伸可以(有时 应该)直接在布局上设置。
还要考虑到边缘的 spacers 是基本的 QSpacerItems,它的功能非常有限(最小 width/height 和大小策略),如果你想要更大的比例边距,你必须设置它在拉伸中。另一种可能性是使用空 QWidgets 而不是 spacers.
基于以上,更好的选择是实际设置网格布局的延伸:
vertical (rows): 1, 2, 1, 4, 1
horizontal (columns): 1, 2, 4, 4, 1
请记住,拉伸值是相对比例,如果您想要更精确的尺寸,请使用更大的值。
显然,您还可以为任何小部件设置最大尺寸,以防您不想超过某个尺寸。
我将附上原始文件(仅在小部件上设置了拉伸),所以我会留给您更改这些值,看看会发生什么。
最后,请记住,如果您添加另一个具有 一个 非 Preferred
或 Ignored
大小策略的小部件,布局将做出反应因此。尝试将按钮添加到现有按钮的同一行或同一列的空网格中,您将看到结果。
这是基本的 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>806</width>
<height>507</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,2,0,0">
<item row="1" column="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<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 row="4" column="3">
<spacer name="verticalSpacer_3">
<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 row="3" column="4">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>2</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="0">
<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>
<item row="0" column="1">
<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>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>806</width>
<height>24</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
虽然基本上只有三个基本布局管理器(QFormLayout 和 QStackedLayout 有点不同),而且它们非常简单,但学习如何使用它们需要大量时间和经验。此外,了解尺寸提示和策略的工作原理对于更好地理解它们的行为 非常 非常重要。我强烈建议您在 Designer 中以及通过从代码创建 UI 来做 大量 实验。
出于 学习 目的,您可以在 Designer 中创建 UI,使用 pyuic
将其导出并研究其内容。但是,请记住,不要 ever、never 编辑生产代码的这些文件。在关于 using Designer.