文章目录
基类控件
一、 简介
1、 什么是 Qt
使用 C++ 语言编写的跨平台 GUI 库,支持Windows 、MacOS和Linux。由于 Qt 使用C++语言编写,所以使用Qt开发的GUI程序的界面风格与当前操作系统完全相同,而且运行效率很高
2、 什么是PyQt
PyQt实现了一个Python模块集。它有超过300类,将近6000个函数和方法。它是一个多平台的工具包,可以运行在所有主要操作系统上,包括UNIX,Windows和Mac。 PyQt采用双许可证,开发人员可以选择GPL和商业许可。在此之前,GPL的版本只能用在Unix上,从PyQt的版本4开始,GPL许可证可用于所有支持的平台 ,同时Qt能实现的功能PyQt都能实现
3、 环境搭建
安装 PyQt5
pip install pyqt5
官方文档:【https://www.riverbankcomputing.com/static/Docs/PyQt5/sip-classes.html】
二、 基本结构
1、 第一个程序
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, qApp
import sys
# 创建一个应用程序
# sys.argv 当别人通过命令行执行这个程序的时候,可以设定一种功能(接收命令行传递的参数)
app = QApplication(sys.argv)
print(app.arguments()) # 得到命令行的参数
print(qApp.arguments()) # qApp为全局变量
# 创建一个窗口
w = QWidget()
# 窗口尺寸
w.resize(300, 150)
# 移动窗口,窗口左上角的坐标
w.move(300, 300)
# 设置窗口的标题
w.setWindowTitle("第一个基于pyqt5的桌面应用")
# 设置标签
label = QLabel(w)
label.setText("hello world")
label.move(150, 75)
# 显示窗口
w.show()
# 进入程序的消息循环,并通过exit函数确保主循环安全结束,相当于无限循环
# 检测整个程序所接收到的用户交互信息
sys.exit(app.exec_())
2、 控件操作
步骤:
-
创建控件
-
# 设置标签 label = QLabel(contain)
参数:
- contain:代表要在哪个控件(容器)上面展示,可以为空
当我们创建一个控件之后,如果说,这个控件没有父控件,则把它当作顶层控件(窗口)
-
-
设置控件
- 大小,样式,位置,样式等
- 顶层控件有权限去设置窗口内容,结构等
-
展示控件
- 当控件没有父控件时,要使用 show 方法去展示控件
3、 快速生成代码
在pycharm中的活动模板配置如下代码,快速生成代码
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("$test$") # 设置标题
self.resize($500$, $500$) # 设置窗口大小
self.move($300$, $300$) # 移动窗口
self.setup_ui() # 调用创建控件的方法
def setup_ui(self): # 添加控件的操作
pass
if __name__ == '__main__':
# 可以通过导包来运行窗口
import sys
app = QApplication(sys.argv)
# 创建窗口
w = Window()
# 显示窗口
w.show()
sys.exit(app.exec_())
4、 面向对象
提高代码的可维护性
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle("Hello") # 设置标题
self.resize(300, 150) # 设置窗口大小
self.move(300, 300) # 移动窗口
self.setup_label() # 调用创建控件的方法
def setup_label(self): # 添加控件的操作
label = QLabel(self)
label.setText("Hello World")
label.move(150, 75)
if __name__ == '__main__':
# 可以通过导包来运行窗口
import sys
app = QApplication(sys.argv)
# 创建窗口
w = Window()
# 显示窗口
w.show()
sys.exit(app.exec_())
三、 基类控件
什么是控件?
- 一个程序界面上的各个独立的标准,一块矩形区域
- 每类控件都具备不同的功能
- 同时,有些控件有相似的功能,可以通过继承关系学习
1、 QObject
1.1 设置标识
1.1.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.Qt import *
obj = QObject(self)
obj.setObjectName("notice") # 设置Qt对象名称
print(obj.objectName()) # 获得Qt对象名称
obj.setProperty("notice_l", "error") # 设置对象的属性
obj.setProperty("notice_l2", "warning")
print(obj.property("notice_l")) # 获得一个对象的属性值
print(obj.dynamicPropertyNames()) # 获取一个对象中所有通过setProperty设置的属性名称
1.1.2 应用场景
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QObject") # 设置标题
self.resize(500, 300) # 设置窗口大小
self.move(500, 500) # 移动窗口
self.setup_ui() # 调用创建控件的方法
def setup_ui(self): # 添加控件的操作
self.qObject_ui()
def qObject_ui(self): # 所有类的基类
# 案例演示
label = QLabel(self) # 创建标签
label.setText("Hello") # 设置标签内容
label.setObjectName("notice") # id 为 notice
label.setProperty("level", "error") # 属性选择器
with open("QStyle.qss", "r") as f:
"""
文件内容为:
QLabel#notice[level='error'] {
font-size: 20px;
color: blue;
}
"""
qApp.setStyleSheet(f.read())
# label.setStyleSheet("font-size: 20px; color: blue;")
# qss 样式表,相当于前端的 css 样式表,可以将其放入一个 `.qss` 的文件中,方便分离和读取,同时,所有符合条件的内容都会变成相应的样式
if __name__ == '__main__':
# 可以通过导包来运行窗口
import sys
app = QApplication(sys.argv)
# 创建窗口
w = Window()
# 显示窗口
w.show()
sys.exit(app.exec_())
1.3 父子对象
1.3.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj2.setParent(obj1) # 设置父子关系
obj3.setObjectName("2") # 设置id
obj3.setParent(obj2)
print(obj1, obj2.parent()) # 获取父类,返回内存地址
print(obj2, obj1.children()) # 获取所有直系子对象
print(obj1.findChild(QObject)) # 获取后代,递归查找,只返回一个
print(obj1.findChild(QObject, "2")) # 获取id为2的后代,只返回一个
print(obj1.findChildren(QObject)) # 获取符合条件的所有后代
1.3.2 应用场景
内存管理机制,父控件删除,那么子控件也会自动删除
- 按钮和对话框本身是父子控件关系
- 当对话框被删除时,内部的子控件也会自动删除——非常合理
- 我们操作的时候,是操作的对话框控件本身,而不是内部的子控件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2)
# 监听 obj2 对象被释放
obj2.destroyed.connect(lambda: print("obj2,被释放"))
print("删除父对象")
del obj1
print("删除完成")
如果一个控件,没有任何父控件,那么就会被当成顶层控件——多个顶层窗口相互独立
如果想要一个控件被包含在另外一个控件内部,就需要设置父子关系
- 显示位置受父控件约束
- 生命周期也被符对象接管
案例:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
win1 = QWidget()
win1.setStyleSheet("background-color: blue;")
win1.setWindowTitle("blue")
win1.resize(500, 500)
win1.show()
win2 = QWidget(win1)
win2.setStyleSheet("background-color: red;")
win2.setWindowTitle("red")
win2.resize(100, 100)
# win2.setParent(win1) # win1 为父对象,win2 = QWidget(win1) 效果一样
win2.show()
l1 = QLabel()
b1 = QPushButton()
l1.setParent(win1)
b1.setParent(win1)
l1.setText("label")
b1.setText("button")
l1.move(200, 200)
b1.move(300, 200)
l2 = QLabel()
l2.setParent(win1)
l2.setText("Label")
l2.move(100, 200)
# 遍历设置样式
for i in win1.findChildren(QLabel):
i.setStyleSheet("color: green;")
l1.show()
b1.show()
l2.show()
sys.exit(app.exec_())
1.4 信号操作
1.4.1 信号与槽机制
信号和槽是Qt中的核心机制,主要作用在于对象之间进行通讯
- 当达到某个条件时,执行某个操作
信号(widget):
- 当一个控件的状态发生改变时,向外发出信息
槽(connect):
- 一个执行某些操作的函数/方法
所有继承自 QWidget 的控件都支持信号与槽机制
1.4.2 机制描述
手动操作:
- 信号和槽相关联
自动操作:
- 当信号发出时,连接槽函数会自动执行
1.4.3 信号处理
信号:
objectNameChange(objectName)
:对象名称发生改变时,发射此信号destroyed(obj)
:对象被销毁时,发射信号blockSignals(True)
:临时阻断连接receivers(widget)
:查看当前信号连接了多少个槽
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
def destroy():
print("对象被摧毁")
obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2)
# obj.destroyed
obj1.destroyed.connect(lambda: destroy())
# obj.objectNameChanged
obj1.objectNameChanged.connect(lambda name: print("对象名称被改变: " + name))
obj1.setObjectName("xxx")
# obj1.objectNameChanged.disconnect() # 断开槽与信号的连接
obj1.blockSignals(True) # 临时阻断连接
obj1.setObjectName("1")
print("连接数量:" + str(obj1.receivers(obj1.objectNameChanged))) # 查看有多少个槽连接这个信号
obj1.blockSignals(False) # 再次开启连接
obj1.objectNameChanged.connect(lambda name: print("第二个连接:" + name))
print("连接数量:" + str(obj1.receivers(obj1.objectNameChanged))) # 查看有多少个槽连接这个信号
obj1.setObjectName("2")
del obj2
1.4.4 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("test") # 设置标题
self.resize(300, 300) # 设置窗口大小
self.move(200, 300) # 移动窗口
self.setup_ui() # 调用创建控件的方法
def ret():
print("标题变化了")
# self.windowTitleChanged.disconnect() # 断开槽与信号的关系
self.blockSignals(True) # 临时断开连接也行
self.windowTitleChanged.connect(ret)
def setup_ui(self): # 添加控件的操作
self.btn() # 添加按钮
def btn(self):
b = QPushButton(self)
b.setText("点击我")
def ret():
self.setWindowTitle("hello")
b.clicked.connect(ret)
if __name__ == '__main__':
# 可以通过导包来运行窗口
import sys
app = QApplication(sys.argv)
# 创建窗口
w = Window()
# 显示窗口
w.show()
sys.exit(app.exec_())
1.5 类型判定
1.5.1 语法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys