PySide6使用QProcess批量执行SVN命令时界面冻结、输出混杂求助
解决方案
核心思路
基于Qt原生的信号槽异步机制实现串行任务调度,完全移除阻塞式的waitForFinished调用,既保证svn命令按顺序执行、输出不混杂,也不会阻塞GUI事件循环,避免界面冻结。
- 用队列存储所有待执行的任务,前一个任务执行完成后通过
finished信号自动触发下一个任务 - 全程无阻塞逻辑,主事件循环正常运行,GUI操作不会卡顿
关键修改点
- 移除所有
waitForFinished调用 - 新增任务队列实现串行调度:
wc_queue存储所有待处理的工作副本路径,sub_task_queue存储当前工作副本下待执行的add/rm/commit子任务 - QProcess绑定为实例属性,避免局部变量被Python垃圾回收导致信号丢失
- 每个操作的结果处理、下一个任务的触发都通过信号槽绑定实现
修改后完整代码
import os, sys from PySide6 import QtCore, QtWidgets, QtGui from PySide6.QtWidgets import QDialog from app.ui.pages.commit import Ui_Dialog class Commit_All(QDialog, Ui_Dialog): def __init__(self, parent=None, work_path='', qss=''): super().__init__(parent=parent) self.work_path = work_path self.qss = qss # 任务队列 self.wc_queue = [] # 待处理的工作副本队列 self.sub_task_queue = [] # 当前工作副本的子任务队列 self.current_wc = None # 当前处理的工作副本 self.current_process = None # 当前运行的QProcess self.setupUi(self) self.setStyleSheet(self.qss) self.setWindowIcon(QtGui.QIcon(QtGui.QPixmap(':icon.ico'))) self.connectSignalsSlots() self.commit_plain.setReadOnly(True) self.finish_btn.setEnabled(False) self.commit_plain.appendPlainText('Starting Commit\n') # 初始化工作副本队列 for wc_name in os.listdir(self.work_path): wc_path = os.path.join(self.work_path, wc_name) if os.path.isdir(wc_path): # 只处理文件夹 self.wc_queue.append(wc_path) # 启动第一个任务 self.process_next_wc() def connectSignalsSlots(self): self.finish_btn.clicked.connect(self.close) def process_next_wc(self): """处理下一个工作副本""" if not self.wc_queue: # 所有任务完成 self.message("\n===== 全部项目提交完成 =====") self.finish_btn.setEnabled(True) return self.current_wc = self.wc_queue.pop(0) self.sub_task_queue.clear() self.finish_btn.setEnabled(False) # 先执行svn status检查 self.current_process = QtCore.QProcess(self) self.current_process.setProgram("svn") self.current_process.setArguments(['st', self.current_wc]) self.current_process.finished.connect(self.handle_svn_st_finished) self.current_process.start() def handle_svn_st_finished(self): """处理svn status的返回结果""" output = bytes(self.current_process.readAll()).decode("latin1") self.current_process.deleteLater() self.current_process = None if not output.strip(): self.message(f'Project {os.path.basename(self.current_wc)} 无变更,跳过提交\n') self.process_next_wc() return # 解析status结果,生成add/rm子任务 for status in output.splitlines(): status_flag = status[:1] item_path = status[8:].strip() if status_flag == '!': self.sub_task_queue.append(('rm', item_path)) elif status_flag == '?': self.sub_task_queue.append(('add', item_path)) # 最后添加commit任务 msg = f'--> auto commit Proj. {os.path.basename(self.current_wc)}' self.sub_task_queue.append(('commit', self.current_wc, msg)) # 开始执行子任务 self.process_next_sub_task() def process_next_sub_task(self): """处理当前工作副本的下一个子任务""" if not self.sub_task_queue: # 当前工作副本所有子任务完成 self.message(f'\nProject {os.path.basename(self.current_wc)} 提交完成!\n') self.process_next_wc() return task = self.sub_task_queue.pop(0) task_type = task[0] self.current_process = QtCore.QProcess(self) self.current_process.readyReadStandardOutput.connect(self.handle_stdout) self.current_process.readyReadStandardError.connect(self.handle_stderr) if task_type == 'add': item_path = task[1] self.current_process.setProgram("svn") self.current_process.setArguments(['add', item_path, '--force']) self.current_process.finished.connect(self.process_next_sub_task) elif task_type == 'rm': item_path = task[1] self.current_process.setProgram("svn") self.current_process.setArguments(['rm', item_path]) self.current_process.finished.connect(self.process_next_sub_task) elif task_type == 'commit': wc_path, msg = task[1], task[2] self.current_process.setProgram("svn") self.current_process.setArguments(['ci', wc_path, '-m', msg]) self.current_process.finished.connect(self.process_next_sub_task) self.current_process.start() def message(self, s): self.commit_plain.appendPlainText(s) def handle_stderr(self): data = self.current_process.readAllStandardError() stderr = bytes(data).decode("latin1") self.message(stderr) def handle_stdout(self): data = self.current_process.readAllStandardOutput() stdout = bytes(data).decode("latin1") stdout = stdout.rstrip('\r\n') if stdout: self.message(stdout)
内容的提问来源于stack exchange,提问作者Christoph
相关产品推荐
相关产品推荐

