Python GUI 编程 | QWidget 窗口控件详解 — 尺寸 & 位置操作

🌟想系统化学习 GUI 编程?看看这个:[Python GUI 编程] PySide & PyQt - 学习手册-优快云博客

在前面的章节中我们依次讲解了 QWidget 的参考坐标系以及 QWidegt 窗口尺寸的获取的方法,那么本章我们将来介绍一下 QWidget 的尺寸 & 位置设置方法。

QWidget 参考坐标系:QWidget 窗口控件详解 — 坐标系统

QWidget 获取窗口尺寸:QWidget 窗口控件详解 — 尺寸获取

0x01:QWidget 尺寸 & 位置操作 — 相关方法

0x0101:move(x, y)

QWidget 的 move(x, y) 方法可以操作窗口的 X,Y 位置(注意区分坐标系,无父类的控件参考坐标系是整个桌面;有父类的控件参考坐标系就是它的父类)。示例代码如下:

import sys
from PyQt5.Qt import *
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
widget1 = QWidget()
widget1.move(0, 0) # 移动窗口至 (0, 0) 位置
widget1.resize(500, 500) # 调整窗口大小为 500x500
widget1.show()
​
widget2 = QWidget()
widget2.move(500, 500) # 移动窗口至 (500, 500) 位置
widget2.resize(500, 500) # 调整窗口大小为 500x500
​
widget3 = QWidget(widget2)
widget3.move(0, 0) # 移动窗口至父窗口 (0, 0) 位置
widget3.resize(250, 250) # 调整窗口大小为 250x250
widget3.setStyleSheet("background-color: red;")
​
widget4 = QWidget(widget2)
widget4.move(250, 250) # 移动窗口至父窗口 (250, 250) 位置
widget4.resize(250, 250) # 调整窗口大小为 250x250
widget4.setStyleSheet("background-color: blue;")
​
widget2.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0102:resize(width, height)

QWidget 的 resize() 函数可以设置用户区域的宽高,这个在上面的例子中其实也有演示。这里笔者给你们看一个特殊的,示例代码如下:

import sys
from PyQt5.Qt import *
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
widget1 = QWidget()
widget1.move(0, 0) # 移动窗口至 (0, 0) 位置
widget1.resize(100, 100) # 调整窗口大小为 100x100
widget1.show()
​
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

在上面那个代码中,我们通过 resize() 尝试设置用户区域为 100 X 100,但是展现出来的结果,我们发现它就不是个正方形。这其实是因为外面套的那层框架,它给你的控件进行了一个限制,如果你调整的大小过小,控件上面的那些按钮就无法显示全,所以你无法为控件设置小于框架限制的大小。

0x0103:setGeometry(x_noFrame, y_noFrame, width, height)

通过 QWidget 的 setGeometry() 函数,我们能直接操控用户区域的位置以及宽高。该函数建议是在控件展示后再调用,看下面两个对比代码:

1. 对比案例 — 先展示后调用

import sys
from PyQt5.Qt import *
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
widget1 = QWidget()
widget1.move(0, 0) # 移动窗口至 (0, 0) 位置
​
# 先展示后调用 => 这个是正确的位置
widget1.show()
widget1.setGeometry(0, 0, 500, 500) # 设置 widget1 用户区域的位置和大小
​
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

如上,可以发现用户区域非常完美的展示到了它该展示的位置。

2. 对比案例 — 先调用后展示

import sys
from PyQt5.Qt import *
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 控件操作
widget1 = QWidget()
widget1.move(0, 0) # 移动窗口至 (0, 0) 位置
widget1.setGeometry(0, 0, 500, 500) # 设置 widget1 用户区域的位置和大小
widget1.show()
​
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

如上,可以发现,实际的用户位置发生了偏移,不推荐这种做法(偏移仅仅是针对这种没有父类的,坐标系是整个桌面的情况,如果控件有父类,就不会发生偏移了)。

0x0104:adjustSize()

QWidget 的 adjustSize() 方法可以根据窗口中的内容自定义的调整窗口大小。看下面这个示例:

import sys
from PyQt5.Qt import *
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 创建一个窗口对象
window = QWidget()
​
label = QLabel("Hello World", window)
label.setStyleSheet("background-color: cyan;")
label.move(100, 100)
​
btn = QPushButton("Click Me", window)
btn.move(100, 200)
​
def btn_click():
    label.setText(label.text() + "Hello World")
    label.adjustSize() # 设置 label 根据其内容自动调整大小
btn.clicked.connect(btn_click)
​
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x0105:setFixedSize(width, height)

通过 setFixedSize() 我们可以固定控件的大小。比如下面这个示例,原本我们的外框体是可以通过拖拽调整大小的,但是设置了 setFixedSize() 方法后,就无法调整大小了:

import sys
from PyQt5.Qt import *
​
# 1. 创建一个应用程序对象
app = QApplication(sys.argv)
# 2. 创建一个窗口对象
window = QWidget()
window.setFixedSize(500, 500) # 固定窗口的大小
​
window.show()
# 4. 应用程序的执行,进入到消息循环
sys.exit(app.exec_())

0x02:QWidget 尺寸 & 位置操作 — 演示案例

0x0201:案例一 固定列数的九宫格

