pyQt5 学习笔记(5)基本控件 QWidget
一、QWidget 简介
在前面几个小节,我们了解了pyQt5的一些最基础的操作,创建一个APP,定时器,信号槽以及绘制空间的方法,QWidget是一个非常基的基类,继承自QObject,所以也拥有QObject的特性。QWidget是所有GUI控件的基类,如按键,表情,文本框,单选/复选框等等。
一个QWideget如下所示:
由于只是创建了一个QWidget,它没有父类空间,所以Qt给加上了标题栏。真实的QWidget是红色框部分。它看起来就是一个灰色的矩形,什么也没有,这就是一个最基本的可视化控件。
二、QWidget 类的 API
前文我们通过resize来设置控件的大小,move来设置控件的位置,但是作为pyQt5的基本类,它还拥有许许多多的方法,这里就不在一一列举,虽然是pyQt5,但是同样可以参考Qt的官方网站查找相关的手册:
三、绘制按表格排列的控件
1. 效果预览
接下来我们来设计一个程序,这个程序在一个窗口下面创建多个QWidget控件,并按表格的格式排列,如下图所示:
- 5x5个控件:
- 5*10个控
2. 程序设计
首先我们要设计一个大的窗体,可以是QWiget控件,接着我们开始创建它的子控件,我们希望只是通过输入和个数,程序就能自动会我们绘画窗体,那么就需要编写计算各个控件大小和位置的代码,这样程序才知道如何是绘画。简单总结,本次程序设计分为以下几个步骤:
- 创建一个APP程序
- 创建一个QWidget作为最顶层控件
- 创建记录子控件个数和表格列数的变量
- 计算子控件宽度
- 使用for循环创建并根据计算好的坐标排列绘制子控件
接下来是具体的程序示例:
from PyQt5.Qt import *
import sys
#0. 创建一个Apo
app = QApplication(sys.argv)
#1. 创建一个父控件
window = QWidget()
#2. 设置父控件的大小和坐标等
window.resize(500,500)
window.move(300,300)
window.setWindowTitle("Qwidget")
#3. 记录需要绘画的子控件个数,
widget_count = 25
column_count = 5
#4. 计算宽度:子控件宽度 = 窗体的宽度÷列数
widget_width = window.width() / column_count
#5. 计算行个数:确定宽度和列数以后,进一步进入行数
row_count = (widget_count -1 ) // column_count + 1
#6. 计算子控件的高度
widget_height = window.height() / row_count
#7. 使用for循环开始绘制子窗体
for i in range(0,widget_count):
#8. 创建一个子窗体
w = QWidget(window)
#9. 设置子窗体换个大小
w.resize(widget_width, widget_height)
#10. 计算本次子控件的x和y坐标
widget_x = i % column_count * widget_width
widget_y = i //column_count * widget_height
#11. 设置子窗体的位置
w.move(widget_x,widget_y)
#12. 设置子窗体的样式表,背景蓝色,并把子控件最外1个像素作为边框,设置为绿色
w.setStyleSheet("background-color:blue;border:1px solid green;")
#13. 显示控件
window.show()
if __name__ == '__main__':
sys.exit(app.exec_())
在这个程序中,我们指定了列的个数和总体个数,所以它的绘制方式是固定的,这样我们就可以通过写算法来计算。它允许的效果如下所示:
四、程序的改进
以上程序看起来很合适,没有任何奇怪的地方,但是当我们把空间的列数设置为3列,则会出现意外的情况:
程序最后少了2个蓝色的控件,这是正常的,因为25个都已经画完了,但是奇怪的是,边框好像出现了白色的粗边框,影响了界面的每观,为什么和之前的显示不一样?
其实,原因就在于,前文设置了控件的列数为5列,而父控件的像素为500,那么算出来的控件宽度为100,它是一个整数,所以程序绘制起来就是顺利的,但是本次我们设置为3,计算出来的宽度就是500/3 = 166.6666…,它并非一个整数,而我们不可能要求程序去绘制一个166.6个像素点的图形。所以,对于行和列的长度,我们都会遇到这个问题,简单的处理是,把计算后控件的长和宽去取整,这里以向下取整为例,修改一下两处代码:
···
#4. 计算宽度:子控件宽度 = 窗体的宽度÷列数
widget_width = int((window.width() / column_count)) #加入int类型转换取整
···
widget_height = int((window.height() / row_count)) #加入int类型转换取整
···
这样,我们就把像素取整了,具体程序如下所示:
from PyQt5.Qt import *
import sys
#0. 创建一个Apo
app = QApplication(sys.argv)
#1. 创建一个父控件
window = QWidget()
#2. 设置父控件的大小和坐标等
window.resize(500,500)
window.move(300,300)
window.setWindowTitle("Qwidget")
#3. 记录需要绘画的子控件个数,
widget_count = 25
column_count = 3
#4. 计算宽度:子控件宽度 = 窗体的宽度÷列数
widget_width = int((window.width() / column_count))
#5. 计算行个数:确定宽度和列数以后,进一步进入行数
row_count = (widget_count -1 ) // column_count + 1
#6. 计算子控件的高度
widget_height = int((window.height() / row_count))
#7. 使用for循环开始绘制子窗体
for i in range(0,widget_count):
#8. 创建一个子窗体
w = QWidget(window)
#9. 设置子窗体换个大小
w.resize(widget_width, widget_height)
#10. 计算本次子控件的x和y坐标
widget_x = i % column_count * widget_width
widget_y = i //column_count * widget_height
#11. 设置子窗体的位置
w.move(widget_x,widget_y)
#12. 设置子窗体的样式表,背景蓝色,并把子控件最外1个像素作为边框,设置为绿色
w.setStyleSheet("background-color:blue;border:1px solid green;")
#13. 显示控件
window.show()
if __name__ == '__main__':
sys.exit(app.exec_())
其运行结果如下所示:
它看起来更美观了,由于我们想下取整了,所以控件是无法充满父控件的,导致最右和最下都预留了边框,这样,我们就可以再设计一个函数,它通过获取控件最后和最下的坐标,来微调父窗口的大小,让程序更加美观:
from PyQt5.Qt import *
import sys
#0. 创建一个Apo
app = QApplication(sys.argv)
#1. 创建一个父控件
window = QWidget()
#2. 设置父控件的大小和坐标等
window.resize(500,500)
window.move(300,300)
window.setWindowTitle("Qwidget")
#3. 记录需要绘画的子控件个数,
widget_count = 25
column_count = 3
#4. 计算宽度:子控件宽度 = 窗体的宽度÷列数
widget_width = int((window.width() / column_count))
#5. 计算行个数:确定宽度和列数以后,进一步进入行数
row_count = (widget_count -1 ) // column_count + 1
#6. 计算子控件的高度
widget_height = int((window.height() / row_count))
#7. 使用for循环开始绘制子窗体
for i in range(0,widget_count):
#8. 创建一个子窗体
w = QWidget(window)
#9. 设置子窗体换个大小
w.resize(widget_width, widget_height)
#10. 计算本次子控件的x和y坐标
widget_x = i % column_count * widget_width
widget_y = i //column_count * widget_height
#11. 设置子窗体的位置
w.move(widget_x,widget_y)
#12. 设置子窗体的样式表,背景蓝色,并把子控件最外1个像素作为边框,设置为绿色
w.setStyleSheet("background-color:blue;border:1px solid green;")
#13. 获取子控件的边界
rightmost = widget_width * 3 #控件最右 = 控件宽度 x 控件的个数
lowest = widget_y + widget_height #空间最底 = 空间最后一列的x坐标 + 本身高度
#14. 微调父窗口大小
window.resize(rightmost,lowest)
#13. 显示控件
window.show()
if __name__ == '__main__':
sys.exit(app.exec_())
程序运行效果如下:
至此,我们解决了程序美观的问题,更细致的,我们可以根据四拾伍入来取整而非粗暴的全部向下取整,这样保证父窗体尽可能的符合我们预设的大小,当然,如果你愿意,你还可以进一步改进程序的结构。这个小程序,如果我们把控件绘制为按键,它就成了一个矩阵键盘。
上一篇: 深入理解css样式position和index属性
下一篇: JVM之Class文件结构