PyQt入门(4)-尺寸策略和布局(上)

文章详细介绍了Qt中的尺寸策略,包括QSizePolicy的7种策略和拉伸优先级,以及QHBoxLayout和QVBoxLayout的使用,特别是拉伸因子和对齐方式如何影响控件布局。此外,还展示了如何实现一个简单的计算器界面作为应用示例。
摘要由CSDN通过智能技术生成

目录

一、尺寸策略

二、QHBoxLayout QVBoxLayout

1、stretch

 2、alignment

三、实现一个计算器界面


一、尺寸策略

widget的尺寸策略是是widget所在的布局处理widget外观(大小和位置)的依据。

widget在布局中则由尺寸策略决定其外观,不在布局中则由setGeometry()决定其外观。

在讨论尺寸策略之前先要了解一个函数:sizeHint() ,它返回一个QSize,是布局给widget提供的首选(默认)大小,不能通过代码设置。布局会根据widget的类型、内容等给widget实时提供一个合适的sizeHint,举个简单的例子,有个QLabel,给它的text设置成1和11的时候,他的sizeHint是不一样的。

PyQt5有7种策略,他们的值都是整数,如下表:

常量描述收缩拉伸
QSizePolicy::Fixed0见名知意,widget的尺寸固定就是sizeHint()的值不能不能
QSizePolicy::MinimumGrowFlag(1)widget的尺寸不能比sizeHint()小。widget倾向于拉伸不能
QSizePolicy::MaximumShrinkFlag(4)widget的尺寸不能比sizeHint()大。不能
QSizePolicy::PreferredGrowFlag | ShrinkFlag(5)sizeHint()是widget最合理的尺寸。这个策略是很多widget的默认策略widget倾向于拉伸
QSizePolicy::ExpandingGrowFlag | ShrinkFlag | ExpandFlag(7)sizeHint()对widget来说是一个合理的尺寸。widget倾向于拉伸
QSizePolicy::MinimumExpandingGrowFlag | ExpandFlag(3)widget的尺寸不能比sizeHint()小。widget倾向于拉伸不能
QSizePolicy::IgnoredShrinkFlag | GrowFlag | IgnoreFlag(13)widget的尺寸可以任意变大变小。widget倾向于拉伸

拉伸优先级:

( Expanding = MinimumExpanding )( Preferred = Ignored = Minimum ),就是说Expanding和Preferred放在一个布局里的话,会拉伸Expanding,收缩Preferred。

关于收缩:

Ignored:最小可以收缩到minimumSize(默认0),就是可以收缩到不显示widget了。

其他模式:无论怎么收缩,widget一定可以完整显示出来。

widget有两个属性:minimumSize和maximumSize,它们控制收缩和拉伸的边界,并且可以在代码中设置

label = QLabel("123")

print(label.minimumSize())
print(label.maximumSize())
print(label.sizeHint())
"""
输出:
PyQt5.QtCore.QSize() # 说明默认最小边界是0,这也是Ignored模式下,widget为什么可以收缩到不显示
PyQt5.QtCore.QSize(16777215, 16777215) # 可以拉伸的最大值
PyQt5.QtCore.QSize(18, 12) # 这个大小正好够显示123的
"""

label.setMinimumSize(10, 100)
label.setMaximumSize(200, 200)

print(label.minimumSize())
print(label.maximumSize())
print(label.sizeHint())
"""
输出:
PyQt5.QtCore.QSize(10, 100) # 这样无论什么模式,widget都不会收缩到不显示了
PyQt5.QtCore.QSize(200, 200)
PyQt5.QtCore.QSize(18, 12) # 这说明设置边界是不会影响sizeHint()的
"""

注意:

按理来说setMaximumSize()应该只是设置拉伸边界,不该影响到尺寸策略的,但是在实际的测试中发现,一旦setMaximumSize()之后,给widget设置Fixed和Maximum策略没有效果了,widget是一定倾向于拉伸的,并且优先级默认是Preferred级别,可以通过设置成Expanding和MinimumExpanding来提高级别

二、QHBoxLayout QVBoxLayout

QHBoxLayout和QVBoxLayout都继承自QBoxLayout,QHBoxLayout水平方向上排列widget,QVBoxLayout垂直方向上排列widget。它们只是排列的方向不同,用法完全一致。下面就以QHBoxLayout为例来说明。

QHBoxLayout添加widget的函数是

def addWidget(self,
              a0: QWidget,
              stretch: int = ...,
              alignment: Alignment | AlignmentFlag = ...)

1、stretch

stretch是拉伸因子,默认值是0,控制widget的拉伸比例,看下图:

 这个QHBoxLayout有两个widget:QLabel("123")和QLabel("2"),现在用的是Fixed策略,所以它们都没有拉伸,那么图上画的1、2、3三个区间就是总共的可拉伸区域,那么QLabel("123")和QLabel("2")分别应该拉伸多少呢?就是通过尺寸策略和拉伸因子共同控制,下面直接出结果:

1、如果两个stretch都是0的话,那就按上面说的拉伸优先级来:优先级高的拉伸全部空间,优先级低的不拉伸;优先级一样的话,空间均分

 2、如果两个stretch都不为0的话,拉伸优先级失效(即不存在优先级高的就拉伸的多),大家按各自的stretch为比例来拉伸空间,如stretch1=1,stretch2=2,则widget1拉伸1/3,widget2拉伸2/3

 3、如果有stretch为0,有stretch不为0的话,不管拉伸优先级,stretch为0的不拉伸,stretch不为0的拉伸全部空间,如stretch1=0,stretch2=1

 2、alignment

alignment是widget的对其方式(上、下、左、右、中间)

重要说明:alignment会在stretch和拉伸优先级的基础上消除widget在指定方向上的拉伸效果

不绕不解释,直接上效果图:

QSizePolicy1=Expanding,stretch1=1

QSizePolicy2=Minimum,stretch2=2

QSizePolicy1=Expanding,stretch1=1

QSizePolicy2=Minimum,stretch2=2,alignment2=Qt.AlignLeft | Qt.AlignTop

 

QSizePolicy1=Expanding,stretch1=1

QSizePolicy2=Minimum,stretch2=2,alignment2=Qt.AlignLeft

QSizePolicy1=Expanding,stretch1=1

QSizePolicy2=Minimum,stretch2=2,alignment2=Qt.AlignTop

三、实现一个计算器界面

效果图:

代码:

class MyTestWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        # 窗口标题
        self.setWindowTitle('计算器')
        # 窗口大小
        self.resize(300, 400)
        self.setCentralWidget(QWidget())

        # 把按钮的文字都设置成20px
        self.setStyleSheet("""QPushButton{font-size:20px;}""")

        # 主界面layout是一个QVBoxLayout
        self.main_layout = QVBoxLayout()

        # 用一个QLabel展示计算结果
        self.l_result = QLabel('0')
        self.l_result.setStyleSheet("""QLabel{background-color: red; font-size:40px;}""")
        # 设置QLabel的文件靠右垂直居中
        self.l_result.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        # 把l_result添加到主界面layout,拉伸因子是1
        self.main_layout.addWidget(self.l_result, stretch=1)

        # 按钮区域layout
        self.operation_layout = QVBoxLayout()
        # 设置layout内各控件之间的space为0
        self.operation_layout.setSpacing(0)
        # 设置layout内控件整体的外边距(可以理解成layout的内边距)
        self.operation_layout.setContentsMargins(0, 0, 0, 0)

        self.layout_l1 = QHBoxLayout()
        self.layout_l1.setSpacing(0)
        self.btn_init = QPushButton("AC")
        self.btn_back = QPushButton("X")
        self.btn_remainder = QPushButton("%")
        self.btn_div = QPushButton("÷")
        self.layout_l1.addWidget(self.btn_init)
        self.layout_l1.addWidget(self.btn_back)
        self.layout_l1.addWidget(self.btn_remainder)
        self.layout_l1.addWidget(self.btn_div)
        self.operation_layout.addLayout(self.layout_l1)

        self.layout_l2 = QHBoxLayout()
        self.layout_l2.setSpacing(0)
        self.btn_7 = QPushButton("7")
        self.btn_8 = QPushButton("8")
        self.btn_9 = QPushButton("9")
        self.btn_mul = QPushButton("x")
        self.layout_l2.addWidget(self.btn_7)
        self.layout_l2.addWidget(self.btn_8)
        self.layout_l2.addWidget(self.btn_9)
        self.layout_l2.addWidget(self.btn_mul)
        self.operation_layout.addLayout(self.layout_l2)

        self.layout_l3 = QHBoxLayout()
        self.layout_l3.setSpacing(0)
        self.btn_4 = QPushButton("4")
        self.btn_5 = QPushButton("5")
        self.btn_6 = QPushButton("6")
        self.btn_sub = QPushButton("-")
        self.layout_l3.addWidget(self.btn_4)
        self.layout_l3.addWidget(self.btn_5)
        self.layout_l3.addWidget(self.btn_6)
        self.layout_l3.addWidget(self.btn_sub)
        self.operation_layout.addLayout(self.layout_l3)

        self.layout_l4 = QHBoxLayout()
        self.layout_l4.setSpacing(0)
        self.btn_1 = QPushButton("1")
        self.btn_2 = QPushButton("2")
        self.btn_3 = QPushButton("3")
        self.btn_add = QPushButton("+")
        self.layout_l4.addWidget(self.btn_1)
        self.layout_l4.addWidget(self.btn_2)
        self.layout_l4.addWidget(self.btn_3)
        self.layout_l4.addWidget(self.btn_add)
        self.operation_layout.addLayout(self.layout_l4)

        self.layout_l5 = QHBoxLayout()
        self.layout_l5.setSpacing(0)
        self.btn_zero = QPushButton("0")
        self.btn_point = QPushButton(".")
        self.btn_equal = QPushButton("=")
        # 大家根据stretch为比例来拉伸空间
        self.layout_l5.addWidget(self.btn_zero, stretch=2)
        self.layout_l5.addWidget(self.btn_point, stretch=1)
        self.layout_l5.addWidget(self.btn_equal, stretch=1)
        self.operation_layout.addLayout(self.layout_l5)

        # 按钮区域layout的拉伸因子是5
        self.main_layout.addLayout(self.operation_layout, stretch=5)

        self.centralWidget().setLayout(self.main_layout)
        self.bat_set_policy()

    def bat_set_policy(self):
        for field in self.__dir__():
            if field.startswith("btn_"):
                # QPushButton的vPolicy默认是Fixed,要改成可拉伸的策略
                getattr(self, field).setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值