Pyside6 布局管理器(3)--- 控件尺寸、尺寸策略与布局的关系详解

在学习QWidget时我们已经学习了控件尺寸的一些基本设置,比如设置其作为顶层窗口时resize()方法,setGeometry()等方法。但在将控件添加到布局中后我们会发现,这些方法对于QWidget做为子控件时却是无效的。而布局的显示与大小也受到控件的影响。

所以,我们有必要了解这些关于控件尺寸限定的内容,为界面效果的展示建立相应的知识基础。

本章就是对控件的尺寸、尺寸策略及与布局的关系进行详细的介绍。

一、控件尺寸

1.控件尺寸的相关方法

API函数

参数说明

返回值

功能作用

resize(self, arg__1)arg_1:QSizeNone设置控件尺寸

size(self

None

QSize

获取控件的尺寸大小(不含框架)

setMaximumSize(self,maxw,maxh)

maxw:int

maxh:int

None

设置控件的最大尺寸

setMinimumSize(self,minw,minh)

minw:int

minh:int

None

设置控件的最小尺寸

maximumSize(self)

None

QSize

获取控件的最大尺寸

minimumSize(self)

None

QSize

获取控件的最小尺寸

setFixedSize(self,size)

size:QSzie(x,y

None

设置控件尺寸为固定尺寸,无法拉大缩小

setBaseSize(basew,baseh)

Basew:int基础宽度

Baseh:int 基础高度

None

设置控件的基础尺寸

baseSize(self)

None

QSize

获取控件的基础尺寸

setSizeIncrement(w,h)

W:int

H:int

None

设置控件延伸尺寸

sizeIncrement(self)

None

QSize

获取控件的延伸尺寸

sizeHint(self)

None

QSize

获取控件的推荐尺寸

minimumSizeHint(self)

None

QSize

获取控件的最小推荐尺寸

2.控件尺寸方法的含义的简要介绍

为什么说这里是简要介绍,因为对于控件的方法有些实在是用文字描述起来会难以说明白,需要放在具体使用情况下去区分它们用法上的区别。

resize():更改控件的尺寸大小,适用于顶层控件及独立控件。

size():获取控件当前实际尺寸大小。

setMaximumSize( ):设置控件的最大限定尺寸,控件的尺寸调整不允许超过设定值(不限于代码调整)。

maximumSize( ):获取控件设置的最大限定尺寸。

setMinimumSize( ):设置控件的最小限定尺寸,控件的尺寸调整不允许超过设定值(不限于代码调整)。

minimumSize( ):获取控件设置的最小限定尺寸。

setFixedSize( ):固定控件的尺寸,无法随意调整(不限于代码调整)。

setBaseSize( ):设置控件的基础尺寸。此方法任何时候都无法控制控件大小,仅仅起到提示作用。也就是说,设置这个值只是提醒用户,尽量不要将控件界面带下缩放到这个值之下,否则会影响内容的查看,这个方法在后面不再讨论。

baseSize):获取控件的基础尺寸。

setSizeIncrement( ):设置控件在拖动改变大小时调整步幅。windows下没有效果,macOS和linux下才能显示效果。且,需要加载布局和子控件。

sizeIncrement( ):获取控件拖动改变大小的调整步幅。

sizeHint( ):获取控件的建议尺寸,这个尺寸是子控件和布局中控件初始化大小的主要影响因素。即编程人员不使用reSize(),setMaximumSize( )等方法设置控件大小时的初始化尺寸大小。例如,需要多个大小相等的按钮,又不想使用尺寸的set方法。那么,就可以在自定义的QPushButton,通重写sizeHint( ),从而达到实例化多个按钮统一尺寸的目的。此方法的实际使用场景应是在布局中,见后面的小节。

minimumSizeHint( ):获取控件的最小建议尺寸。使用情况同sizeHint()。

二、控件的尺寸

1.顶层窗口的尺寸

1)顶层窗口不做设置的默认尺寸

这里所说的顶层窗口不仅仅是指定QWidget,还包括QLabel、QPushButton等继承自QWidget的控件未设置父对象时作为顶层窗口。我了探究他们在默认情况下尺寸控制情况,编写如下代码:

import sys
from PySide6.QtWidgets import QApplication, QWidget,QPushButton,QCalendarWidget,QMainWindow,QTextEdit,QGroupBox,QToolBox

class testWindow(QTextEdit):
    def __init__(self):
        super(testWindow, self).__init__()
        self.getSizes(self)

    @staticmethod
    def getSizes(obj):
        print(obj.size())
        print(obj.maximumSize())
        print(obj.minimumSize())
        print(obj.baseSize())
        print(obj.sizePolicy())
        print(obj.sizeIncrement())
        print(obj.sizeHint())
        print(obj.minimumSizeHint())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = testWindow()
    window.show()
    window.getSizes(window)
    sys.exit(app.exec())

在内部不装载子控件时:

  • 顶层窗口内部无子控件,QWidget作为顶层窗口时初始化尺寸是size()方法返回值,默认大小为QSize(640,480)。
  • 继承自QWidget的小控件做为顶层窗口且内部无子控件时,控制其初始化尺寸的方法则是sizeHint()。小控件类型不同,默认实现的尺寸大小也是不同的。如QPushButton是QSize(40,23),QLabel是QSize(6,15)。但需要注意的是,如QLabel,默认QSize(6,15)显然不能满足现实要求,那么他的实际在屏幕上展现的width则是标题栏的最小宽度。
  • 比较特殊的QMainWindow,内部无子控件时的默认尺寸是QSize(200,100),即不是size()的返回值,也不是sizeHint()的返回值。

装载子控件后:

  • QWidget、QMainWindow及QGroupBox、QStackedWiget等能够作为容器的控件作为顶层窗口,一部分是根据子控件的大小来计算其初始化大小(子控件大小+内容边距)。而有些则是Qt设置者内部定义了大小,而非size()或者sizeHint()的返回值,如QStackedWiget。
  • QPushButton、QLabel等独立控件作为顶层窗口装载子控件在这里没有讨论的意义,他们装载子控件干啥?

各控件在作为顶层窗口,默认情况下,相关尺寸方法的表现:

  • size()方法返回所有控件实际显示尺寸
  • maximumSize( )返回值为QSize(1677215,1677215),即默认情况可以无限大。
  • minimumSize( )返回值为QSize(0,0),即默认情况下可以缩小至看不到(会保留Title)
  • sizeIncrement( )返回值为QSize(0,0)。根据默认情况下的拖动效果,设计者在设计时内部可能已经实现了它的值QSize(1,1).
  • sizeHint( )返回值QWidget为QSize(-1,-1),其他控件各有不同。
  • minimumSizeHint( )返回值为QSize(-1,-1),其他控件各有不同。

总结:在不做任何设置的情况下,QWidget的初始化显示尺寸依赖的方法各有不同,有的是size()返回值,有的是sizeHint()返回值,有的是设计者内部定义值。作为编程人员,我们没有必要关心这些内容,而对顶层窗口的关注点应该在其设置的相关方法及表现。

设计者:Qt设计人员

编程人员:我们

用户:我们制作的GUI软件的使用者

2)顶层窗口尺寸设置及相关性质

顶层窗口尺寸初始化尺寸的设置方法,在QWidget中已经介绍过,通常我们使用resize()、setGeometry()方法。这些设置方法不仅可以在窗口初始化时使用,也可以在窗口显示后通过调用控件相关信号的方式改变窗口大小。下来,我们将调用了这些方法后,顶层窗口尺寸变化及相关表现进行罗列:

  • 如果resize()方法设置了顶层窗口,窗口的显示大小发生相应改变。
  • 如果设置了setMaximumSize( ),最大化按钮将不可用(无法最大化),窗口拖动改变大小时,最大只能拖动到设置值。
  • 如果设置了setMinimumSize( ),窗口拖动改变大小时,最小只能拖动到设置值(默认情况下可以拖动至只剩Title)。
  • 如果设置了setFixedSize( ),窗口固定大小,无法拖动改变大小,最大化按钮不可用。
  • 如果设置了setSizeIncrement( ),窗口拖动时,无变化。
  • sizeHint()通常是重写此方法,用返回值控制控件初始化大小,在顶层窗口的设置中无法表现。
  • minimumSizeHint( )通常是重写此方法,用返回值控制控件调整时最小值,在顶层窗口的设置中无法表现。

2.子控件未装载进布局时的尺寸

QWidget及其子类做为其他控件的子控件时且不装在进布局时,不做设置默认情况下,其初始化大小为sizeHint()的返回值。可以通过resize()方法改变其大小。其他尺寸方法对这种子控件没有什么作用。

表现上,他不随父控件的大小改变而改变,当父控件尺寸小于其尺寸时,其受到父控件窗口的裁剪。

3.子控件放入子布局时的尺寸

1)默认不做任何尺寸设置的情况

我们先看下面的代码:

from PySide6.QtWidgets import QWidget,QApplication,QGridLayout,QPushButton,QLabel,QTextEdit
import sys

class testWindow(QWidget):
    def __init__(self):
        super().__init__()
        lay = QGridLayout()
        self.setLayout(lay)
        self.move(300,300)

        btn1 = QPushButton()
        btn2 = QPushButton()
        btn3 = QPushButton()
        btn4 = QPushButton()
        lab = QLabel()
        lab.setStyleSheet("background:red")
        textEdit = QTextEdit()

        lay.addWidget(btn1,0,0)
        lay.addWidget(btn2,0,1)
        lay.addWidget(btn3,0,2)
        lay.addWidget(btn4,1,0)
        lay.addWidget(lab,1,1,1,2)
        lay.addWidget(textEdit,2,0,1,3)

        self.setBaseSize(500,500)
        self.setSizeIncrement(30,50)

        self.getSize(self)
        self.getSize(btn3)
        self.getSize(lab)
        self.getSize(textEdit)
        print(lay.contentsMargins())
        print(lay.spacing())

    @staticmethod
    def getSize(obj):
        print("{}的{}".format(obj,obj.size()))
        print("{}的{}".format(obj,obj.baseSize()))
        print("{}的{}".format(obj,obj.minimumSize()))
        print("{}的{}".format(obj,obj.maximumSize()))
        print("{}的{}".format(obj,obj.sizeIncrement()))
        print("{}的{}".format(obj,obj.sizeHint()))
        print("{}的{}".format(obj,obj.minimumSizeHint()))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = testWindow()
    win.show()
    sys.exit(app.exec())

运行结果:

控制台显示结果:

<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(640, 480)
<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(500, 500)
<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(0, 0)
<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(16777215, 16777215)
<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(30, 50)
<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(278, 272)
<__main__.testWindow(0x1aba16a4440) at 0x000001ABA360FE80>的PySide6.QtCore.QSize(154, 151)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(640, 480)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(16777215, 16777215)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(40, 23)
<PySide6.QtWidgets.QPushButton(0x1aba16a2a30) at 0x000001ABA36122C0>的PySide6.QtCore.QSize(40, 23)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(640, 480)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(16777215, 16777215)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(6, 15)
<PySide6.QtWidgets.QLabel(0x1aba16a8190) at 0x000001ABA36123C0>的PySide6.QtCore.QSize(6, 15)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(640, 480)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(16777215, 16777215)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(0, 0)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(256, 192)
<PySide6.QtWidgets.QTextEdit(0x1aba16b9650) at 0x000001ABA3612440>的PySide6.QtCore.QSize(71, 71)
<PySide6.QtCore.QMargins(11, 11, 11, 11) at 0x000001ABA36124C0>
6

从结果我们可以看出父窗口的初始化宽度和最小值是其sizeHitn()和minimumSizeHint()的返回值,而不是size()和minimumSize(),而且其初始化大小是受到内部子控件大小控制的。

父窗口的初始化宽度 = textEdit的sizeHint().width() + 2 * contentsMargin

                                  = 256+22

                                  = 278

父窗口的初始化高度 = btn的sizeHint().height()  *  2 + textEdit的sizeHint().height() +

                                    2 * contentsMargin +  2 * spaceing()

                                  = 23 *2 + 192 + 2 * 11 + 2* 6

                                  = 272

另外,通过计算我们也可以知道父窗口的最小值也是由其内部子控件的minimumSizeHint()决定的。所有得出以下结论,我们的得出以下结论:

  • size()返回值非子控件显示的实际值。各个子控件都是以自己的sizeHint()值进行呈现。跨行跨列的控件不遵从sizeHint()值展现,而是相应的进行伸展填充多余的空间(这与其尺寸策略有关)。
  • 当尺寸策略非Fixed的情况下或非Maximum,子控件的尺寸主要受伸缩因子控制。控件按照设置的伸缩因子所占比例分享除内容编剧和空白间距的空间。子控件会跟随父控件的大小改变而改变,最大值由父控件的大小决定,最小值由其minimumSizeHint()决定。
  • 当任意子控件的尺寸策略为Fixed,此子控件的尺寸固定为sizeHint(),不受其他任何因素影响,也不能跟随父控件大小改变而改变。这种固定是分为两个方向的,宽度固定,高度可变;宽度可变,高度固定;宽度和高度均固定。
  • 当任意子控件尺寸策略为Maximum,此子控件将以最大值进行显示,sizeHint()做为其最大值;多余空间由其他尺寸策略非Fixed或非Maximum的子控件占据。即,此控件的最大值被限制为maximumSize(),父控件尺寸增大的改变无法对其造成影响。
  • 父窗口不做任何尺寸设置的默认情况下,尺寸大小由内部控件的行列数(决定spacing的多少)及控件的类型(sizeHint()值)、内容边距值决定的。跨行跨列的情况下,各控件类型中sizeHint()最大值进行计算。

2)对含有布局的父控件进行设置

父控件为顶层窗口时,顶层窗口的设置依然如第二.1中所表现的一致。

子控件的尺寸设置表现及各因素之间的影响方式:

  • 子控件的resize()方法设置无效,其尺寸只受到sizeHint()方法、伸缩因子和其尺寸策略QSizePolicy影响。
  • sizeHint()控制控件初始化大小,通过重写可改变默认初始化大小的显示值。需要注意的是如果如果自定义控件时只重写sizeHint()而未重写minimumSizeHint( ),则默认minimumSizeHint( )的值等于sizeHint()的值。
  • 如果设置了setMaximumSize( ),除尺寸策略Fixed的限制,初始化显示值为设置值,控件尺寸跟随父控件的变化最大不能超过设置值。
  • 如果设置了setMinimumSize( ),除尺寸策略Fixed的限制,控件尺寸跟随父控件的变化最小不能超过设置值。
  • 如果设置了setFixedSize( ),子控件固定大小,其他任何因素无法对齐尺寸大小造成影响,也无法跟随父控件大小改变而改变大小。
  • setSizeIncrement( )对于子控件无任何影响。
  • minimumSizeHint( )通常是重写此方法,用返回值控制控件调整时最小值。

布局的影响因素较多,主要的因素组合产生的变化上面已经列出,需要大家多进行测试才能熟练的运用。

三、控件的尺寸策略

1.控件尺寸策略的含义

上一节我们已经接触到了控件的尺寸策略,不同的尺寸策略的设置将影响控件初始化尺寸的显示及跟随父窗口变化时自身尺寸的变化。这种变化的体现主要在控件的尺寸的自适应伸缩性质上。

比如,上一节的例子中,我们看到按钮的尺寸策略水平方向为minimum,竖直方向为Fixed。即:水平方向上sizeHint()为其最小值,但足够使用,且不能小于sizeHint()的值。在有额外空间时,它可以伸展,但与其他伸展策略相较没有优势。竖直方向上,其尺寸固定,不能大也不能小。

这里还要解释两个概念,一个是额外空间。所谓的额外空间就是窗口的尺寸能够计算的分配控件大于控件sizeHint()。比如,窗口尺寸是QSize(300,300),水平布局(LeftToRight)中放入两个按钮控件,水平方向上扣除两侧内容边距22(11*2),再扣除两个按钮间的空白间距6,那么每个按钮在水平方向上可分配的尺寸就应该是:L = (300-22-6)/2 = 136。而按钮的sizeHint()水平方向最小尺寸为65,那么这中间相差的71就是额外的控件。

另一个概念是伸展策略的优势:两个按钮的水平方向上的尺寸策略均为minimum。此时,我们将其中一个按钮的水平策略改为minimumExpanding(水平方向上sizeHint()为其最小值,但足够使用,且不能小于sizeHint()的值。在有额外空间时,它尽可能获得空间)。可以看到minimumExpanding策略比minimum策略在水平伸展的定义上有更高优先级。所以,当我们这么设置时,minimum策略的按钮尺寸水平方向上为sizeHint(),而minimumExpanding策略的按钮将获得71*2的额外尺寸。垂直方向两个按钮的尺寸策略是固定值,所以虽然有多余空间,但按钮垂直尺寸不在占用。

要具体了解他的作用与功能,就需要了解他的相关参数与含义,如下:

枚举类

枚举常量

枚举值

功能描述

QSizePolicy. Policy

Fixed

0

sizeHint()是唯一可接受的替代方案,因此小部件永远不会增长或收缩(例如:按钮的垂直方向)。

Minimum

1

