Python可视化模块(PyQt5)的快速入门(一)
PyQt5
通过Python去开发一个可视化界面的工具,需要用到GUI的库。我选择了PyQt5,但是我从未接触过,所以进行一番学习
写在前面,基本是各种查阅资料,各种学。有点问题部分希望大家提出相互交流,共同进步,在此拜谢!
前两天由于电脑被公司的流氓软件劫持了···(再次不细说了,都是泪),所以重装了系统。外加我本人还去秦皇岛玩了一圈嘿嘿。耽搁了一些更新的时间
简单介绍 : PyQt5是基于Qt框架的Python绑定。它使Python开发者能够构建一个桌面程序
-
安装PyQt5
pip install PyQt5 -
一段简单的PyQt5代码
import sys from PyQt5.QtWidgets import QApplication, QWidget app = QApplication(sys.argv) # 创建应用对象(系统环境初始化) window = QWidget() # 创建窗口 window.show() # 显示窗口 sys.exit(app.exec_()) # 启动事件循环,保持窗口响应,直到用户关闭窗口在这里
app = QApplication(sys.argv) # 创建应用对象(系统环境初始化)这个是所有PyQt5的第一步
QApplication,是应用的引擎:
-
控制整个应用的运行
-
管理程序的界面事件循环(event loop)
-
处理窗口控件、键盘、鼠标等事件
-
管理GUI的资源与状态
sys.argv:
- 传递外部参数给应用chengxu
- 如果给命令行运行程序,可以通过sys.argv接受
sys.exit(app.exec_()) # 启动事件循环,保持窗口响应,直到用户关闭窗口这个是所有GUI程序的主事件循环入口
app.exec_()
- 启动事件循环:监听点击、用户输入、相应按钮动作
- 没有它,窗口就一闪而过了,程序直接推出
sys.exit_()
- 将sys.exec_的返回值传给操作系统
- 告知系统我已退出,有没有问题
-
-
基础控件大全(其实也不是很全)
控件类型 类名 说明 标签 QLabel 显示文本或图片 输入框 QLineEdit 用户输入一行文本 多行文本框 QTextEdit 输入多行文本 按钮 QPushButton 点击触发事件 下拉选择框 QComboBox 选择项 复选框 QCheckBox 多选项 单选按钮 QRadioButton 单选项 -
信号与槽(事件机制)
信号:事件发出------按钮被点击
槽: 事件处理器-----定义的函数
核心:
1.信号发出者不需要知道槽函数是如何实现的,只是负责“广播事件”,槽负责响应事件。(解耦)
2.信号随时发出,执行看事件的循环机制(异步执行)
一个信号可以连接多个槽函数
多个信号触发一个槽也行
举个栗子:
# 连接按钮的点击信号到槽函数 self.button.clicked.connect(self.update_label) # 这里的self.button.clicked就是信号 # 这里的self.update_label就可以理解为槽函数,用于响应信号注意:可以自定义信号与槽
通过
pyqtSignal来创建自定义信号from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtWidgets import QApplication, QLabel, QPushButton, QVBoxLayout, QWidget import sys class MyObject(QObject): # 创建一个自定义信号 custom_signal = pyqtSignal(str) def __init__(self): super().__init__() def trigger_signal(self, message): self.custom_signal.emit(message) class MyWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle("自定义信号示例") self.resize(300, 150) self.label = QLabel("等待消息...") self.button = QPushButton("触发信号") layout = QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.button) self.setLayout(layout) # 实例化 MyObject 类 self.my_object = MyObject() # 连接自定义信号到槽函数 self.my_object.custom_signal.connect(self.update_label) # 按钮点击触发信号 self.button.clicked.connect(lambda: self.my_object.trigger_signal("自定义信号触发!")) def update_label(self, message): self.label.setText(message) app = QApplication(sys.argv) win = MyWindow() win.show() sys.exit(app.exec_()) -
布局管理
layout = QVBoxLayout()创建一个垂直布局管理器
可以把布局想象成一个空房间,把控件丢进去就会自己整齐排好
布局类 说明 QVBoxLayout 垂直布局 QHBoxLayout 水平布局 QGridLayout 网格布局 -
多线程(重点)
应用背景:PyQt程序运行时,若需要执行一个耗时操作(读取大文件、联网、图片处理、延时循环等等),并且这些操作是在主线程(GUI线程)进行的,则会产生:
- 窗口卡顿
- 无响应提示
- 界面无法点击/无法关闭
PyQt有两种线程支持方式:
- QThread(推荐,支持信号机制)⭐⭐⭐⭐⭐
- threading.Thread(Python原生线程,与QT不兼容)
可以理解为:
主线程:画画的人(维持页面稳定)
子线程:干活的人(读取、计算、下载)
形象理解-----------如果你要让画画的人去干活,那画面就卡住了
import sys from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton # 创建一个工作线程类 class MyThread(QThread): countChanged = pyqtSignal(int) # 定义信号,发送整数 def run(self): for i in range(1, 11): self.sleep(1) # 模拟耗时任务 self.countChanged.emit(i) # 每次发出一个信号 # 主界面 class MyWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle("多线程演示") self.resize(300, 150) self.label = QLabel("点击开始计数") self.button = QPushButton("开始") layout = QVBoxLayout() layout.addWidget(self.label) layout.addWidget(self.button) self.setLayout(layout) # 实例化线程 self.thread = MyThread() # 绑定信号与槽函数 self.thread.countChanged.connect(self.update_label) self.button.clicked.connect(self.start_thread) def update_label(self, value): self.label.setText(f"计数:{value}") def start_thread(self): if not self.thread.isRunning(): self.thread.start() app = QApplication(sys.argv) win = MyWindow() win.show() sys.exit(app.exec_())需要注意的是:GUI更新必须在主线程
-
subprocess
subprocess是用来让Python调用外部命令或程序的工具,而在PyQt多线程中,使用它,是为了让外部调用不阻塞主界面,配合QThread来异步执行命令行任务。
能干什么?
- shell命令
- 启动外部程序
- 获取紫禁城的输出、错误信息
- 向子进程传入输入
- 控制子进程的超时、管道、环境变量等
subprocess.run()----比Popen()简单
import subprocess result = subprocess.run(["ls"], capture_output=True, text=True) print(result.stdout) #capture_output=True:自动捕获 stdout 和 stderr #text=True:表示返回的是字符串(不是 bytes) subprocess.run(["echo", "Hello, World!"]) #["echo", "Hello, World!"] 是一个列表,第一个是命令,其余是参数。subprocess.Popen()-----------高级些(看了基本结构,确实是复杂了些)
import subprocess process = subprocess.Popen( args, # 命令和参数(列表) stdin=subprocess.PIPE, # 向子进程输入数据 stdout=subprocess.PIPE, # 从子进程获取输出 stderr=subprocess.PIPE, # 获取子进程的错误输出 text=True, # 设置文本模式(返回字符串,而不是字节) cwd=None, # 设置子进程的工作目录 env=None, # 设置子进程的环境变量 bufsize=-1, # 设置缓冲区大小(通常不用设置) universal_newlines=True # 自动处理换行符 )例子①读取输出
import subprocess # 启动子进程,执行命令并获取输出 process = subprocess.Popen( ["ls", "-l"], # 命令及参数 stdout=subprocess.PIPE, # 获取标准输出 stderr=subprocess.PIPE, # 获取标准错误输出 text=True # 使得输出为字符串 ) # 从子进程读取输出 stdout, stderr = process.communicate() # 打印结果 print("标准输出:", stdout) print("标准错误:", stderr)process.communicate()会等待子进程结束并返回它的输出结果。它会将标准输出和标准错误捕获并返回。stdout为标准输出,stderr为错误输出。例子②通过stdin向子进程输入数据
import subprocess # 启动子进程,执行命令 process = subprocess.Popen( ["python", "-c", "import sys; sys.stdin.read()"], stdin=subprocess.PIPE, # 向子进程发送输入数据 stdout=subprocess.PIPE, # 获取标准输出 text=True ) # 向子进程输入数据 output, _ = process.communicate(input="Hello from subprocess!") # 输出结果 print("子进程输出:", output)例子③实时读取输出(长时间运行的任务)
import subprocess # 启动子进程 process = subprocess.Popen( ["ping", "www.baidu.com", "-t"], # Windows 上持续 ping stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) # 实时读取输出 for line in process.stdout: print("Ping 输出:", line.strip())不要忘记
.communicate()Popen是一个异步操作,执行后不会等待子进程结束。如果你不调用.communicate(),子进程的输出可能不会被捕获。

浙公网安备 33010602011771号