PyQt是一个用于创建GUI应用程序的跨平台工具包,它将Python与Qt库融为一体。PyQt允许使用Python语言调用Qt库中的API。这样做的最大好处就是在保留了Qt高运行效率的同时,大大提高了开发效率。
pip install pyqt5-tools
即可同时安装 PyQt5 和一些重要的工具,比如 Qt designer。
from PyQt5.QtWidgets import QApplication, QMainWindow
#from PyQt5.Qt import * # 导入所有包
import sys
#创建应用程序对象
app = QApplication(sys.argv)
# 创建控件
window = QMainWindow()
# 设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle('第一个窗口')
# 展示控件
window.show()
sys.exit(app.exec_())
上面的代码把控件对应的变量名全部作为全局变量。如果要设计稍微复杂一些的程序,就会出现太多的控件对应的变量名。而且这样也不利于代码的模块化。所以,我们通常应该把 一个窗口和其包含的控件,对应的代码全部封装到类中,如下所示:
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
class Window():
def __init__(self):
self.window = QMainWindow()
self.window.resize(500, 400)
self.window.move(300, 300)
self.window.setWindowTitle('第一个窗口')
if __name__ == '__main__':
app = QApplication(sys.argv)
stats = Window()
stats.window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
作用:python文件通常有两种使用方法,第一是作为脚本直接执行,第二是 import 到其他的 python 脚本中被调用(模块重用)执行。因此 if __name__ == 'main':
的作用就是控制这两种情况执行代码的过程,在 if __name__ == 'main':
下的代码只有在第一种情况下(即文件作为脚本直接执行)才会被执行,而 import 到其他脚本中是不会被执行的,因此可以在if __name__ == 'main':
下放这个Python 文件的测试代码,即 import 到其他的 python 脚本中不会被执行的代码 。
面向对象就是在编程的时候尽可能的去模拟真实的现实世界,按照现实世界中的逻辑去处理一个问题,分析问题中参与其中的有哪些实体,这些实体应该有什么属性和方法,我们如何通过调用这些实体的属性和方法去解决问题。 面向过程就是面向解决问题的过程进行编程。是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数。
from PyQt5.QtWidgets import QApplication, QMainWindow,QLabel
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('第一个窗口')
self.setup_ui()
def setup_ui(self):
label = QLabel(self)
label.setText("这是一个标签")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
活动模板:很简单的一个示例,就是在 PyCharm 中输入 main 关键字,会自动带出一些默认的代码,这个就是活动模板配置
Pycharm 中 File -》Settings –> Editor –> Live Templates –> Python –>右上角“+”号
Pycharm 中 File –> Settings –> Editor –> File and Code Templates–> Python Script
# -*- coding: utf-8 -*-
"""
-------------------------------------------------
# @Project :${PROJECT_NAME}
# @File :${NAME}
# @Date :${DATE} ${TIME}
# @Author :作者名
# @Software :${PRODUCT_NAME}
-------------------------------------------------
"""
1、Ctrl+鼠标左键,点入到内置文件中,翻到类名处查看
2、 通过保留属性__base__
,返回的是直接继承关系
print(QWidget.__bases__) # 返回结果是元组
3、使用 mro()
,返回整个继承链条!
print(QObject.mro()) # 返回结果是列表
QObject 所有 Qt 对象的基类
API测试:
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QObject的学习")
self.resize(400, 400)
self.set_ui()
def set_ui(self):
self.QObject_test()
def QObject_test(self):
obj = QObject()
obj.setObjectName("jianjian")
print(obj.objectName())
obj.setProperty("notice_level", "error")
obj.setProperty("notice_level2", "warning")
print(obj.property("notice_level"))
print(obj.dynamicPropertyNames())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
输出:
1 jianjian
2 error
3 [PyQt5.QtCore.QByteArray(b'notice_level'), PyQt5.QtCore.QByteArray(b'notice_level2')]
QObejct.qss
QLabel#notice {
font-size :20px;
color :green;
border:1px solid gray;
border-radius:8px;
}
QLabel#notice[notice_level = "warning"] {
color :yellow;
border-color:yellow;
}
QLabel#notice[notice_level = "error"] {
color :red;
border-color:red;
}
test.py
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QObject的学习")
self.resize(300, 300)
self.set_ui()
def set_ui(self):
self.QObject_test()
def QObject_test(self): # 读取QObject.qss
with open("QObject.qss", "r") as f:
qApp.setStyleSheet(f.read())
label = QLabel(self)
label.setText("标签1")
label.setObjectName("notice")
label2 = QLabel(self)
label2.setText("标签2")
label2.move(100, 100)
label2.setObjectName("notice")
label2.setProperty("notice_level", "warning")
label3 = QLabel(self)
label3.setText("标签3")
label3.move(200, 200)
label3.setObjectName("notice")
label3.setProperty("notice_level","error")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
API测试:构造如下父子图
from PyQt5.Qt import *
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('父子对象')
self.set_ui()
def set_ui(self):
self.QObject_test()
def QObject_test(self):
obj0 = QObject()
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj4 = QObject()
obj5 = QObject()
# 打印各个对象变量 也可print('obj0:', obj0)
for i in range(6):
name = "obj" + str(i)
print(name,eval(name))
#设置父对象
obj1.setParent(obj0)
obj2.setParent(obj0)
obj3.setParent(obj1)
obj4.setParent(obj2)
obj5.setParent(obj2)
# 设置对象名称
obj2.setObjectName("2")
obj3.setObjectName("3")
# API测试结果
print('obj0父对象:', obj0.parent())
print('obj0所有直接子对象:', obj0.children())
print('obj0的第一个子对象:', obj0.findChild(QObject))
print('obj0的第二个子对象:', obj0.findChild(QObject,"2"))
print('obj0的第三个子对象(孙子):', obj0.findChild(QObject, "3", Qt.FindChildrenRecursively)) #递归(默认选项,可不写)
print('obj0的第三个子对象(孙子):', obj0.findChild(QObject, "3", Qt.FindDirectChildrenOnly)) #只查找直接子对象
print('obj0的所有子对象:', obj0.findChildren(QObject))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
输出:
obj0 <PyQt5.QtCore.QObject object at 0x000002749F7F33A8>
obj1 <PyQt5.QtCore.QObject object at 0x000002749F7F3438>
obj2 <PyQt5.QtCore.QObject object at 0x000002749F7F34C8>
obj3 <PyQt5.QtCore.QObject object at 0x000002749F7F3558>
obj4 <PyQt5.QtCore.QObject object at 0x000002749F7F35E8>
obj5 <PyQt5.QtCore.QObject object at 0x000002749F7F3678>
obj0父对象: None
obj0所有直接子对象: [<PyQt5.QtCore.QObject object at 0x000002749F7F3438>, <PyQt5.QtCore.QObject object at 0x000002749F7F34C8>]
obj0的第一个子对象: <PyQt5.QtCore.QObject object at 0x000002749F7F3438>
obj0的第二个子对象: <PyQt5.QtCore.QObject object at 0x000002749F7F34C8>
obj0的第三个子对象(孙子): <PyQt5.QtCore.QObject object at 0x000002749F7F3558>
obj0的第三个子对象(孙子): None
obj0的所有子对象: [<PyQt5.QtCore.QObject object at 0x000002749F7F3438>, <PyQt5.QtCore.QObject object at 0x000002749F7F3558>, <PyQt5.QtCore.QObject object at 0x000002749F7F34C8>, <PyQt5.QtCore.QObject object at 0x000002749F7F35E8>, <PyQt5.QtCore.QObject object at 0x000002749F7F3678>]
监听信号, 响应用户行为
案例一:点击按钮显示内容
from PyQt5.Qt import *
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('信号与槽')
self.setup_ui()
def setup_ui(self):
self.QObject_signal_test()
def QObject_signal_test(self):
btn = QPushButton(self)
btn.setText("点我呀")
def clicked_slot(self):
print("点我干啥")
btn.clicked.connect(clicked_slot)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
案例二:在所有修改的窗口标题前, 添加前缀”简简-“
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('信号与槽')
if __name__ == '__main__':
app = QApplication(sys.argv) # 创建应用程序对象
window = Window()
def windowTitleChanged_slot(arg):
print("修改的标题是:",arg) # arg为windowTitleChanged传回的参数
window.blockSignals(True) # 临时阻塞信号,不阻断将会陷入死循环
print("信号是否阻断:",window.signalsBlocked())
window.setWindowTitle("简简-"+ arg)
window.blockSignals(False) # 再次开启信号的连接,不开启的话只能成功添加一次前缀
print("信号是否阻断:", window.signalsBlocked())
window.windowTitleChanged.connect(windowTitleChanged_slot) # 连接信号和槽
window.setWindowTitle("测试")
window.setWindowTitle("测试2")
print("信号有{}个槽函数".format(window.receivers(window.windowTitleChanged)))
window.windowTitleChanged.disconnect() # 取消信号和槽之间的联系
window.setWindowTitle("测试3")
print("信号有{}个槽函数".format(window.receivers(window.windowTitleChanged)))
window.show() # 展示控件
sys.exit(app.exec_())
输出:
修改的标题是: 测试
信号是否阻断: True
信号是否阻断: False
修改的标题是: 测试2
信号是否阻断: True
信号是否阻断: False
信号有1个槽函数
信号有0个槽函数
API测试:
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('类型判定')
self.setup_ui()
def setup_ui(self):
self.QObject_type_judge()
def QObject_type_judge(self):
obj = QObject()
w = QWidget()
btn = QPushButton()
label = QLabel()
list = [obj, w, btn, label]
print("isWidgetType测试")
for i in list:
print("是否是控件类型:", i.isWidgetType())
print("inherits测试")
for i in list:
print("是否继承自QWidget:", i.inherits("QWidget"))
if __name__ == '__main__':
app = QApplication(sys.argv) # 创建应用程序对象
window = Window()
window.show() # 展示控件
sys.exit(app.exec_())
输出:
isWidgetType测试
是否是控件类型: False
是否是控件类型: True
是否是控件类型: True
是否是控件类型: True
inherits测试
是否继承自QWidget: False
是否继承自QWidget: True
是否继承自QWidget: True
是否继承自QWidget: True
过滤筛选控件
案例: 创建一个窗口, 包含多个QLabel或其他控件,将包含在窗口内所有的QLabel控件, 设置背景色cyan
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QObject的学习")
self.resize(400, 400)
self.set_ui()
def set_ui(self):
self.QObject_type_judge()
def QObject_type_judge(self):
label_1 = QLabel(self)
label_1.setText("标签1")
label_2 = QLabel(self)
label_2.setText("标签2")
label_2.move(100,100)
btn = QPushButton(self)
btn.setText("按钮")
btn.move(200,200)
for widget in self.children():
if widget.inherits("QLabel"):
widget.setStyleSheet("background-color:cyan;")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
API测试:
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('对象删除')
self.setup_ui()
def setup_ui(self):
self.QObject_delete()
def QObject_delete(self):
obj1 = QObject()
self.obj = obj1
obj2 = QObject()
obj3 = QObject()
obj3.setParent(obj2)
obj2.setParent(obj1)
obj1.destroyed.connect(lambda: print("obj1 被释放"))
obj2.destroyed.connect(lambda: print("obj2 被释放"))
obj3.destroyed.connect(lambda: print("obj3 被释放"))
# del obj2 # 这时候没有任何效果,因为obj2还被obj1引用着呢!
obj2.deleteLater() # 删除对象时,也会解除它与父对象的关系,而且是稍后删除。
print(obj1.children()) # 因为deleteLater是稍后删除,所以子节点还在
if __name__ == '__main__':
app = QApplication(sys.argv) # 创建应用程序对象
window = Window()
window.show() # 展示控件
sys.exit(app.exec_())
输出:
[<PyQt5.QtCore.QObject object at 0x0000022E610E45E8>]
obj2 被释放
obj3 被释放
想要移除某一个对象的时候使用
事件机制、拦截事件, 监听特定行为
案例
暂时欠着。。。
API测试
from PyQt5.Qt import *
import sys
class MyQObject(QObject): # 重写QObject()中的timerevent() 方法
def timerEvent(self,evnt):
print(evnt,"每隔一秒打印")
app = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle('定时器')
obj = MyQObject()
time_id = obj.startTimer(1000) # 每隔1s调用QObject() 中的timerevent() 方法 #所以此时应该重写QObject()中的timerevent() 方法
# obj.killTimer(time_id) #如果想停止它,将定时器id 传给 killTimer() 即可
window.show()
sys.exit(app.exec_())
输出:
<PyQt5.QtCore.QTimerEvent object at 0x000002081A182318> 每隔一秒打印
<PyQt5.QtCore.QTimerEvent object at 0x000002081A182318> 每隔一秒打印
<PyQt5.QtCore.QTimerEvent object at 0x000002081A182318> 每隔一秒打印
轮询、倒计时
案例1:创建一个窗口, 并设置一个子控件QLabel,展示10s倒计时,倒计时结束, 就停止计时。
from PyQt5.Qt import *
import sys
class MyLabel(QLabel): # 封装版本
def __init__(self, *args, **kwargs): # 这更加通用
super().__init__(*args, **kwargs)
self.setText("10")
self.setStyleSheet("font-size:22px;")
self.move(200, 200)
self.timer_id = self.startTimer(1000)
def timerEvent(self, *args, **kwargs):
# 获取当前的标签内容
print("开始计时")
current_sec = int(self.text())
current_sec -= 1
self.setText(str(current_sec))
if current_sec == 0:
self.killTimer(self.timer_id)
print("计时结束")
app = QApplication(sys.argv)
window = QMainWindow()
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle('定时器')
label = MyLabel(window)
window.show()
sys.exit(app.exec_())
案例2:创建一个窗口, 通过定时器不断增加该窗口的尺寸大小,每100ms 宽高均增加1px
from PyQt5.Qt import *
import sys
class MyWidget(QWidget):
def timerEvent(self, *args, **kwargs):
current_w = self.width()
current_h = self.height()
self.resize(current_w+10,current_h+10)
app = QApplication(sys.argv)
window = MyWidget()
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle('定时器')
window.startTimer(100)
window.show()
sys.exit(app.exec_())
所有的可视控件的基类
左上角为坐标原点,向右为x轴正方向,向下为y轴正方向
控件位置参照:
注意: 控件显示完毕之后, 具体的位置或者尺寸数据才会正确
from PyQt5.QtWidgets import QApplication, QWidget
import sys
app = QApplication(sys.argv)
window = QWidget()
window.resize(200, 200)
window.move(100, 100)
window.setWindowTitle('尺寸大小')
print(window.geometry()) # 输出: PyQt5.QtCore.QRect(100, 100, 200, 200) 错误
window.show()
print(window.geometry()) # 输出: PyQt5.QtCore.QRect(101, 131, 200, 200) 正确
sys.exit(app.exec_())
所以,要获取控件的尺寸,一定要在控件显示完毕之后再去获取!
点击按钮,复制标签内容,展示在标签后面
from PyQt5.QtWidgets import QApplication, QWidget,QPushButton,QLabel
import sys
app = QApplication(sys.argv)
window = QWidget()
window.resize(400, 400)
window.move(100, 100)
window.setWindowTitle('自适应尺寸')
label = QLabel(window)
label.setText("hello world")
label.move(100, 100)
label.setStyleSheet("background-color:cyan;") # 为了更清晰看到具体的区域
def addContent():
new_content = label.text() + "hello world"
label.setText(new_content)
# label.resize(label.width()+100,label.height()) 笨方法 改变大小
label.adjustSize() #自适应大小
btn = QPushButton(window)
btn.setText("增加内容")
btn.move(200, 200)
btn.clicked.connect(addContent)
window.show()
sys.exit(app.exec_())
通过给定的的个数,你负责在一个窗口内创建相应个数的子控件,按照九宫格的布局进行摆放
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
#创建app
app = QApplication(sys.argv)
window = QWidget()
window.show()
window.resize(500,500)
window.move(300,300)
#总控件的个数
widget_count = 10
#有多少列
column_count = 3
#一个控件的宽度
widget_width = window.width() / column_count
#有多少行
row_count = (widget_count-1) // column_count +1
#一个控件的高度
widget_height = window.height() / row_count
for i in range(widget_count):
w = QWidget(window)
w.resize(widget_width,widget_height)
# w.move(widget_width * (i % column_count), widget_height * (i // column_count))
x,y = divmod(i,column_count) # x,y = (i//column_count, i%column_count)
w.move(widget_width*y,widget_height*x)
w.setStyleSheet("background-color:red;border:1px solid yellow")
w.show()
sys.exit(app.exec_())
下载地址:https://jwt1399.lanzoui.com/iGnrtrz68fg
此工具对 Qwidget 尺寸大小位置 API 进行了全面使用,拖动窗口可实时显示相关位置信息。
创建一个窗口, 设置最小尺寸(200,200)和最大尺寸(400,400),测试通过resize是否可以改变
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
app = QApplication(sys.argv)
window = QMainWindow()
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle('最大最小尺寸')
window.setMinimumSize(200,200) #也可单独限制宽和高
window.setMaximumSize(400,400)
print(window.maximumSize())
window.resize(500,500) #通过代码也是无法修改的
print(window.maximumSize())
window.show()
sys.exit(app.exec_())
'''
输出:
PyQt5.QtCore.QSize(400, 400)
PyQt5.QtCore.QSize(400, 400)
'''
创建一个窗口, 包含一个标签,标签文本为”Hello World”,标签大小为(100, 60),将文本放在标签的右下角,默认文本显示是水平靠左,垂直居中的
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
window = QMainWindow()
window.resize(400, 400)
window.move(300, 300)
window.setWindowTitle('最大最小尺寸')
label = QLabel(window)
label.setText("Hello,world")
label.resize(200,200)
label.setStyleSheet("background-color:cyan;border:1px solid red")
label.setContentsMargins(100,100,0,0) # 设置内容边距,四个参数是边距,顺时针(左上右下)
print(label.getContentsMargins()) #打印各个边内容边距设置的具体值
print(label.contentsRect()) #打印各个边内容边距设置的具体值
window.show()
sys.exit(app.exec_())
'''
输出:
(100, 100, 0, 0)
PyQt5.QtCore.QRect(100, 100, 100, 100)
'''
显示和关闭事件
移动事件
调整大小
鼠标事件
键盘事件
焦点事件
拖拽事件
绘制事件
改变事件
右键菜单
输入法
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__() # 继承父类的init方法
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle('事件')
self.setup_ui()
def setup_ui(self):
pass
def showEvent(self, QShowEvent):
print("窗口被展示了")
def closeEvent(self,QCloseEvent):
print("窗口被关闭了")
def moveEvent(self,QMoveEvent):
print("窗口被移动了")
def resizeEvent(self, QSizeEvent):
print("窗口被改变了大小")
def enterEvent(self, QEvent):
print("鼠标进入")
def leaveEvent(self, QEvent):
print("鼠标离开")
def mousePressEvent(self, QMouseEvent):
print("鼠标按压")
def mouseMoveEvent(self, QMouseEvent):
print("鼠标按下移动")
if __name__ == '__main__':
app = QApplication(sys.argv) # 创建应用程序对象
window = Window()
window.setMouseTracking(True) # 设置鼠标追踪
window.show() # 展示控件
sys.exit(app.exec_())
。。。
除了以上系统提供参数,还可以自定义QCursor对象
鼠标跟踪
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
class MyWindow(QWidget):
def mouseMoveEvent(self, event): # 点击 QMouseEvent 可以查看里面包含的方法
# print("鼠标移动了",event.globalPos()) # globalPos() 是整个屏幕为准
print("鼠标移动了",event.localPos()) # localPos() 是控件本身为准
window = MyWindow()
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle('鼠标')
# window.setCursor(Qt.BusyCursor) #设置忙碌鼠标,转圈圈的样式
pixmap = QPixmap("C:/Users/admin/Pictures/centos.png").scaled(50,50) #设置鼠标样式和大小
cursor = QCursor(pixmap,0,0) #设置鼠标样式和热点,默认热点为图片中心(-1,-1),热点点击相应位置鼠标点击才会触发,修改为(0,0), 这就是图片的左上角成为热点。
window.setCursor(cursor)
# window.unsetCursor() # 重置鼠标形状,使上面的设置失效
current_cursor = window.cursor() #获取鼠标对象
print(current_cursor.pos()) #获取鼠标的位置,它是相对于整个电脑屏幕的
current_cursor.setPos(0,0) # 这时鼠标的位置在屏幕的左上角
window.setMouseTracking(True) #设置跟踪
print(window.hasMouseTracking()) #查看鼠标是否处于跟踪状态
window.show()
sys.exit(app.exec_())
。。。
下载地址:https://jwt1399.lanzoui.com/iy5gBrz6api
此工具对 QCursor 鼠标形状 API 进行了全面使用,选择对应单选框,可查看对应鼠标效果,还可自定义鼠标形状。
创建窗口, 包含若干 Label 控件,点击哪个标签, 就让哪个标签背景变红,使用父控件处理和自定义 QLabel 子类 两种方法实现
方法一:自定义 QLabel 子类
from PyQt5.Qt import *
import sys
class Label(QLabel):
def mousePressEvent(self, QMouseEvent):
self.setStyleSheet("background-color:red")
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("父子关系")
for i in range(10):
label = Label(window)
label.setText("标签"+str(i))
label.move(30*i,30*i)
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
方法二:使用父控件处理
from PyQt5.Qt import *
import sys
class Window(QWidget):
def mousePressEvent(self, event):
local_x = event.x()
local_y = event.y()
sub_widget = self.childAt(local_x,local_y) #子控件
if sub_widget: # 排除sub_widget 是None
sub_widget.setStyleSheet("background-color:red;")
#创建app
app = QApplication(sys.argv)
#创建控件
window = Window()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("父子关系")
for i in range(10):
label = QLabel(window)
label.setText("标签"+str(i))
label.move(30*i,30*i)
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
图标
标题
不透明度
窗口状态
最大化最小化
控制
窗口标志
windowFlags()
setWindowFlags(Qt.WindowStaysOnTopHint)
Qt.Widget #默认,一个窗口或控件,包含窗口边框、标题栏(图标、标题、最小化、最大化、关闭)
Qt.Window #一个窗口,包含窗口边框和标题栏(图标、标题、最小化、最大化、关闭)
Qt.Dialog #一个对话框窗口,窗口边框、标题栏(图标、标题、问号、关闭)
Qt.Sheet #一个窗口或部件Macintosh表单
Qt.Drawer #一个窗口或部件Macintosh抽屉
Qt.Popup #一个弹出式顶层窗口
Qt.Tool #一个工具窗口
Qt.ToolTip #一个提示窗口,没有标题栏和窗口边框
Qt.SplashScreen #一个欢迎窗口,是QSplashScreen构造函数的默认值
Qt.SubWindow #一个子窗口
Qt.MSWindowsFixedSizeDialogHint #窗口无法调整大小
Qt.FramelessWindowHint #窗口无边框
Qt.CustomizeWindowHint #有边框但无标题栏和按钮,不能移动和拖动
Qt.WindowTitleHint #添加标题栏和一个关闭按钮
Qt.WindowSystemMenuHint #添加系统目录和一个关闭按钮
Qt.WindowMaximizeButtonHint #激活最大化和关闭按钮,禁止最小化按钮
Qt.WindowMinimizeButtonHint #激活最小化和关闭按钮,禁止最大化按钮
Qt.WindowMinMaxButtonsHint #激活最小化,最大化和关闭按钮
Qt.WindowCloseButtonHint #添加一个关闭按钮
Qt.WindowContextHelpButtonHint #添加问号和关闭按钮,同对话框
Qt.WindowStaysOnTopHint #窗口始终处于顶层位置
Qt.WindowStaysOnBottomHint #窗口始终处于底层位置
通过 setWindowFlags来设置窗口的 WIndowFlags,多个 WindowFlags之间用 |
连接,如:
window = QWidget()
window.setWindowFlags(Qt.Tool | Qt.FramelessWindowHint)
取消某个 WindowFlags:
window.setWindowFlags(window.windowFlags() & ~Qt.FramelessWindowHint)
判断是否设置了某个 WindowFlags:
(widget.windowFlags() | Qt.FramelessWindowHint) == window.windowFlags()
from PyQt5.Qt import *
import sys
class Window(QWidget): #通过判定窗口的状态实现点击窗口切换最大和正常
def mousePressEvent(self, QMouseEvent):
if self.isMaximized():
self.showNormal()
else:
self.showMaximized()
#创建app
app = QApplication(sys.argv)
#创建控件
window = Window()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("顶层窗口相关") #设置标题
print(window.windowTitle()) #获取标题
window.setWindowIcon(QIcon("C:/Users/admin/Pictures/jj.ico")) #设置图标
print(window.windowIcon()) #获取图标
window.setWindowOpacity(0.8) #设置不透明度
print(window.windowOpacity()) #获取不透明度
print(window.windowState() == Qt.WindowNoState) # True 说明默认是无状态
window.setWindowState(Qt.WindowMinimized) #最小化
#展示控件
window.show()
# window.showMaximized() #展示最大,这时上面的window.show() 也可以不用要
# window.showFullScreen()
# window.showMinimized()
#进入消息循环
sys.exit(app.exec_())
创建一个窗口,要求无边框,无标题,窗口不透明度0.9,自定义最小化,最大化,关闭按钮,支持拖拽用户区移动。
from PyQt5.Qt import *
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.resize(500, 400)
self.move(300, 300)
self.setWindowTitle("顶层窗口操作案例")
self.setWindowFlags(Qt.FramelessWindowHint) # 无边框无标题
self.setWindowOpacity(0.9) # 不透明度
self.setup_ui()
def setup_ui(self):
self.btn_width = 40
self.btn_height = 25
self.top_margin = 0
self.add_close_max_min()
def add_close_max_min(self): # 添加三个按钮
self.close_btn = QPushButton(self)
self.close_btn.setText("关闭")
self.close_btn.resize(self.btn_width,self.btn_height)
self.max_btn = QPushButton(self)
self.max_btn.setText("最大")
self.max_btn.resize(self.btn_width, self.btn_height)
self.min_btn = QPushButton(self)
self.min_btn.setText("最小")
self.min_btn.resize(self.btn_width, self.btn_height)
def resizeEvent(self, QResizeEvent): #监听窗口大小的变化,计算按钮的位置。
self.close_btn.move(self.width() - self.close_btn.width(), self.top_margin)
self.max_btn.move(self.width() - 2 * self.close_btn.width(), self.top_margin)
self.min_btn.move(self.width() - 3 * self.close_btn.width(), self.top_margin)
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton: #按压鼠标左键
self.move_flags = True #移动标志
self.mouse_x = event.globalX()
self.mouse_y = event.globalY()
self.window_x = self.x()
self.window_y = self.y()
def mouseMoveEvent(self, event):
if self.move_flags: #当按压鼠标左键,才进行下方移动
self.move_x = event.globalX() - self.mouse_x
self.move_y = event.globalY() - self.mouse_y
self.move(self.window_x + self.move_x, self.window_y + self.move_y)
def mouseReleaseEvent(self, event):
self.move_flags = False
#创建app
app = QApplication(sys.argv)
#创建控件
window = Window()
# window = Window(flags=Qt.FramelessWindowHint) #初始化窗口设置Flags
def max_normal_change_slot(): #(最大化/正常)切换槽函数
if window.isMaximized():
window.showNormal()
window.max_btn.setText("最大")
else:
window.showMaximized()
window.max_btn.setText("恢复")
window.close_btn.pressed.connect(lambda: window.close())
window.min_btn.pressed.connect(lambda: window.showMinimized())
window.max_btn.pressed.connect(max_normal_change_slot)
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
下载地址:https://jwt1399.lanzoui.com/i6NwYrz69qd
此工具对窗口标志 API 进行了全面使用,选择对应窗口样式和顶层窗口外观标志,可查看对应窗口显示效果。
Qt官方也有类似的工具:
https://doc.qt.io/qt-5/qtwidgets-widgets-windowflags-example.html
。。。
状态提示
工具提示
这是啥提示
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow() # QMainWindow采用懒加载的方式(当控件用的时候才会加载上去)
window.statusBar() # 使用状态栏,状态栏显示
window.setWindowFlags(Qt.WindowContextHelpButtonHint) #换个带问号的窗口样式
label = QLabel(window)
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("信息提示")
label.setText("标签")
#设置状态提示
window.setStatusTip("这是一个窗口")
print(window.statusTip()) #获取提示信息
#设置工具提示
label.setToolTip("这是一个标签")
print(label.toolTip())
#设置工具提示时长
label.setToolTipDuration(2000) #设置提示时长为2s
print(label.toolTipDuration()) #获取提示时长
#设置这是啥提示
label.setWhatsThis("这是啥?这是标签") #点击右上角?号,再点击标签才显示
print(label.whatsThis()) #获取提示信息
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
单个控件角度
父控件角度
from PyQt5.Qt import *
import sys
class Window(QWidget):
def mousePressEvent(self, event):
# self.focusNextChild() #在子控件中切换焦点
# self.focusPreviousChild() #反序
self.focusNextPrevChild(False) # True 是前面的Next False 是后面的Prev
# print(self.focusWidget()) # 点击时获取它的子控件中获取焦点的那个
#创建app
app = QApplication(sys.argv)
#创建控件
window = Window()
lineEdit1 = QLineEdit(window)
lineEdit2 = QLineEdit(window)
lineEdit3 = QLineEdit(window)
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("焦点控制")
lineEdit1.move(100,50)
lineEdit2.move(100,100)
lineEdit3.move(100,150)
lineEdit2.setFocus() #先让第二个获取焦点
lineEdit3.setFocusPolicy(Qt.TabFocus) #第三个只能Tab键来获得焦点
# lineEdit2.clearFocus() #取消前面获得的焦点
print(window.focusWidget()) # 获取当前窗口的获取焦点的子控件
# tab 切换 2 1 3
Window.setTabOrder(lineEdit2,lineEdit1)
Window.setTabOrder(lineEdit1,lineEdit3)
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
所有按钮控件的基类
#查看是否自动重复
print(btn.autoRepeat())
#设置自动重复
btn.setAutoRepeat(True)
btn.setAutoRepeatDelay(2000) #初次检测延迟为2s
btn.setAutoRepeatInterval(1000) #重复检测间隔为1s
print(btn.autoRepeatDelay()) #首次延迟
print(btn.autoRepeatInterval()) #以后的触发间隔
案例:
设置只点击按钮中心的圆形区域才会有效
from PyQt5.Qt import *
import sys
class Btn(QPushButton):
def hitButton(self, point):
print("点击点坐标:", point) # 用户点击按钮之后,这个函数会将用户点击的点传出来
#圆心坐标
cir_x = self.width()/2
cir_y = self.height()/2
#鼠标点击点坐标
hit_x = point.x()
hit_y = point.y()
#点击点到圆心距离 > 半径
if pow(hit_x-cir_x,2)+pow(hit_y-cir_y,2) > pow(self.width()/2,2):
return False #代表点击无效,不会触发信号
return True #True代表用户点击的用效 ,会触发信号的发射
############################画内切圆###############################
def paintEvent(self, event):
super().paintEvent(event)
# 画家和纸
painter = QPainter(self) # 它里面的参数是 QPaintDevice “纸”
#给画家支笔
pen = QPen(QColor(100,10,155),4) #笔的颜色和宽度
painter.setPen(pen)
#画家开始画
painter.drawEllipse(self.rect()) #这就是两个点,四个值
############################画内切圆###############################
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("设置有效区域")
btn = Btn("按钮",window)
btn.resize(200,200)
btn.pressed.connect(lambda :print("按钮被点击"))
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("信号")
btn = QPushButton("按钮",window)
btn.move(200,200)
btn.pressed.connect(lambda :print("按钮被鼠标按下了"))
btn.released.connect(lambda :print("按钮被鼠标释放了"))
#clicked 往外传递一个参数,它表示的是当前按钮是否是被选中的状态:
btn.clicked.connect(lambda arg:print("按钮被鼠标点击了",arg))
#toggled也会往外传递个参数,用来反馈按钮是否被选中。(前提是按钮可以被选中,如果按钮本身不能被选中不会触发它。)
btn.toggled.connect(lambda arg:print("按钮选中状态发生改变",arg))
btn.setCheckable(True) #设置按钮可选中,不设的话 toggled 不会触发
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
QAbstractButton 的子类
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("按钮创建")
btn1 = QPushButton()
btn2 = QPushButton(window)
btn3 = QPushButton("按钮",window)
btn4 = QPushButton(QIcon("image/jj.ico"),"按钮",window)
btn1.move(200,50)
btn2.move(200,100)
btn3.move(200,150)
btn4.move(200,200)
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
应用场景:想通过快捷键触发按钮点击事件的时候设置
应用场景:可以设置点击按钮是弹出的菜单, 供用户选择
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("菜单")
############################菜单的设置###############################
btn = QPushButton("菜单",window)
menu = QMenu()
# 菜单之行为动作 新建,打开,退出
new_action = QAction(menu) # 父控件是menu
new_action.setText("新建")
new_action.setIcon(QIcon("image/jj.ico"))
new_action.triggered.connect(lambda: print("新建文件"))
open_action = QAction(menu) # 父控件是menu
open_action.setText("打开")
open_action.setIcon(QIcon("image/jj.ico"))
open_action.triggered.connect(lambda: print("打开文件"))
menu.addAction(new_action)
menu.addAction(open_action)
# 分割线
menu.addSeparator()
# 菜单之子菜单 最近打开
sub_menu = QMenu(menu)
sub_menu.setTitle("最近打开 ") # 注意不是setText
sub_menu.setIcon(QIcon("image/jj.ico"))
file_action = QAction("Python_Gui_编程")
sub_menu.addAction(file_action)
menu.addMenu(sub_menu)
btn.setMenu(menu)
############################菜单的设置###############################
###########################################################
# btn.showMenu() #此时,先展示的是菜单,它可以独自展示的,因为它直接继承的QWidget
###########################################################
#展示控件
window.show()
###########################################################
btn.showMenu() #此时,先展示的是窗口,然后再展示菜单
###########################################################
#进入消息循环
sys.exit(app.exec_())
应用场景:主要在对话框中,当我们打开一个对话框之后,可以设置默认处理的按钮。
都是继承下来的
命令链接是Windows Vista引入的新控件,命令链接按钮不应单独使用,而应作为向导和对话框中单选按钮的替代选项 QPushButton 的子类
创建
描述
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("QCommandLinkButton")
clbtn = QCommandLinkButton("标题","描述",window)
clbtn.resize(100,80)
# clbtn.setText("Python")
# clbtn.setDescription("hello world")
# clbtn.setIcon(QIcon("icon.ico"))
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
通常是在工具栏内部使用,工具按钮通常不显示文本标签,而是显示图标 QAbstractButton 的子类
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("QToolButton ")
tool_btn = QToolButton(window)
tool_btn.setText("工具按钮")
###########################当有图标显示时候,文本就不会显示了###############################
#它和QPushButton 的不同,就是在于它一般只显示图标,不显示文本
tool_btn.setIcon(QIcon("image/jj.ico"))
tool_btn.setIconSize(QSize(20,20))
############################当有图标显示时候,文本就不会显示了###############################
tool_btn.setToolTip("这是一个新建按钮")
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
tool_btn.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
print(tool_btn.toolButtonStyle()) # 输出:3
tool_btn.setArrowType(Qt.RightArrow) #注意,如果箭头和图标同时存在的话,箭头的优先级高
print(tool_btn.arrowType()) # 输出:4
tool_btn = QToolButton(window)
tool_btn.setIcon(QIcon("image/jj.ico"))
tool_btn.setIconSize(QSize(20,20))
tool_btn.setAutoRaise(True) #当鼠标放上去的时候,会有自动提升的效果
btn = QPushButton(window)
btn.setIcon(QIcon("image/jj.ico"))
btn.setIconSize(QSize(20,20))
btn.move(100,100)
btn.setFlat(True)#当鼠标放上去的时候,也不会提升上来。
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
tool_btn = QToolButton(window)
tool_btn.setText("工具按钮")
tool_btn.setIcon(QIcon("image/jj.ico"))
tool_btn.setIconSize(QSize(20,20))
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("QToolButton")
############################按钮设置菜单###############################
menu = QMenu(tool_btn)
new_action = QAction("新建")
menu.addAction(new_action)
open_action = QAction("打开")
menu.addAction(open_action)
menu.addSeparator()
sub_menu = QMenu(menu)
sub_menu.setTitle("子菜单")
relative_action = QAction("最近打开")
sub_menu.addAction(relative_action)
menu.addMenu(sub_menu)
tool_btn.setMenu(menu)
############################设置菜单###############################
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
但是 ,却不能点击显示菜单效果,这时因为有个东西要设置的。这里涉及到下面的菜单弹出模式
它的默认弹出模式是,按住一会才会弹出菜单。
tool_btn.setPopupMode(QToolButton.InstantPopup)
print(tool_btn.popupMode()) #输出:2
from PyQt5.Qt import *
import sys
#创建app
app = QApplication(sys.argv)
#创建控件
window = QMainWindow()
tool_btn = QToolButton(window)
tool_btn.setText("工具按钮")
tool_btn.setIcon(QIcon("image/jj.ico"))
tool_btn.setIconSize(QSize(20,20))
#设置控件
window.resize(500, 400)
window.move(300, 300)
window.setWindowTitle("QToolButton")
############################按钮设置菜单###############################
menu = QMenu(tool_btn)
new_action = QAction("新建")
menu.addAction(new_action)
new_action.setData("new") #绑定数据
open_action = QAction("打开")
menu.addAction(open_action)
open_action.setData("open") #绑定数据
menu.addSeparator()
sub_menu = QMenu(menu)
sub_menu.setTitle("子菜单")
relative_action = QAction("最近打开")
sub_menu.addAction(relative_action)
menu.addMenu(sub_menu)
tool_btn.setMenu(menu)
tool_btn.setPopupMode(QToolButton.InstantPopup)
############################设置菜单###############################
def tool_btn_triggered_slot(action):
if action.data() == "new":
print("你点击的是新建",action)
elif action.data() == "open":
print("你点击的是打开",action)
tool_btn.triggered.connect(tool_btn_triggered_slot)
#展示控件
window.show()
#进入消息循环
sys.exit(app.exec_())
一般用于给用户提供若干选项中的单选操作 QAbstractButton 的子类
radio_button_1 = QRadioButton("男",window)
radio_button_1.move(100,100)
radio_button_1.setIcon(QIcon("icon.ico"))
radio_button_1.setChecked(True) # 它是默认选中
radio_button_2 = QRadioButton("女",window)
radio_button_2.move(100,200)
radio_button_2.setIcon(QIcon("icon.ico"))
radio_button_2.toggled.connect(lambda :print("状态切换"))
提供 一个抽象的按钮容器, 可以将多个按钮划分为一组 QObject 的子类
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
#1,创建app
app = QApplication(sys.argv)
#2,控件的操作:
#创建控件
window = QWidget()
radio_button_1 = QRadioButton("男-Male",window)
radio_button_1.move(100,100)
radio_button_2 = QRadioButton("女-Famale",window)
radio_button_2.move(100,200)
radio_button_yes = QRadioButton("yes",window)
radio_button_yes.move(300,100)
radio_button_no = QRadioButton("yes",window)
radio_button_no.move(300,200)
#设置控件
window.setWindowTitle("QRadioButton")
window.resize(500,500)
###########################################################
sex_group = QButtonGroup(window)
sex_group.addButton(radio_button_1)
sex_group.addButton(radio_button_2)
###########################################################
###########################################################
judge_group = QButtonGroup(window)
judge_group.addButton(radio_button_yes,1) # 设置id=1
judge_group.addButton(radio_button_no,2) # 设置id=2
###########################################################
print(sex_group.buttons())
print(judge_group.button(1))
print(judge_group.checkedButton())
sex_group.removeButton(radio_button_2)
#展示控件
window.show()
#3,进入消息循环
sys.exit(app.exec_())
#****************************绑定id *******************************
sex_group.setId(radio_button_1,1)
sex_group.setId(radio_button_2,2)
#****************************绑定id *******************************
#****************************获取id *******************************
print(sex_group.id(radio_button_1))
print(sex_group.id(radio_button_2))
#****************************获取id *******************************
#****************************查看当前选中的按钮的id*******************
print(sex_group.checkedId())
#****************************查看当前选中的按钮的id*******************
#****************************将一个组的独占设置为否定*******************************
sex_group.setExclusive(False)
#****************************将一个组的独占设置为否定*******************************
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
#1,创建app
app = QApplication(sys.argv)
#2,控件的操作:
#创建控件
window = QWidget()
radio_button_1 = QRadioButton("男-Male",window)
radio_button_1.move(100,100)
radio_button_2 = QRadioButton("女-Famale",window)
radio_button_2.move(100,200)
radio_button_yes = QRadioButton("yes",window)
radio_button_yes.move(300,100)
radio_button_no = QRadioButton("yes",window)
radio_button_no.move(300,200)
#设置控件
window.setWindowTitle("QRadioButton")
window.resize(500,500)
###########################################################
sex_group = QButtonGroup(window)
sex_group.addButton(radio_button_1)
sex_group.addButton(radio_button_2)
###########################################################
###########################################################
judge_group = QButtonGroup(window)
judge_group.addButton(radio_button_yes,1) # 设置id=1
judge_group.addButton(radio_button_no,2) # 设置id=2
###########################################################
#****************************绑定id *******************************
sex_group.setId(radio_button_1,1)
sex_group.setId(radio_button_2,2)
#****************************绑定id *******************************
sex_group.buttonClicked.connect(lambda val:print(val)) #向外传出的是具体的按钮
sex_group.buttonClicked[int].connect(lambda val:print(val)) #向外传出的是按钮的id
sex_group.buttonClicked.connect(lambda val:print(val,sex_group.id(val))) # 当然获取了具体的按钮之后,自然很简单就可以获得它的id
#展示控件
window.show()
#3,进入消息循环
sys.exit(app.exec_())
一般用于给用户提供若干选项中的多选操作 QAbstractButton 的子类
checkbox1 = QCheckBox(window)
checkbox1.setText("Python")
checkbox1.move(50,30)
checkbox2 = QCheckBox(window)
checkbox2.setText("C++")
checkbox2.move(50,60)
checkbox3 = QCheckBox(window)
checkbox3.setText("C")
checkbox3.move(50,90)
checkbox1.setTristate(True)
print(checkbox1.isTristate())
checkbox2.setCheckState(Qt.PartiallyChecked) # 半选中状态
# checkbox2.setCheckState(Qt.Checked) #选中
# checkbox2.setCheckState(Qt.Unchecked) #未选中
它之所以多了个信号,是因为它有的时候是三态,所以之前的toggled 就不支持三态了。
checkbox1.setTristate(True)
checkbox1.stateChanged.connect(lambda state:print(state)) # 0,1,2
checkbox3.toggled.connect(lambda bool:print(bool)) # True,False
67-91
79-85 ???
92-93
94
95-130
131-140
141-143
144-151
152-160
261-295
296-327
Qt Designer 通过拖拽的方式放置控件可以随时查看控件效果,设计符合MVC的架构,实现了视图和逻辑的分离,从而实现了开发的便捷
为了不每次都在外部打开 QTDesigner,可以在 PyCharm 中配置快捷按钮,只需点击即可打开QTDesigner
操作步骤:点击设置–>工具–>外部工具–>点击“+”–>进行如下配置
Name:QTDesigner
Program:D:\Qt\Qt5.14.2\5.14.2\mingw73_32\bin\designer.exe # QTDesigner的位置
Working directory:$ProjectFileDir$ #当前项目文件目录
配置完成后,在 Pycharm 的菜单栏 Tools 或者右击——>External Tools——>QTDesigner,可以看到刚才配置菜单 QTDesigner,点击即可打开 QTDesigner
from PyQt5.QtWidgets import QApplication
from PyQt5 import uic
import sys
# 从文件中加载UI定义
app = QApplication(sys.argv)
ui = uic.loadUi("test.ui")
ui.show()
sys.exit(app.exec_())
1.执行如下的命令把 UI 文件直接转化为包含界面定义的Py文件
python -m PyQt5.uic.pyuic test.ui -o test.py -x
# -o 输出文件
# -x 生成if __name__ == "__main__":测试代码
2.然后在你的代码文件中这样使用定义界面的类
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
import test # ui文件转为py文件的文件名
app = QApplication(sys.argv)
window = QMainWindow()
ui = test.Ui_MainWindow() # py文件的类名
ui.setupUi(window)
window.show()
sys.exit(app.exec_())
为了不每次都执行 ui 转 py 代码,可以在 PyCharm 中配置快捷按钮,只需点击即可进行 ui 文件到 py 文件的转化。
操作步骤:点击设置–>工具–>外部工具–>点击“+”–>进行如下配置
Name:PyUIC
Program:D:\Python37\python.exe #python安装路径,要确保已经安装PyQt5
Arguments:-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$_ui.py -x #把ui文件转成同名py文件
Working directory:$FileDir$ #当前文件目录
配置完成后,在 Pycharm 的菜单栏 Tools 或者右击需要转换的ui文件——>External Tools——>PyUIC,点击 PyUIC 即可进行转换
可以在 PyCharm 中配置快捷按钮,只需点击即可进行 qrc 文件到 py 文件的转化。
操作步骤:点击设置–>工具–>外部工具–>点击“+”–>进行如下配置
Name:PyQrc
Program:D:\Python37\Scripts\pyrcc5.exe #pyrcc5路径,要确保已经安装PyQt5
Arguments:$FileName$ -o $FileNameWithoutExtension$_rc.py #把qrc文件转成同名py文件
Working directory:$FileDir$ #当前文件目录
配置完成后,在 Pycharm 的菜单栏 Tools 或者右击需要转换的qrc文件——>External Tools——>PyQrc,点击 PyQrc 即可进行转换
如果系统提供的信号不能满足我们的需求,这时就需要我们自定义信号 例如鼠标单击往往指的是左击,而不是右击,如果想要拥有右击信号,就需要自己自定义信号了!
在类的内部, 以类属性的形式定义
class Btn(QPushButton):
doubleClick = pyqtSignal()
doubleClick2 = pyqtSignal([int], [str])
QTDeasigner中使用自定义信号要将控件提升为自定义的类(Btn)
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
class Btn(QPushButton):
right_clicked = pyqtSignal([str],[int],[int,str]) #中括号的意思是重载
def mousePressEvent(self,event):
super().mousePressEvent(event)
if event.button() == Qt.RightButton: #右击时发射信号
self.right_clicked.emit(self.text()) #发射参数是str的信号
self.right_clicked[int,str].emit(100,self.text()) #发射参数是str和int的信号
self.right_clicked[int].emit(100) #发射参数是int的信号
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("信号的学习")
self.resize(400,400)
self.set_ui()
def set_ui(self):
btn = Btn("我是按钮",self)
btn.right_clicked.connect(lambda arg:print("右键被点击了",arg))
# btn.right_clicked[int,str].connect(lambda v1,arg :print("右键被点击了",v1,arg))
# btn.right_clicked[int].connect(lambda val:print(val))
if __name__ == '__main__':
app =QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
使用规则:
@pyqtSlot()
def on_objectName_信号名(self): # 名字是 on_$ObjectName$_$Singnal$
pass
示例:
from PyQt5 import QtCore
from PyQt5.Qt import *
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("装饰器连接信号和槽的学习")
self.resize(400, 400)
self.set_ui()
def set_ui(self):
btn = QPushButton("测试按钮", self)
btn.resize(200, 200)
btn.move(100, 100)
btn.setObjectName("btn")
QtCore.QMetaObject.connectSlotsByName(self) # 它一定要等到self中的对象创建完成
@pyqtSlot()
def on_btn_clicked(self): # 名字是 on_$ObjectName$_$Signal$
print("按钮被点击了")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
所有动画共享的功能,继承此类, 实现一些自定义动画
from PyQt5.Qt import * # 刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("动画的学习")
self.resize(400, 400)
self.set_ui()
def set_ui(self):
btn = QPushButton("按钮", self)
btn.resize(200, 200)
btn.move(100, 100)
btn.setStyleSheet("background-color:cyan;")
# 1, 创建一个动画对象 ,并且设置目标属性
animation = QPropertyAnimation(btn, b"pos", self)
# 2,设置属性值 包括 开始值 (插值) 结束值
animation.setStartValue(QPoint(0, 0))
animation.setKeyValueAt(0.5, QPoint(0, 200)) # 在动画时长的中间要插值
animation.setEndValue(QPoint(200, 200))
# 3,动画时长
animation.setDuration(2000) # 2s
# 4,启动动画
animation.start()
animation.setLoopCount(3) # 循环三遍
#时间操作
print("循环次数:", animation.loopCount())
print("单次时长:", animation.duration(), "总时长:", animation.totalDuration())
btn.clicked.connect(lambda: print("当前循环次数:", animation.currentLoop(),"当前循环次内的时长:", animation.currentLoopTime(), "当前动画运行时长:", animation.currentTime()))
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
"""
循环次数: 3
单次时长: 2000 总时长: 6000
当前循环次数: 0 当前循环次内的时长: 1456 当前动画运行时长: 1456
当前循环次数: 1 当前循环次内的时长: 1296 当前动画运行时长: 3296
当前循环次数: 2 当前循环次内的时长: 1328 当前动画运行时长: 5328
"""
0
动画的当前时间随着时间而增加(即,从0移动到结束/持续时间)1
动画的当前时间随着时间而减少(即,从结束/持续时间向0移动)# 动画方向设置一定要在启动动画之前
animation.setDirection(QAbstractAnimation.Backward)
print("动画方向:",animation.direction())
0
停止 1
暂停 2
运行案例:当用户点击按钮的时候,动画停止,再次点击时动画继续。
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("动画的学习")
self.resize(400,400)
self.set_ui()
def set_ui(self):
btn = QPushButton("按钮",self)
btn.resize(200,200)
btn.move(100,100)
btn.setStyleSheet("background-color:cyan;")
#1, 创建一个动画对象 ,并且设置目标属性
animation = QPropertyAnimation(btn,b"pos",self)
#2,设置属性值 包括 开始值 (插值) 结束值
animation.setStartValue(QPoint(0,0))
animation.setKeyValueAt(0.5,QPoint(0,200)) #在动画时长的中间要插值
animation.setEndValue(QPoint(200,200))
#3,动画时长
animation.setDuration(2000) #2s
#这里通过动画曲线,改变动画节奏:
animation.setEasingCurve(QEasingCurve.InOutBounce)
animation.setLoopCount(3) # 循环三遍
#动画方向设置一定要在 启动动画之前
animation.setDirection(QAbstractAnimation.Backward)
#4,启动动画
animation.start()
def btn_clicked_slot():
if animation.state() == QAbstractAnimation.Running:
animation.pause()
elif animation.state() == QAbstractAnimation.Paused:
animation.resume()
btn.clicked.connect(btn_clicked_slot)
if __name__ == '__main__':
app =QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
用于实现某个属性值从x到y的动画变化
方式1
animation = QPropertyAnimation(self)
animation.setTargetObject(btn) #对 btn 做动画
animation.setPropertyName(b"pos") #对btn 的 pos 属性做动画
方式2
animation = QPropertyAnimation(btn, b"pos", self)
常用属性
#对位置做动画
animation = QPropertyAnimation(btn,b"pos",self)
animation.setStartValue(QPoint(0,0))
animation.setEndValue(QPoint(300,300))
#对尺寸做动画
animation = QPropertyAnimation(btn,b"size",self)
animation.setStartValue(QSize(0,0))
animation.setEndValue(QSize(300,300))
#对位置和尺寸同时做动画
animation = QPropertyAnimation(btn,b"geometry",self)
animation.setStartValue(QRect(0,0,100,100))
animation.setEndValue(QRect(200,200,300,300))
#对透明度做动画
animation = QPropertyAnimation(self,b"windowOpacity",self)
animation.setStartValue(1)
animation.setEndValue(0.5)
animation.setStartValue(QSize(0,0))
animation.setKeyValueAt(0.5,QPoint(0,200)) #在动画时长的中间要插值
animation.setEndValue(QSize(200,200))
animation.setDuration(2000) #2s
#这里通过动画曲线,改变动画节奏:
animation.setEasingCurve(QEasingCurve.InOutBounce)
#启动动画
animation.start()
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("动画的学习")
self.resize(400,400)
self.set_ui()
def set_ui(self):
btn = QPushButton("按钮",self)
btn.resize(200,200)
btn.move(100,100)
btn.setStyleSheet("background-color:cyan;")
#1, 创建一个动画对象 ,并且设置目标属性
animation = QPropertyAnimation(btn,b"pos",self) #可一起写,对象,属性
# animation.setTargetObject(btn) #对 btn 做动画
# animation.setPropertyName(b"pos") #对btn 的 pos 属性做动画
#2,设置属性值 包括 开始值 (插值) 结束值
animation.setStartValue(QPoint(0,0))
animation.setKeyValueAt(0.5,QPoint(0,200)) #在动画时长的中间要插值
animation.setEndValue(QPoint(200,200))
#3,动画时长
animation.setDuration(2000) #2s
#这里通过动画曲线,改变动画节奏:
animation.setEasingCurve(QEasingCurve.InOutBounce)
#4,启动动画
animation.start()
if __name__ == '__main__':
app =QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
暂停动画, 在串行动画中使用
可以将一组动画, 同时播放或者按顺序播放
添加动画
移除动画
获取动画
获取并移除
动画个数
清空动画
并行动画,多个动画同时执行
串行动画,多个动画先后执行
from PyQt5.Qt import * #刚开始学习可以这样一下导入
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("动画组的学习")
self.resize(800,800)
self.set_ui()
def set_ui(self):
red_btn = QPushButton("红色按钮",self)
green_btn = QPushButton("绿色按钮",self)
red_btn.resize(100,100)
green_btn.resize(100,100)
green_btn.move(150,150)
red_btn.setStyleSheet("background-color:red;")
green_btn.setStyleSheet("background-color:green;")
#动画设置
animation_green = QPropertyAnimation(green_btn,b"pos",self)
animation_green.setKeyValueAt(0,QPoint(150,150))
animation_green.setKeyValueAt(0.25,QPoint(550,150))
animation_green.setKeyValueAt(0.5,QPoint(550,550))
animation_green.setKeyValueAt(0.75,QPoint(150,550))
animation_green.setKeyValueAt(1,QPoint(150,150))
animation_green.setDuration(2000)
#animation_green.start() # 动画不是阻塞的,动画运行时会继续往下运行
###########################################################
animation_red = QPropertyAnimation(red_btn,b"pos",self)
animation_red.setKeyValueAt(0,QPoint(0,0))
animation_red.setKeyValueAt(0.25,QPoint(0,700))
animation_red.setKeyValueAt(0.5,QPoint(700,700))
animation_red.setKeyValueAt(0.75,QPoint(700,0))
animation_red.setKeyValueAt(1,QPoint(0,0))
animation_red.setDuration(2000)
#animation_red.start()
#用串行动画组来管理上面两个动画
animation_group = QSequentialAnimationGroup(self)
animation_group.addAnimation(animation_red)
animation_group.addAnimation(animation_green)
animation_group.start()
#用并行动画组来管理上面两个动画
# animation_group = QParallelAnimationGroup(self)
# animation_group.addAnimation(animation_red)
# animation_group.addAnimation(animation_green)
# animation_group.start()
if __name__ == '__main__':
app =QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
案例:第一个动画执行执行完 5s 之后再执行第二个
方法一:使用addPause
#用动画组来管理上面两个动画
animation_group = QSequentialAnimationGroup(self)
animation_group.addAnimation(animation_red)
#############################设置暂停时长##############################
animation_group.addPause(5000) # 只有串行中才会有这个设置 暂停5s
#############################设置暂停时长##############################
animation_group.addAnimation(animation_green)
animation_group.start()
方法二:使用QPauseAnimation
#用动画组来管理上面两个动画
animation_group = QSequentialAnimationGroup(self)
animation_group.addAnimation(animation_red)
#############################设置暂停时长##############################
pause_animation = QPauseAnimation()
pause_animation.setDuration(5000)
animation_group.addAnimation(pause_animation)
#############################设置暂停时长##############################
animation_group.addAnimation(animation_green)
animation_group.start()
358
注:标题后含 “*” 号,说明该内容还未写完,eg:“事件*
”