sizeHint()是最小的,也是足够的。小部件可以被扩展,但是如果遇到高优先级的尺寸策略设置控件,它没有优势(例如,按钮的水平方向)。它不能小于sizeHint()提供的大小。

Maximum

2

sizeHint()是一个最大值。如果其他小部件需要空间,则小部件可以缩小任何量而不会受到损害(例如,分隔线)。它不能大于sizeHint()提供的大小。

Preferred

3

sizeHint()是最好的,但小部件可以缩小,仍然有用。小部件可以扩展,但是它比sizeHint()(默认的QWidget策略)大没有优势

Expanding

4

sizeHint()是一个合理的大小,但小部件可以缩小,仍然是有用的。小部件可以利用额外的空间,因此它应该获得尽可能多的空间(例如水平滑块的水平方向)。

MinimumExpanding

5

sizeHint()是最小的,也是足够的。小部件可以利用额外的空间,因此它应该获得尽可能多的空间(例如水平滑块的水平方向)。

Ignored

6

sizeHint()被忽略。小部件将获得尽可能多的空间。

从上面的枚举值和含义可以看到,控件的尺寸策略的设置都是以sizeHint()值为参考标准的。他可以分为两个方面进行理解。

第一个方面,跟随父控件变化的情况。

  • 不变。Fixed策略,可以理解为setFixedSize(),不能变化。
  • 单向变化。Minimum和MinimumExpanding策略,只能跟随父控件变大,不能再变小了。Maximum策略相反,只能跟随父控件变小,不能再变大了。
  • 双向变化。Preferred、Expanding、Ignored可随父控件的变化而变化。

第二个方面,初始化时尺寸占用空间扩展。

  • 固定值。Fixed策略,不受其他控件影响。
  • 优先级占用空间。Maximum < Minimum = Preferred < MinimumExpanding = Expanding < Ignored。

        用两个控件的尺寸策略设置作为比较,来说明他们的优先级。在QHBoxLayout布局中,两个控件A和B,水平策略设置如下:

        当A为Ignored时,B控件除非设置为Fixed,其他策略设置均会被压缩完空间,所有控件均被A占有。

        当A为Maximum,B为除Maximum和Ignored外的其他策略时,A的水平方向大小为其sizeHint(),剩余水平空间被B占用;B为Maximum时,A和B平分水平空间。

        当A为Minimum或Preferred,B为MinimumExpanding或Expanding时,A的水平方向大小为其sizeHint(),剩余水平空间被B占用;B为Minimum或Preferred时,A和B平分水平空间。

        当A为MinimumExpanding或Expanding时,B除Ignored外其他策略时,均会被压缩至sizeHint(),多余控件被A占用。B为MinimumExpanding或Expanding时,A和B平分水平空间。

       不再做例子,自己试验。

2.控件的尺寸策略设置及QSizePolicy类的相关方法

控件尺寸策略的设置我们在QWidget的学习时已经学过,设置通过QWidget.setSizePolicy()方法,参数即是QSizePolicy类。获取使用QWidget.sizePolicy()方法。

下面是QSizePolicy类的初始化方法和其他相关方法:

API函数

参数说明

返回值

功能作用

QSizePolicy(HV,type=DefaultType)

H:QSizePolicy.Policy

V:QSizePolicy.Policy

type:QSizePolicy.ControlType

三个参数均为Qt枚举类型

None

添加空白部件

setControlType(self, type)

type: QSizePolicy.ControlType

None

设置与此大小策略适用的小组件关联的控件类型

controlType(self)

None

QSizePolicy.ControlType

返回与应用此大小策略的小组件关联的控件类型

setRetainSizeWhenHidden(self, retainSize)

retainSize:bool

None

设置布局在隐藏时是否应保留构件的大小。如果是 ,则不会通过隐藏小部件来更改布局

retainSizeWhenHidden(self)

None

bool

返回布局在隐藏时是否应保留小组件的大小。默认为Flase

setHeightForWidth(self, b)

b:bool

None

设置高度依赖于宽度

hasWidthForHeight(self)

None

bool

查看是否设置高度依赖于宽度

setWidthForHeight(self, b)

b:bool

None

设置宽度依赖于高度

hasWidthForHeight(self)

None

bool

查看是否设置宽度依赖于高度

setHorizontalPolicy(self, d)

QSizePolicy.Policy

None

设置水平方向尺寸策略

horizontalPolicy(self)

