QProcess 是 Qt 框架中用于启动外部程序并与其交互的核心类。主要功能包括:
需明确指定程序路径和参数,避免直接传递完整命令字符串(旧版已弃用):
from PySide6.QtCore import QProcess
process = QProcess()
process.setProgram("python3") # 设置程序路径
process.setArguments(["-i"]) # 设置参数(如交互模式)
process.start() # 启动进程
⚠️ 注意:旧版 start("python dummy.py")
已弃用,需分离程序名和参数 。
通过信号与槽机制实现异步通信,避免阻塞主线程:
# 连接输出信号到处理函数
process.readyReadStandardOutput.connect(handle_stdout)
process.readyReadStandardError.connect(handle_stderr)
def handle_stdout():
data = process.readAllStandardOutput()
print("标准输出:", data.data().decode())
def handle_stderr():
data = process.readAllStandardError()
print("错误输出:", data.data().decode())
信号绑定:监听进程启动、结束和错误事件:
process.started.connect(lambda: print("进程已启动"))
process.finished.connect(lambda: print("进程结束,退出码:", process.exitCode()))
process.errorOccurred.connect(lambda err: print("错误发生:", err))
状态查询:通过 state()
获取当前状态(QProcess.NotRunning
、QProcess.Running
)。
强制终止:
terminate()
:发送终止信号(允许进程清理资源)。kill()
:立即终止进程(可能残留资源)。if process.state() == QProcess.Running:
process.terminate()
process.waitForFinished(3000) # 最多等待3秒
deleteLater()
延迟删除对象:process.finished.connect(process.deleteLater)
QThread 是 Qt 提供的跨平台线程管理类,用于将耗时任务从主线程(GUI 线程)中分离,避免界面卡顿。其核心功能包括线程创建、任务执行、线程间通信及资源管理。
适用场景:任务逻辑简单且独立,无需频繁交互。
实现步骤:
from PySide6.QtCore import QThread, Signal
class WorkerThread(QThread):
finished = Signal(str) # 自定义信号
def run(self):
result = "Task completed" # 耗时操作
self.finished.emit(result) # 发射信号
# 使用示例
thread = WorkerThread()
thread.finished.connect(handle_result) # 连接信号到处理函数
thread.start() # 启动线程
特点:
线程逻辑直接封装在 run() 中。
线程结束后需调用 quit() 和 wait() 释放资源
适用场景:任务复杂、需与主线程频繁交互或需要灵活控制生命周期。
实现步骤:
from PySide6.QtCore import QObject, QThread, Signal
class Worker(QObject):
finished = Signal(str)
def do_work(self):
result = "Task completed" # 耗时操作
self.finished.emit(result)
# 创建对象和线程
worker = Worker()
thread = QThread()
worker.moveToThread(thread) # 将任务对象移入子线程
# 信号与槽连接
thread.started.connect(worker.do_work)
worker.finished.connect(thread.quit) # 完成后退出线程
worker.finished.connect(worker.deleteLater) # 释放资源
thread.finished.connect(thread.deleteLater)
thread.start() # 启动线程
特点:
任务逻辑与线程管理分离,代码更清晰。
通过信号槽机制实现线程间安全通信,避免直接操作 GUI
核心信号:
started:线程启动时发射。
finished:线程结束时发射。
自定义信号(如进度更新、结果返回等)
跨线程通信示例:
class Worker(QObject):
progress = Signal(int)
finished = Signal(str)
def long_task(self):
for i in range(100):
time.sleep(0.1)
self.progress.emit(i + 1) # 发射进度信号
self.finished.emit("Completed")
# 主线程连接信号
worker.progress.connect(update_progress_bar)
worker.finished.connect(show_result)
线程的完整生命周期包括创建、启动、运行、等待、完成和销毁六个阶段:
创建:实例化 QThread 和任务对象。
启动:调用 start() 进入运行状态。
运行:执行 run() 或绑定的任务函数。
等待:通过 wait() 阻塞主线程直到子线程结束。
完成:发射 finished 信号。
销毁:
调用 quit() 退出线程。
调用 wait() 确保资源释放。
使用 deleteLater() 延迟删除对象 。
以下是一个简单的 QThread 示例,展示了如何通过子类化 QThread 来管理线程生命周期:
from PySide6.QtCore import QThread, Signal
import time
class WorkerThread(QThread):
finished = Signal(str) # 自定义信号,用于传递任务完成信息
def run(self):
# 模拟耗时操作
for i in range(5):
print(f"Worker thread is running: {i}")
time.sleep(1)
self.finished.emit("Task completed") # 发射信号,表示任务完成
# 创建并启动线程
thread = WorkerThread()
thread.finished.connect(lambda msg: print(f"Thread finished: {msg}"))
thread.finished.connect(thread.deleteLater) # 线程完成后自动销毁
thread.start()
# 阻塞主线程,等待子线程完成
thread.wait()
print("Main thread continues after thread completion")
示例说明:
创建线程:通过继承 QThread,定义 WorkerThread 类,并在 run() 方法中模拟耗时任务。
启动线程:调用 thread.start() 启动线程。
线程运行:run() 方法中执行任务,并通过 time.sleep(1) 模拟耗时操作。
线程完成:任务完成后,通过 finished.emit() 发射信号。
销毁线程:finished.connect(thread.deleteLater) 确保线程完成后自动销毁
subprocess
是 Python 用于执行外部命令和进程管理的核心模块,提供了更灵活的子进程控制方式。
subprocess模块定义了一个类: Popen,具体如下所示:
class subprocess.Popen( args,bufsize=0,
executable=None,
stdin=None,
stdout=None,
stderr=None,
preexec_fn=None,
close_fds=False,
shell=False,
cwd=None,
env=None,
universal_newlines=False,
startupinfo=None,
creationflags=0)
下面我将重点介绍一下stdin stdout和stderr:
stdin stdout和stderr,分别表示子程序的标准输入、标准输出和标准错误。可选的值有PIPE或者一个有效的文件描述符(其实是个正整数)或者一个文件对象,还有None。如果是PIPE,则表示需要创建一个新的管道,如果是None,不会做任何重定向工作,子进程的文件描述符会继承父进程的。另外,stderr的值还可以是STDOUT,表示子进程的标准错误也输出到标准输出。
可以通过下面的代码实现实时读取输出:用到了stdout
while True:
output = process.stdout.readline()
if not output and process.poll() is not None:
break
print(output.strip())
通过下面的代码实现错误处理:
try:
subprocess.check_call(["invalid_command"]) # 非零退出码时抛异常
except subprocess.CalledProcessError as e:
print(f"Error: {e}")
subprocess.run
(推荐):简化版,自动等待命令完成。 使用 subprocess
运行 Python 脚本并捕获错误:
try:
result = subprocess.run(
["python", "train.py"],
check=True,
capture_output=True,
text=True
)
except subprocess.CalledProcessError as e:
print(f"训练失败: {e.stderr}")
下面是上述三种方法的对比说明: