🌟想系统化学习 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_())