None

QSizePolicy.Policy

获取水平方向尺寸策略

setVerticalPolicy(self, d)

QSizePolicy.Policy

None

设置垂直方向尺寸策略

verticalPolicy(self)

None

QSizePolicy.Policy

获取垂直方向尺寸策略

setHorizontalStretch(self, stretchFactor)

stretchFactor: int

None

设置水平方向伸缩因子

horizontalStretch(self)

None

stretchFactor: int

获取水平方向的伸缩因子

setVerticalStretch(self, stretchFactor)

stretchFactor: int

None

设置垂直方向伸缩因子

verticalStretch(self)

None

stretchFactor: int

获取垂直方向的伸缩因子

expandingDirections(self)

None

Qt.Orientation

返回小部件在那个方向上能利用更多空间

transposed(self)

None

None

交换水平和垂直方向的尺寸策略及伸缩因子3

transposed(self)

None

QSizePolicy.Policy

返回一个交换了水平和垂直方向的策略及伸缩因子的尺寸策略对象

QSizePolicy的初始化方法前两个参数是个枚举类,分别指定水平和竖直两个方向的尺寸策略,具体枚举值及含义我们在上一小节已经学过。最后一个参数也是一个枚举类:

枚举类

枚举常量

枚举值

功能描述

QSizePolicy.controlType

DefalutType

未指定时的默认类型

ButtonBox

一个QDialogButtonBox的实例

CheckBox一个QCheckBox的实例
ComboBox一个QComboBox的实例
Frame一个QFrame的实例
GroupBox一个QGroupBox的实例
Label一个QLabel的实例
Line一个QQFrame类型为VLine或HLine的实例
LineEdit一个LineEdit的实例
PushButton一个PushButton的实例
RadioButton一个RadioButton的实例
Slider一个QSlider的实例
SpinBox一个QSpinBox的实例
      TableWidget一个QTableWidget的实例
ToolButton一个QToolButton的实例

通常,QSizePolicy的此参数可以忽略,并不是必要的。如果需要也可以通过setControlType(self, type)方法进行设置。这个参数用于指定此策略应当应用于控件的类型。它被一些样式使用,特别是QMacStyle,用于在部件之间插入适当的间距。例如,macOS Aqua指南规定按钮之间应间隔12像素,而垂直堆叠的单选按钮只需要6像素。

setHorizontalPolicy(self, d)和setHorizontalPolicy(self, d)则是分别设置控件水平和竖直方向上的尺寸策略。

expandingDirections(self)方法的返回值是基于尺寸策略的设置决定的。比如,如果按钮控件的默认尺寸策略水平方向为Minimum,垂直方向为Fixed,那么相应的返回值就是Qt.Orietnation.Horizeontal。

setHorizontalStretch(self, stretchFactor)和setVerticalStretch(self, stretchFactor)的作用和QLayout.addStrecth()作用相同。但建议使用布局的伸缩因子方法。

setHeightForWidth(self, b)作用是控制窗口部件的高度是否随其宽度的变化而变化。但是,它并没有进行实现,当 setHeightForWidth 设置为 True 时,需要重写 heightForWidth( ) 函数来指定在给定宽度 w 下窗口部件应有的高度。这通常用于那些其高度自然依赖于宽度的控件,例如标签(当文本换行时)或某些自定义绘制的控件。相应的setWidthForHeight(self, b)也是一样。

setRetainSizeWhenHidden(self, retainSize)方法设置布局在控件隐藏时是否应保留小部件的大小。如果retainSize为true,则不会通过隐藏小部件来更改布局。

四、例子

本例子基本使用前面学过的内容,仅有QFormLayout未学,将在后面的小节进行学习。例子中实现两个槽函数功能作为演示,其他的功能大家可以自己发挥。

from PySide6.QtWidgets import QWidget,QApplication,QFormLayout,QPushButton,\
    QLabel,QSizePolicy,QHBoxLayout,QVBoxLayout,QLineEdit
from PySide6.QtCore import Qt
from PySide6.QtGui import QAction,QIcon,QMovie
import sys,random

class customLab(QLabel):
    def __init__(self):
        super(customLab, self).__init__()

        font = self.font()
        font.setFamily("微软雅黑")
        font.setWordSpacing(20.0)
        self.setFont(font)
        self.setText(self.randomLetter())

    def mousePressEvent(self, ev):
        if ev.button() == Qt.MouseButton.LeftButton:
            self.setText(self.randomLetter())
    
    def randomLetter(self):
        self.letterList = [0] * 5
        for i in range(len(self.letterList)):
            self.letterList[i] = chr(random.randint(65,90))
        string = "".join(self.letterList)
        return string

class LoginWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setFixedSize(400,500)
        self.setWindowTitle("登陆界面")

        mainLayout = QVBoxLayout()
        self.setLayout(mainLayout)
        mainLayout.setContentsMargins(0,0,0,0)

        pictureLab = QLabel()
        pictureLab.setFixedHeight(self.height() / 2)
        pictureLab.setScaledContents(True)
        movie = QMovie(pictureLab)
        movie.setFileName("../exmaple/蒲公英.gif")
        movie.start()
        pictureLab.setMovie(movie)

        accountLab = QLabel("账号:")
        accountline = QLineEdit()
        accountline.setPlaceholderText("请输出账号")

        passwordLab = QLabel("密码:")
        passwordLine = QLineEdit()
        passwordLine.setPlaceholderText("请输入密码")
        passwordLine.setEchoMode(QLineEdit.EchoMode.Password)
        eyeAction = QAction(passwordLine)
        eyeAction.setIcon(QIcon("../exmaple/close-eye.PNG"))
        eyeAction.triggered.connect(self.setEye)
        passwordLine.addAction(eyeAction,QLineEdit.ActionPosition.TrailingPosition)

        acpwLayout = QFormLayout()
        acpwLayout.setContentsMargins(80,0,80,0)
        acpwLayout.setSpacing(20)
        acpwLayout.addRow(accountLab,accountline)
        acpwLayout.addRow(passwordLab,passwordLine)

        checkLine = QLineEdit()
        checkLine.setPlaceholderText("点击更换验证码")
        checkLine.setVisible(False)
        checkLab = customLab()
        checkLab.setVisible(False)
        checkLayout = QHBoxLayout()
        checkLayout.addWidget(checkLine)
        checkLayout.setContentsMargins(80,0,80,0)
        checkLayout.setSpacing(20)
        checkLayout.addWidget(checkLab)
        
        loginBtn = QPushButton("登   陆")
        loginBtn.setFixedHeight(40)
        loginBtn.clicked.connect(self.login)
        triggerQRLab = QLabel("<<<<二维码登陆")
        triggerQRLab.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        triggerPhoenLab = QLabel(">>>>手机登陆")
        loginLayout = QHBoxLayout()
        loginLayout.addWidget(triggerQRLab)
        loginLayout.addWidget(loginBtn)
        loginLayout.addWidget(triggerPhoenLab)

        registerLab = QLabel("<a href='#'>注册账号</a>")
        registerLab.setAlignment(Qt.AlignmentFlag.AlignCenter)
        registerLab.setTextInteractionFlags(Qt.TextInteractionFlag.LinksAccessibleByMouse)
        forgetLab = QLabel("<a href='#'>忘记密码</a>")
        forgetLab.setAlignment(Qt.AlignmentFlag.AlignCenter)
        registerLayout = QHBoxLayout()
        registerLayout.addWidget(registerLab)
        registerLayout.addWidget(forgetLab)

        messageLab = QLabel("  版权声明:xxx制作       备案号:xxxxxxxxxxxx")

        mainLayout.addWidget(pictureLab)
        mainLayout.addSpacing(30)
        mainLayout.addLayout(acpwLayout)
        mainLayout.addLayout(checkLayout)
        mainLayout.addLayout(loginLayout)
        mainLayout.addLayout(registerLayout)
        mainLayout.addWidget(messageLab)


        self.checkLine = checkLine
        self.checkLab = checkLab
        self.passwordline = passwordLine
        self.eye = eyeAction

    def setEye(self):
        if self.passwordline.echoMode() == QLineEdit.EchoMode.Password:
            self.passwordline.setEchoMode(QLineEdit.EchoMode.Normal)
            self.eye.setIcon(QIcon("../exmaple/open-eye.PNG"))
        else:
            self.passwordline.setEchoMode(QLineEdit.EchoMode.Password)
            self.eye.setIcon(QIcon("../exmaple/close-eye.PNG"))

    def login(self):
        self.checkLine.setVisible(True)
        self.checkLab.setVisible(True)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = LoginWindow()
    win.show()
    sys.exit(app.exec())

运行结果:

20241021-214254

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值