目录
前置:
1 本系列将以 "PyQt6实例_批量下载pdf工具"开头,放在 【PyQt6实例】 专栏
2 本系列涉及到的PyQt6知识点:
线程池:QThreadPool,QRunnable;
信号与槽:pyqtSignal,pyqtSlot;
界面:QTextEdit,QLabel,QLineText,QPushButton,QMainWindow,QWidget;
布局:QHBoxLayout,QVBoxLayout;
弹框:QFileDialog,QMessageBox。
3 本系列后续会在B站录制视频,到时会在文末贴出链接。本人还是建议先看博文,不懂的再看视频,这样效率高,节约时间。
代码:
def execute_btn_clicked(self):
txt_dir = self.txtdir_lineedit.text()
if txt_dir is None or len(txt_dir.strip())<=0:
self.information_dialog('请先选择txt所在目录')
return
txt_list = os.listdir(txt_dir)
if len(txt_list)<=0:
self.information_dialog('txt所在目录为空')
return
pdf_dir = self.savedir_lineedit.text()
if pdf_dir is None or len(pdf_dir.strip())<=0:
self.information_dialog('请设置pdf存储目录')
return
answer = QMessageBox.question(
self,
'确认启动?',
f'如果确定启动,程序将把任务分成 {self.max_thread_count} 个线程执行。执行过程将占用设备资源。',
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)
if answer == QMessageBox.StandardButton.Yes:
self.this_time_start_yeah = True
self.thread_finished_count = 0
self.txtdir_lineedit.setDisabled(True)
self.savedir_lineedit.setDisabled(True)
self.choicedir_btn.setDisabled(True)
self.savedir_btn.setDisabled(True)
self.execute_btn.setDisabled(True)
if self.last_time_executed_tickers is not None:
for one in self.last_time_executed_tickers:
txt_list.remove(f'{one}.txt')
pass
# 分发任务
interval = len(txt_list)//self.max_thread_count
if interval == 0:
self.max_thread_count = 1
self.insert_executelog('需要执行的内容很少,只开启一个线程')
pass
for i in range(0,self.max_thread_count):
if i == self.max_thread_count-1:
node_txt_list = txt_list[i*interval:]
else:
node_txt_list = txt_list[i*interval:(i+1)*interval]
task_data = {
'txt_dir':txt_dir,
'pdf_dir':pdf_dir,
'txt_list':node_txt_list,
'temp_dict':self.last_time_data
}
worker = Worker(i,task_data)
worker.signals.result.connect(self.thread_result_fn)
worker.signals.finished.connect(self.thread_finished_fn)
worker.signals.error.connect(self.thread_error_fn)
self.runner_list.append(worker)
self.insert_otherlog(f'线程 {i} 启动。')
self.threadpool.start(worker)
pass
else:
return
pass
def thread_result_fn(self,res:tuple):
# (thread_num,stoped,ticker,executed_url_list,excuted_ticker_list)
# (thread_num,success,None,None,excuted_ticker_list)
thread_num = res[0]
status = res[1]
if status == 'stoped':
self.insert_otherlog(f'线程 {thread_num} 停止.')
if res[2] is not None:
self.pre_last_time_data[res[2]] = res[3]
self.pre_last_time_executed_tickers.extend(res[4])
pass
else:
self.insert_otherlog(f'线程 {thread_num} 正常结束。')
pass
def thread_finished_fn(self,res:int):
self.thread_finished_count += 1
res_str = f'线程 {res} 结束.'
self.insert_otherlog(res_str)
if self.thread_finished_count == self.max_thread_count:
temp_str = '上次执行正常结束'
if self.pre_last_time_data:
temp_str = '上次被强制停止'
with open(os.path.join(basedir,'data','temp.json'),'w',encoding='utf-8') as fw:
json.dump(self.pre_last_time_data,fw)
pass
if len(self.pre_last_time_executed_tickers)>0:
temp_str = '上次被强制停止'
tickers_str = '\n'.join(self.pre_last_time_executed_tickers)
with open(os.path.join(basedir,'data','executed.txt'),'w',encoding='utf-8') as fw:
fw.write(tickers_str)
pass
pre_str = f"{self.txtdir_lineedit.text()};{self.savedir_lineedit.text()};{temp_str}"
with open(os.path.join(basedir,'data','params.txt'),'w',encoding='utf-8') as fw:
fw.write(pre_str)
if self.waitting_close:
self.close()
else:
self.txtdir_lineedit.setDisabled(False)
self.savedir_lineedit.setDisabled(False)
self.choicedir_btn.setDisabled(False)
self.savedir_btn.setDisabled(False)
self.execute_btn.setDisabled(False)
self.infomation_dialog('所有工作线程停止完毕')
pass
pass
def thread_error_fn(self,res:tuple):
error_str = f"线程 {res[0]} 报错。报错类型:{res[1]}。值:{res[2]}。异常栈:{res[3]}"
self.insert_executelog(error_str)
pass
视频:
https://www.bilibili.com/video/BV1zeZcYQEax/
https://www.bilibili.com/video/BV1BeZcYQEZq/
https://www.bilibili.com/video/BV1VSZAYJEUf/