1+ import os .path
12from sys import getdefaultencoding
23from typing import Optional , Sequence
34
45from PySide6 import QtCore
56
67
78class SubProcessTool (QtCore .QObject ):
8- """辅助使用QProcess创建并管理子进程的工具类 """
9+ """辅助QProcess使用的工具类,将所有直接对子进程进行的操作都封装在此类中 """
910
1011 # 自定义信号,参数为 tuple[output_type: SubProcessTool.output_type, output_text: str]
1112 output = QtCore .Signal (tuple )
1213
1314 # output_types
14- STATE = 0
15- FINISHED = 1
15+ STATE = 1
1616 STDOUT = 2
1717 STDERR = 3
18+ FINISHED = 4
19+
20+ def __init__ (
21+ self ,
22+ parent : Optional [QtCore .QObject ] = None ,
23+ * ,
24+ program : str = "" ,
25+ arguments : Sequence [str ] = (),
26+ working_directory : str = "./" ,
27+ ) -> None :
28+ """
29+ :param parent: 父对象
30+ :param program: 待运行的子进程
31+ :param arguments: 运行参数
32+ :param working_directory: 子进程工作目录
33+ :return: None
34+ """
1835
19- def __init__ (self , parent : Optional [QtCore .QObject ] = None ) -> None :
2036 super (SubProcessTool , self ).__init__ (parent )
21- self .process : Optional [QtCore .QProcess ] = None
2237
23- def start_process (self , program : str , arguments : Sequence [str ]) -> None :
38+ self .program : str = program
39+ self ._arguments : Sequence [str ] = arguments
40+ self ._working_directory : str = working_directory
41+ self ._process : Optional [QtCore .QProcess ] = None
42+ self .exit_code : int = 0
43+ self .exit_status : QtCore .QProcess .ExitStatus = QtCore .QProcess .NormalExit
44+
45+ def start_process (
46+ self ,
47+ * ,
48+ mode : QtCore .QIODeviceBase .OpenMode = QtCore .QIODeviceBase .OpenModeFlag .ReadWrite , # type: ignore
49+ ) -> None :
50+ """
51+ 创建并启动子进程 \n
52+ :param mode: 设备打开的模式
53+ :return: None
54+ """
55+
56+ if self ._process is None : # 防止在子进程运行结束前重复启动
57+ self ._process = QtCore .QProcess (self )
58+
59+ self ._process .stateChanged .connect (self ._handle_state ) # type: ignore
60+ self ._process .readyReadStandardOutput .connect (self ._handle_stdout ) # type: ignore
61+ self ._process .readyReadStandardError .connect (self ._handle_stderr ) # type: ignore
62+ self ._process .started .connect (self ._process_started ) # type: ignore
63+ self ._process .finished .connect (self ._process_finished ) # type: ignore
64+ self ._process .errorOccurred .connect (self ._handle_error ) # type: ignore
65+
66+ self ._process .setWorkingDirectory (self ._working_directory )
67+ self ._process .start (self .program , self ._arguments , mode )
68+ self ._process .waitForStarted (1000 ) # 阻塞,直到启动了子进程或超时(单位为毫秒)
69+
70+ def abort_process (self , timeout : int = 10000 ) -> bool :
71+ """
72+ 终止子进程 \n
73+ :param timeout: 超时时间,单位为毫秒
74+ :return: 子进程是否完成
75+ """
76+
77+ if self ._process :
78+ self ._process .terminate ()
79+ finished = self ._process .waitForFinished (timeout ) # 阻塞,直到进程终止或超时
80+ if not finished :
81+ self ._process .kill () # 超时后杀死子进程
82+ return finished
83+ else :
84+ return True
85+
86+ def set_arguments (self , arguments : Sequence [str ]) -> None :
2487 """
25- 使用给定参数启动指定子进程 \n
26- :param program: 子进程命令
27- :param arguments: 子进程参数
88+ 设置子进程参数 \n
89+ :param arguments: 参数列表
2890 :return: None
2991 """
3092
31- if self .process is None : # 防止在子进程运行结束前重复启动
32- self .process = QtCore .QProcess ()
93+ self ._arguments = arguments
3394
34- self .process .stateChanged .connect (self ._handle_state ) # type: ignore
35- self .process .readyReadStandardOutput .connect (self ._handle_stdout ) # type: ignore
36- self .process .readyReadStandardError .connect (self ._handle_stderr ) # type: ignore
37- self .process .started .connect (self ._process_started ) # type: ignore
38- self .process .finished .connect (self ._process_finished ) # type: ignore
95+ def set_working_dir (self , work_dir : str ) -> bool :
96+ """
97+ 设置子进程工作目录 \n
98+ :param work_dir: 工作目录
99+ :return: 是否设置成功
100+ """
39101
40- self .process .start (program , arguments )
102+ if os .path .isdir (work_dir ):
103+ self ._working_directory = work_dir
104+ return True
105+ else :
106+ return False
41107
42108 def _process_started (self ) -> None :
43109 """
44- 处理子进程的槽 \n
110+ 处理子进程开始的槽 \n
45111 :return: None
46112 """
113+
47114 pass
48115
49- def _process_finished (
50- self , exit_code : int , exit_status : QtCore .QProcess .ExitStatus
51- ) -> None :
116+ def _process_finished (self , code : int , status : QtCore .QProcess .ExitStatus ) -> None :
52117 """
53- 处理子进程的槽 \n
118+ 处理子进程结束的槽 \n
119+ :param code: 退出码
120+ :param status: 退出状态
54121 :return: None
55122 """
56123
57- self .output .emit ((self .FINISHED , str (exit_code )))
58- self .process = None
124+ self .exit_code = code
125+ self .exit_status = status
126+ self .output .emit ((self .FINISHED , str (code )))
127+ self ._process = None
59128
60129 def _handle_stdout (self ) -> None :
61130 """
62131 处理标准输出的槽 \n
63132 :return: None
64133 """
65134
66- if self .process :
67- data = self .process .readAllStandardOutput ()
68- stdout = bytes (data ).decode (getdefaultencoding ())
135+ if self ._process :
136+ data = self ._process .readAllStandardOutput ()
137+ stdout = bytes (data ).decode (getdefaultencoding ()) # 将QByteArray转为str
69138 self .output .emit ((self .STDOUT , stdout ))
70139
71140 def _handle_stderr (self ) -> None :
@@ -74,9 +143,9 @@ def _handle_stderr(self) -> None:
74143 :return: None
75144 """
76145
77- if self .process :
78- data = self .process .readAllStandardError ()
79- stderr = bytes (data ).decode (getdefaultencoding ())
146+ if self ._process :
147+ data = self ._process .readAllStandardError ()
148+ stderr = bytes (data ).decode (getdefaultencoding ()) # 将QByteArray转为str
80149 self .output .emit ((self .STDERR , stderr ))
81150
82151 def _handle_state (self , state : QtCore .QProcess .ProcessState ) -> None :
@@ -93,3 +162,12 @@ def _handle_state(self, state: QtCore.QProcess.ProcessState) -> None:
93162 }
94163 state_name = states [state ]
95164 self .output .emit ((self .STATE , state_name ))
165+
166+ def _handle_error (self , error : QtCore .QProcess .ProcessError ) -> None :
167+ """
168+ 处理子进程错误 \n
169+ :param error: 子进程错误
170+ :return: None
171+ """
172+
173+ pass
0 commit comments