对象的名称和属性
# 实例化对象
obj = QObject()
# 设置名称, 可以重复
obj.setObjectName("名")
# 设置属性
obj.setProperty("name", "jack")
obj.property("name") # 获取属性值
# 获取所有的动态属性
obj.dynamicPropertyNames()
# 设置样式使用qss, 类似css样式表
label = QLabel(window)
label.setText("富文本")
label.setStyleSheet("color:red; font-size:24px;")
# 也可以创建.qss 文件,设置样式
# 控件选择器
QLabel {
color: red;
font-size: 24px;
}
// 控件选择器 + id选择器
QPushButton#pp{
color: blue;
}
//id选择器 + 属性
QPushButton#pp[name="jack"]{
key: value; /*类似css*/
}
//也可以直接通过id选择器实现
#pp[name=laufing]{
color: red;
background: gray;
font-weight: bold;
font-style: italic;
padding: 2px;
margin: 20px;
width: 50px;
height: 100px;
border-style: solid;
border-width: 2px;
border-color: yellow;
text-align: right;
}
# 使用样式文件
from PyQt5.Qt import qApp
with open("style.qss", "r") as f:
qApp.setStyleSheet(f.read())
QObject对象的父子关系
from PyQt5.QtCore import QObject
obj1 = QObject()
obj2 = QObject()
# 设置父对象
obj2.setParent(obj1)
# 查看父对象
obj2.parent()
# 查看直接子对象
obj1.children()
# 查找一个子对象
obj1.findChild(类型, 对象名称, 查找方式)
obj1.findChild(QObject, 'laufing', Qt.FindChildrenRecursively)
obj1.findChild(QObject, 'laufing', Qt.FindDirectChildrenOnly)
obj1.findChildren() # 查找多个子对象
# 导入
from PyQt5.QtCore import Qt
Qt.FindChildOption.FindChildrenRecursively
Qt的内存管理
1. 所有的对象都直接或者间接的继承QObject,形参QObject继承树;
2. 当实例化一个QObject对象时,若指定父对象,则该QObject对象则会放入父对象的children列表中
3. 父对象销毁时,其所有的子对象也一起销毁,避免内存泄漏。
# 在一个函数中测试如下:
obj1 = QObject()
obj2 = QObject()
obj2.setParent(obj1)
# 删除信号 连接槽函数
obj1.destroyed.connect(lambda : print("obj1被销毁"))
obj2.destroyed.connect(lambda :print("obj2被销毁"))
反映到控件:
- 当一个控件设置了父控件,那么就被受父控件的管理(大小、生命周期),父控件删除,子控件也被删除
- 案例,关闭一个对话框,则删除其内部的所有的子控件。
案例
- 创建一个空白窗口,添加多个QLabel、QPushButton等控件
- 所有的QLabel都设置cyan背景色
- 在添加一个QLabel 控件 也是具有相同的背景色
# __author__ = "laufing"
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QLabel, QPushButton
from PyQt5.QtGui import QIcon, QPixmap
import sys
app = QApplication(sys.argv)
w1 = QWidget()
w1.setWindowTitle("laufing")
icon = QIcon()
icon.addPixmap(QPixmap("./imgs/dog.jpg"), QIcon.Normal, QIcon.Off)
w1.setWindowIcon(icon)
w1.resize(400, 500)
w1.move(300, 300)
label1 = QLabel(w1)
label1.setText("label1")
label1.resize(30, 20)
label1.move(0,20)
label2 = QLabel(w1)
label2.setText("label2")
label2.resize(30, 20)
label2.move(35, 20)
btn = QPushButton(w1)
btn.setText("btn1")
btn.resize(30, 20)
btn.move(70, 20)
# 设置label颜色
for i in w1.findChildren(QLabel):
i.setStyleSheet("background-color:cyan")
w1.show()
exit_code = app.exec_()
sys.exit(exit_code)
QObject 信号的操作
信号与槽机制, Qt中的核心机制,用户对象之间通信。
当一个控件的状态发生变化时,会发出信号,然后提前连接的槽函数,执行相应的操作。
继承QWidget的控件,都支持信号与槽
机制
信号种类:
内置
QPushButton().pressed, 按下时
QPushButton().clicked 点击时
自定义
pyqtSignal()
槽函数种类
内置 & 自定义函数
建立连接
object.信号.connect(槽函数)
信号与槽 是多对多关系,一个信号可以连接多个槽函数,一个槽函数也可以监听多个信号。
信号也可以连接另一个信号
具体使用:
obj1 = QObject()
# 对象被销毁时,发出destroyed信号,绑定槽函数
obj1.destroyed.connect(myFunc) # myFunc定义时,可以接收参数obj, 就是触发信号的对象。
obj1.objectNameChanged.connect(func1) # 槽函数会接收 改后的名字
# 取消信号与槽函数的连接,信号依旧触发,但没有函数的执行
obj1.objectNameChanged.disconnect()
# 临时取消 信号与槽的连接
obj1.blockSignals(True)
obj1.blockSignals(False) # 恢复
# 查看信号是否阻塞
obj1.signalsBlocked() # 返回True or False
# 信号连接的槽函数 数量
obj1.receivers(obj1.objectNameChanged) # 必须传入信号
案例
:
实现窗口中放置一个按钮,点击时,每次更改窗口的标题,如
点击一次, 变为“laufing 1”
点击二次,变为“laufing2”
…
# 核心代码
#
click_times = 0
def func1(p):
# 声明是全局变量,默认赋值的变量为局部变量
global click_times
click_times += 1
# p 为 False ?
print("点击按钮,更改窗口的名称:", p, type(p))
# 设置窗口标题(顶级控件)
print(w1)
w1.setWindowTitle("laufing")
def func2(p):
print("窗口名字改变:", p)
# 声明是全局变量
global click_times
# 修改窗口标题
w1.blockSignals(True) # 临时阻塞信号
w1.setWindowTitle("laufing " + str(click_times)) # 设置标题
w1.blockSignals(False) # 取消信号阻塞
# 信号与槽 连接
w1.windowTitleChanged.connect(func2)
w1.setWindowTitle("6666")
btn.clicked.connect(func1)
QObject 类型判定
# 判定对象是否是某个类型
obj.isWidgetType() # 对象是否 为控件类型
obj.inherits("QWidget") # 返回bool
obj.inherits("QLabel")
QObject 对象的删除
deleteLater() 稍后删除一个对象,并与父对象解出关系;
给消息循环发送一个事件,下次循环时再删除;
在本次循环,还可以继续完成相关操作。
# 删除一个对象
obj.deleteLater()
事件机制
用户的操作会产生消息,放入消息队列中:
操作系统的消息队列, 如键盘事件、鼠标事件
应用程序的消息队列,如控件的点击事件
消息循环不断扫描消息队列,将消息封装为QEvent对象,交给QApplication的notify
方法,进行二次分发,分发给事件源对象的event方法,然后在根据事件的类型分发给事件源对象的事件函数。
# 定义自己的应用类,并实例化
class App(QApplication):
def notify(self, receiver, event):
# receiver 事件的接收对象(事件源), 如按钮
# event QEvent对象
# 过滤事件
if receiver.inherits("QPushButton") and event.type() == QEvent.MouseButtonPress:
print("事件:", receiver, event)
return super().notify(receiver, event)
# 定义一个按钮类并实例化,点击触发事件
class MyBtn(QPushButton): # QPushButton的源码方法 都是pass?
def event(self, event):
# 接收事件,并分发给对应的事件函数
if event.type() == QEvent.MouseButtonPress:
print("event函数接收事件", event)
# 父类的event函数分发
return super(MyBtn, self).event(event)
# 事件函数
def mousePressEvent(self, *args, **kwargs):
# 这里会发出pressed信号,便于连接 槽函数
print("事件函数执行中....")
return super().mousePressEvent(*args, **kwargs)
def mouseReleaseEvent(self, e):
return super().mouseReleaseEvent(e)
def mouseDoubleClickEvent(self, e):
print("双击....", e)
return super(MyBtn, self).mouseDoubleClickEvent(e)
# 单击是?
信号与槽 是对事件的封装
为了对python文件进行加密,会把python模块编译成.pyd文件,供其他人调用。拿到一个.pyd文件,在没有文档说明的情况下,可以试试查看模块内的一些函数和类的用法
,pyd一般使用c/c++ 编写。
QObject的定时器
from PyQt5.QtCore import Qt
# Qt.PreciseTimer 精确毫秒
# Qt.CoarseTimer 5%误差
# 定义自己的类
class MyObject(QObject)
def timerEvent(self, *args, **kwargs):
print("定时的操作...")
# 实例化
obj = MyObject()
# 开启定时器, 毫秒 控件对象直接调用
timer_id = obj.startTimer(1000, 类型)
# 类型 Qt.PreciseTimer 精确到毫秒
# 取消定时器
obj.killTimer(timer_id)
案例:使用QLabel实现一个倒计时效果