本题的难点不在于如何移动控件,而在于计算控件所处的位置,下面是笔者的示例答案以及简单的分析过程(笔者懒,就直接标在运行结果上了):

import sys
import math
from PyQt5.Qt import *
​
class MyWindow(QWidget):
    def __init__(self, widget_count, widget_width, widget_height):
        super().__init__()
        self.setWindowTitle("QObject 九宫格布局")
        self.widget_count = widget_count  # 子控件的个数
        self.widget_width = widget_width  # 每个子控件的宽度
        self.widget_height = widget_height # 每个子控件的高度
        self.init_ui() #初始化 UI
    
    def init_ui(self):       
        # 初始化整个窗口的布局
        line = math.ceil(self.widget_count / 3) # 向上取整获取行数
        height = line * self.widget_height + (line - 1) * 10 # 计算总高度, (line - 1) * 10 是行间距
        widght = self.widget_width * 3 + 20 # 计算总宽度, 20 是左右间距
        self.setFixedSize(widght, height) # 设置窗口大小 => 固定了哈
​
        for widget in range(self.widget_count):
            # 创建子控件
            child = QWidget(self)
            child.resize(self.widget_width, self.widget_height)
            child.setStyleSheet("background-color: cyan")
​
            label = QLabel(child)
            label.setText(str(widget + 1))
            label.show()
            # 先展示 Label,后移动位置,避免 Label 位置不正确
            label.move((self.widget_width - label.width()) // 2, (self.widget_height - label.height()) // 2)
​
            # 设置子控件的布局
            row = widget // 3 # 计算子控件所在的行
            col = widget % 3 # 计算子控件所在的列
            child.show()
            child.move((10 + self.widget_width) * col if col !=0 else 0, (10 + self.widget_height) * row if row !=0 else 0)
​
if __name__ == "__main__":
    widget_count = 21 # 设置创建的子控件的数量
    widget_width = 200 # 设置子控件的宽度
    widget_height = 100 # 设置子控件的高度
​
    # 1. 创建一个应用程序对象
    app = QApplication(sys.argv)
    # 2. 创建一个窗口对象
    window = MyWindow(widget_count, widget_width, widget_height)
    window.show()
    # 4. 应用程序的执行,进入到消息循环
    sys.exit(app.exec_())

好吧,有点抽象,希望读者自己也跟着画画,然后算算,这个还是比较 Easy 的。

0x0202:案例二 固定窗口大小的九宫格

在上面那个案例中,我们是固定了列数,然后根据用户输入的子控件个数计算总框架的大小,然后再把子控件摆进去。在这个案例中,我们将固定整个画布的大小,然后由用户自定义控件的个数和列数来进行展示,示例代码如下:

import sys
import math
from PyQt5.Qt import *
​
class MyWindow(QWidget):
    def __init__(self, widget_count, columns_count, fix_width=800, fix_height=800, interval_size=10):
        super().__init__()
        self.setWindowTitle("QObject 九宫格布局")
        self.widget_count = widget_count    # 子控件的个数
        self.columns_count = columns_count  # 每行的子控件个数
        self.fix_width = fix_width          # 窗口固定宽度
        self.fix_height = fix_height        # 窗口固定高度
        self.interval_size = interval_size  # 子控件之间的间隔
        self.init_ui() #初始化 UI
    
    def init_ui(self):       
        # 初始化整个窗口的布局
        self.setFixedSize(self.fix_width, self.fix_height) # 设置窗口大小 => 固定了哈
​
        for widget in range(self.widget_count):
            # 创建子控件
            child = QWidget(self)
            child_width = int((self.fix_width - (self.columns_count - 1) * self.interval_size) / self.columns_count) # 子控件的宽度
            line_count = math.ceil(self.widget_count / self.columns_count) # 子控件行数
            child_height = int((self.fix_height - (line_count - 1) * self.interval_size) / line_count) # 子控件的高度
            child.resize(child_width, child_height) # 设置子控件大小
            child.setStyleSheet("background-color: cyan")
​
            label = QLabel(child)
            label.setText(str(widget + 1))
            label.show()
            # 先展示 Label,后移动位置,避免 Label 位置不正确
            label.move((child_width - label.width()) // 2, (child_height - label.height()) // 2)
​
            # 设置子控件的布局
            row = widget // self.columns_count # 计算子控件所在的行
            col = widget % self.columns_count # 计算子控件所在的列
            child.show()
            child.move((self.interval_size + child_width) * col if col !=0 else 0, (self.interval_size + child_height) * row if row !=0 else 0)
​
if __name__ == "__main__":
    widget_count = 100  # 设置创建的子控件的数量
    columns_count = 6 # 设置每行的子控件数量
    fix_width = 800   # 设置用户区域固定宽度
    fix_height = 800  # 设置用户区域固定高度
    interval_size = 10 # 设置控件之间的间隔
​
    # 1. 创建一个应用程序对象
    app = QApplication(sys.argv)
    # 2. 创建一个窗口对象
    window = MyWindow(widget_count, columns_count, fix_width=fix_width, fix_height=fix_height, interval_size=interval_size)
    window.show()
    # 4. 应用程序的执行,进入到消息循环
    sys.exit(app.exec_())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blue17 :: Hack3rX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值