656 lines
23 KiB
Python
656 lines
23 KiB
Python
import os
|
||
import comtypes.client
|
||
import random
|
||
import datetime
|
||
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
|
||
QPushButton, QFrame, QListWidget, QListWidgetItem,
|
||
QFileDialog, QProgressBar, QMessageBox, QSpacerItem)
|
||
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QSize, QTimer
|
||
from PyQt5.QtGui import QPixmap, QIcon, QDragEnterEvent, QDropEvent, QDragLeaveEvent
|
||
|
||
|
||
def generate_unique_filename(original_path):
|
||
"""生成唯一的文件名格式:原名称_日期_随机数.pdf"""
|
||
base_name = os.path.basename(original_path)
|
||
name_without_ext = os.path.splitext(base_name)[0]
|
||
|
||
# 获取当前日期
|
||
current_date = datetime.datetime.now().strftime("%Y%m%d")
|
||
|
||
# 生成4位随机数
|
||
random_num = random.randint(1000, 9999)
|
||
|
||
# 组合成新文件名
|
||
new_filename = f"{name_without_ext}_{current_date}_{random_num}.pdf"
|
||
return os.path.join(os.path.dirname(original_path), new_filename)
|
||
|
||
|
||
class ConversionThread(QThread):
|
||
progress_updated = pyqtSignal(int, int, str) # current, total, filename
|
||
conversion_done = pyqtSignal(str, bool, str) # filename, success, message
|
||
finished_all = pyqtSignal()
|
||
|
||
def __init__(self, files):
|
||
super().__init__()
|
||
self.files = files
|
||
|
||
def run(self):
|
||
word = None
|
||
try:
|
||
word = comtypes.client.CreateObject('Word.Application')
|
||
word.Visible = False
|
||
|
||
total = len(self.files)
|
||
for i, file_path in enumerate(self.files):
|
||
self.progress_updated.emit(i + 1, total, os.path.basename(file_path))
|
||
|
||
try:
|
||
# 使用新的文件名生成逻辑
|
||
pdf_path = generate_unique_filename(file_path)
|
||
doc = word.Documents.Open(os.path.abspath(file_path))
|
||
doc.SaveAs(pdf_path, FileFormat=17) # 17 = PDF
|
||
doc.Close()
|
||
self.conversion_done.emit(file_path, True, pdf_path) # 传递新文件路径
|
||
except Exception as e:
|
||
self.conversion_done.emit(file_path, False, str(e))
|
||
|
||
self.finished_all.emit()
|
||
finally:
|
||
if word:
|
||
word.Quit()
|
||
|
||
|
||
class WordToPDFPage(QWidget):
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.files = []
|
||
self.converted_files = {}
|
||
self.conversion_thread = None
|
||
self.init_ui()
|
||
self.setStyleSheet(self.get_page_style())
|
||
|
||
def init_ui(self):
|
||
self.setObjectName("wordToPdfPage")
|
||
self.setAcceptDrops(True)
|
||
|
||
layout = QHBoxLayout()
|
||
layout.setContentsMargins(20, 20, 20, 20)
|
||
layout.setSpacing(20)
|
||
|
||
# 左侧面板 - 文件上传
|
||
left_panel = QWidget()
|
||
left_layout = QVBoxLayout(left_panel)
|
||
left_layout.setContentsMargins(0, 0, 0, 0)
|
||
left_layout.setSpacing(15)
|
||
|
||
# 上传区域(增强拖拽效果)
|
||
upload_area = QFrame()
|
||
upload_area.setObjectName("uploadArea")
|
||
upload_area.setFixedHeight(200)
|
||
upload_area.setAcceptDrops(True)
|
||
|
||
upload_layout = QVBoxLayout(upload_area)
|
||
upload_layout.setAlignment(Qt.AlignCenter)
|
||
|
||
upload_icon = QLabel()
|
||
upload_icon.setPixmap(QPixmap(":/icons/upload.png").scaled(64, 64, Qt.KeepAspectRatio, Qt.SmoothTransformation))
|
||
upload_icon.setAlignment(Qt.AlignCenter)
|
||
|
||
self.upload_text = QLabel("拖拽文件或文件夹到此处\n或点击上传")
|
||
self.upload_text.setAlignment(Qt.AlignCenter)
|
||
self.upload_text.setWordWrap(True)
|
||
|
||
upload_btn = QPushButton("选择文件或文件夹")
|
||
upload_btn.setObjectName("uploadBtn")
|
||
upload_btn.clicked.connect(self.handle_upload)
|
||
|
||
upload_layout.addWidget(upload_icon)
|
||
upload_layout.addWidget(self.upload_text)
|
||
upload_layout.addWidget(upload_btn)
|
||
|
||
# 文件列表
|
||
file_list_frame = QFrame()
|
||
file_list_frame.setObjectName("fileListFrame")
|
||
file_list_layout = QVBoxLayout(file_list_frame)
|
||
file_list_layout.setContentsMargins(0, 0, 0, 0)
|
||
file_list_layout.setSpacing(5)
|
||
|
||
file_title = QLabel("待转换文件")
|
||
file_title.setObjectName("sectionTitle")
|
||
|
||
self.file_list = QListWidget()
|
||
self.file_list.setObjectName("fileList")
|
||
self.file_list.setSelectionMode(QListWidget.ExtendedSelection)
|
||
|
||
file_list_layout.addWidget(file_title)
|
||
file_list_layout.addWidget(self.file_list)
|
||
|
||
# 操作按钮
|
||
btn_layout = QHBoxLayout()
|
||
btn_layout.setSpacing(10)
|
||
|
||
self.convert_btn = QPushButton("开始转换")
|
||
self.convert_btn.setObjectName("convertBtn")
|
||
self.convert_btn.clicked.connect(self.start_conversion)
|
||
|
||
delete_btn = QPushButton("删除选中")
|
||
delete_btn.setObjectName("deleteBtn")
|
||
delete_btn.clicked.connect(self.delete_selected)
|
||
|
||
btn_layout.addWidget(self.convert_btn)
|
||
btn_layout.addWidget(delete_btn)
|
||
|
||
# 组装左侧面板
|
||
left_layout.addWidget(upload_area)
|
||
left_layout.addWidget(file_list_frame)
|
||
left_layout.addLayout(btn_layout)
|
||
|
||
# 右侧面板 - 转换结果
|
||
right_panel = QWidget()
|
||
right_layout = QVBoxLayout(right_panel)
|
||
right_layout.setContentsMargins(0, 0, 0, 0)
|
||
right_layout.setSpacing(15)
|
||
|
||
# 进度区域
|
||
progress_frame = QFrame()
|
||
progress_frame.setObjectName("progressFrame")
|
||
progress_layout = QVBoxLayout(progress_frame)
|
||
progress_layout.setContentsMargins(15, 15, 15, 15)
|
||
progress_layout.setSpacing(10)
|
||
|
||
progress_title = QLabel("转换进度")
|
||
progress_title.setObjectName("sectionTitle")
|
||
|
||
# 总体进度
|
||
total_layout = QHBoxLayout()
|
||
total_layout.setSpacing(10)
|
||
|
||
total_label = QLabel("总体进度:")
|
||
total_label.setObjectName("progressLabel")
|
||
|
||
self.total_progress = QProgressBar()
|
||
self.total_progress.setObjectName("totalProgress")
|
||
self.total_progress.setTextVisible(False)
|
||
|
||
total_layout.addWidget(total_label)
|
||
total_layout.addWidget(self.total_progress)
|
||
|
||
# 文件进度
|
||
file_layout = QHBoxLayout()
|
||
file_layout.setSpacing(10)
|
||
|
||
file_label = QLabel("当前文件:")
|
||
file_label.setObjectName("progressLabel")
|
||
|
||
self.file_progress = QProgressBar()
|
||
self.file_progress.setObjectName("fileProgress")
|
||
self.file_progress.setTextVisible(False)
|
||
|
||
file_layout.addWidget(file_label)
|
||
file_layout.addWidget(self.file_progress)
|
||
|
||
# 状态标签
|
||
self.status_label = QLabel("就绪")
|
||
self.status_label.setObjectName("statusLabel")
|
||
self.status_label.setAlignment(Qt.AlignCenter)
|
||
|
||
progress_layout.addWidget(progress_title)
|
||
progress_layout.addLayout(total_layout)
|
||
progress_layout.addLayout(file_layout)
|
||
progress_layout.addWidget(self.status_label)
|
||
|
||
# 结果列表
|
||
result_frame = QFrame()
|
||
result_frame.setObjectName("resultFrame")
|
||
result_layout = QVBoxLayout(result_frame)
|
||
result_layout.setContentsMargins(0, 0, 0, 0)
|
||
result_layout.setSpacing(5)
|
||
|
||
result_title = QLabel("转换结果")
|
||
result_title.setObjectName("sectionTitle")
|
||
|
||
self.result_list = QListWidget()
|
||
self.result_list.setObjectName("resultList")
|
||
self.result_list.setSelectionMode(QListWidget.ExtendedSelection)
|
||
|
||
result_layout.addWidget(result_title)
|
||
result_layout.addWidget(self.result_list)
|
||
|
||
# 下载按钮
|
||
self.download_btn = QPushButton("全部下载")
|
||
self.download_btn.setObjectName("downloadBtn")
|
||
self.download_btn.setEnabled(False)
|
||
self.download_btn.clicked.connect(self.download_all)
|
||
|
||
# 日志区域
|
||
log_frame = QFrame()
|
||
log_frame.setObjectName("logFrame")
|
||
log_layout = QVBoxLayout(log_frame)
|
||
log_layout.setContentsMargins(0, 0, 0, 0)
|
||
log_layout.setSpacing(5)
|
||
|
||
log_title = QLabel("转换日志")
|
||
log_title.setObjectName("sectionTitle")
|
||
|
||
self.log_content = QListWidget()
|
||
self.log_content.setObjectName("logContent")
|
||
self.log_content.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
||
|
||
log_layout.addWidget(log_title)
|
||
log_layout.addWidget(self.log_content)
|
||
|
||
# 组装右侧面板
|
||
right_layout.addWidget(progress_frame)
|
||
right_layout.addWidget(result_frame)
|
||
right_layout.addWidget(self.download_btn)
|
||
right_layout.addWidget(log_frame)
|
||
|
||
# 主布局
|
||
layout.addWidget(left_panel)
|
||
layout.addWidget(right_panel)
|
||
|
||
self.setLayout(layout)
|
||
|
||
def get_page_style(self):
|
||
return """
|
||
/* ===== Word转PDF页面样式 ===== */
|
||
#wordToPdfPage {
|
||
background-color: #1a202c;
|
||
}
|
||
|
||
/* 卡片样式 */
|
||
#uploadArea,
|
||
#fileListFrame,
|
||
#progressFrame,
|
||
#resultFrame,
|
||
#logFrame {
|
||
background-color: #2d3748;
|
||
border: 1px solid #4a5568;
|
||
border-radius: 8px;
|
||
padding: 15px;
|
||
}
|
||
|
||
/* 上传区域 */
|
||
#uploadArea {
|
||
border: 2px dashed #4a5568;
|
||
background-color: rgba(45, 55, 72, 0.5);
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
#uploadArea:hover {
|
||
border-color: #818cf8;
|
||
background-color: rgba(129, 140, 248, 0.1);
|
||
}
|
||
|
||
#uploadArea[dragActive="true"] {
|
||
border-color: #4ade80;
|
||
background-color: rgba(74, 222, 128, 0.1);
|
||
}
|
||
|
||
/* 标题样式 */
|
||
#sectionTitle {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #e2e8f0;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
/* 文件列表 */
|
||
#fileList, #resultList, #logContent {
|
||
background-color: rgba(26, 32, 44, 0.3);
|
||
border: 1px solid #4a5568;
|
||
border-radius: 6px;
|
||
min-height: 200px;
|
||
max-height: 250px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
#fileList::item, #resultList::item, #logContent::item {
|
||
padding: 8px 12px;
|
||
border-bottom: 1px solid rgba(74, 85, 104, 0.5);
|
||
}
|
||
|
||
#fileList::item:selected,
|
||
#resultList::item:selected,
|
||
#logContent::item:selected {
|
||
background-color: rgba(129, 140, 248, 0.15);
|
||
}
|
||
|
||
/* 进度条 */
|
||
#totalProgress, #fileProgress {
|
||
height: 8px;
|
||
border-radius: 4px;
|
||
background-color: #2d3748;
|
||
}
|
||
|
||
#totalProgress::chunk {
|
||
background-color: #818cf8;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
#fileProgress::chunk {
|
||
background-color: #4ade80;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
#progressLabel {
|
||
color: #a0aec0;
|
||
font-size: 13px;
|
||
min-width: 70px;
|
||
}
|
||
|
||
#statusLabel {
|
||
font-size: 14px;
|
||
color: #e2e8f0;
|
||
margin-top: 10px;
|
||
padding: 8px;
|
||
border-radius: 6px;
|
||
background-color: rgba(26, 32, 44, 0.3);
|
||
}
|
||
|
||
/* 按钮样式 */
|
||
#uploadBtn, #convertBtn, #deleteBtn, #downloadBtn {
|
||
min-height: 40px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
#uploadBtn {
|
||
min-width: 180px;
|
||
}
|
||
|
||
#convertBtn {
|
||
background-color: #4f46e5;
|
||
}
|
||
|
||
#convertBtn:disabled {
|
||
background-color: #4a5568;
|
||
}
|
||
|
||
#downloadBtn {
|
||
background-color: #10b981;
|
||
}
|
||
|
||
#downloadBtn:hover {
|
||
background-color: #059669;
|
||
}
|
||
|
||
#deleteBtn {
|
||
background-color: #ef4444;
|
||
}
|
||
|
||
#deleteBtn:hover {
|
||
background-color: #dc2626;
|
||
}
|
||
|
||
/* 日志样式 */
|
||
#logContent::item[type="info"] {
|
||
color: #a0aec0;
|
||
}
|
||
|
||
#logContent::item[type="success"] {
|
||
color: #34d399;
|
||
}
|
||
|
||
#logContent::item[type="warning"] {
|
||
color: #fbbf24;
|
||
}
|
||
|
||
#logContent::item[type="error"] {
|
||
color: #f87171;
|
||
}
|
||
"""
|
||
|
||
def dragEnterEvent(self, event: QDragEnterEvent):
|
||
if event.mimeData().hasUrls():
|
||
event.acceptProposedAction()
|
||
# 高亮显示拖拽区域
|
||
self.findChild(QFrame, "uploadArea").setProperty("dragActive", True)
|
||
self.findChild(QFrame, "uploadArea").style().polish(self.findChild(QFrame, "uploadArea"))
|
||
self.upload_text.setText("释放文件以添加")
|
||
|
||
def dragLeaveEvent(self, event: QDragLeaveEvent):
|
||
# 恢复拖拽区域样式
|
||
self.findChild(QFrame, "uploadArea").setProperty("dragActive", False)
|
||
self.findChild(QFrame, "uploadArea").style().polish(self.findChild(QFrame, "uploadArea"))
|
||
self.upload_text.setText("拖拽文件或文件夹到此处\n或点击上传")
|
||
|
||
def dropEvent(self, event: QDropEvent):
|
||
# 恢复拖拽区域样式
|
||
self.findChild(QFrame, "uploadArea").setProperty("dragActive", False)
|
||
self.findChild(QFrame, "uploadArea").style().polish(self.findChild(QFrame, "uploadArea"))
|
||
self.upload_text.setText("拖拽文件或文件夹到此处\n或点击上传")
|
||
|
||
urls = event.mimeData().urls()
|
||
files = []
|
||
added_count = 0
|
||
|
||
for url in urls:
|
||
path = url.toLocalFile()
|
||
if os.path.isdir(path):
|
||
# 处理文件夹
|
||
for root, _, filenames in os.walk(path):
|
||
for f in filenames:
|
||
if f.lower().endswith(('.doc', '.docx')):
|
||
files.append(os.path.join(root, f))
|
||
elif os.path.isfile(path) and path.lower().endswith(('.doc', '.docx')):
|
||
files.append(path)
|
||
|
||
if files:
|
||
added_count = self.add_files(files)
|
||
self.add_log(f"添加了 {added_count} 个文件", "success")
|
||
else:
|
||
self.add_log("未找到有效的Word文件", "warning")
|
||
|
||
def handle_upload(self):
|
||
"""处理文件或文件夹上传"""
|
||
options = QFileDialog.Options()
|
||
files, _ = QFileDialog.getOpenFileNames(
|
||
self, "选择Word文件", "", "Word Files (*.doc *.docx);;All Files (*)", options=options
|
||
)
|
||
|
||
if files:
|
||
added_count = self.add_files(files)
|
||
self.add_log(f"添加了 {added_count} 个文件", "success")
|
||
else:
|
||
folder = QFileDialog.getExistingDirectory(self, "选择包含Word文件的文件夹")
|
||
if folder:
|
||
files = []
|
||
for root, _, filenames in os.walk(folder):
|
||
for f in filenames:
|
||
if f.lower().endswith(('.doc', '.docx')):
|
||
files.append(os.path.join(root, f))
|
||
|
||
if files:
|
||
added_count = self.add_files(files)
|
||
self.add_log(f"从文件夹添加了 {added_count} 个文件", "success")
|
||
else:
|
||
self.add_log("文件夹中没有找到Word文件", "warning")
|
||
|
||
def add_files(self, files):
|
||
"""添加文件到列表,避免重复"""
|
||
added_count = 0
|
||
for file in files:
|
||
if file not in self.files and os.path.exists(file):
|
||
self.files.append(file)
|
||
item = QListWidgetItem(os.path.basename(file))
|
||
item.setData(Qt.UserRole, file)
|
||
self.file_list.addItem(item)
|
||
added_count += 1
|
||
return added_count
|
||
|
||
def delete_selected(self):
|
||
"""删除选中的文件"""
|
||
selected_items = self.file_list.selectedItems()
|
||
if not selected_items:
|
||
self.add_log("请先选择要删除的文件", "warning")
|
||
return
|
||
|
||
for item in selected_items:
|
||
self.files.remove(item.data(Qt.UserRole))
|
||
self.file_list.takeItem(self.file_list.row(item))
|
||
|
||
self.add_log(f"删除了 {len(selected_items)} 个文件", "info")
|
||
|
||
def start_conversion(self):
|
||
"""开始转换文件"""
|
||
if not self.files:
|
||
self.add_log("请先添加要转换的文件!", "warning")
|
||
return
|
||
|
||
# 重置状态
|
||
self.converted_files = {}
|
||
self.result_list.clear()
|
||
self.log_content.clear()
|
||
self.download_btn.setEnabled(False)
|
||
self.convert_btn.setEnabled(False)
|
||
|
||
# 重置进度条
|
||
self.total_progress.setValue(0)
|
||
self.file_progress.setValue(0)
|
||
self.status_label.setText("正在准备转换...")
|
||
|
||
# 添加开始日志
|
||
self.add_log("开始转换任务", "info")
|
||
self.add_log(f"共 {len(self.files)} 个文件待处理", "info")
|
||
|
||
# 创建并启动转换线程
|
||
self.conversion_thread = ConversionThread(self.files.copy())
|
||
self.conversion_thread.progress_updated.connect(self.update_progress)
|
||
self.conversion_thread.conversion_done.connect(self.handle_conversion_done)
|
||
self.conversion_thread.finished_all.connect(self.handle_finished_all)
|
||
self.conversion_thread.start()
|
||
|
||
def update_progress(self, current, total, filename):
|
||
"""更新进度条"""
|
||
self.total_progress.setMaximum(total)
|
||
self.total_progress.setValue(current)
|
||
|
||
# 重置文件进度为0
|
||
self.file_progress.setValue(0)
|
||
self.file_progress.setMaximum(100)
|
||
|
||
# 更新状态
|
||
self.status_label.setText(f"正在转换: {os.path.basename(filename)}")
|
||
self.add_log(f"开始转换: {os.path.basename(filename)} ({current}/{total})", "info")
|
||
|
||
# 模拟文件进度动画
|
||
self.animate_file_progress()
|
||
|
||
def animate_file_progress(self):
|
||
"""模拟文件转换进度动画(实际应用中应由实际进度驱动)"""
|
||
self.file_progress_value = 0
|
||
|
||
def update_progress():
|
||
if self.file_progress_value < 100:
|
||
self.file_progress_value += 2
|
||
self.file_progress.setValue(self.file_progress_value)
|
||
QTimer.singleShot(50, update_progress)
|
||
|
||
update_progress()
|
||
|
||
def handle_conversion_done(self, file_path, success, message):
|
||
"""处理单个文件转换完成"""
|
||
basename = os.path.basename(file_path)
|
||
if success:
|
||
# 成功时,message包含新的PDF路径
|
||
pdf_path = message
|
||
self.converted_files[file_path] = pdf_path
|
||
|
||
# 从待转换列表移除
|
||
for i in range(self.file_list.count()):
|
||
item = self.file_list.item(i)
|
||
if item.data(Qt.UserRole) == file_path:
|
||
self.file_list.takeItem(i)
|
||
break
|
||
|
||
# 添加到结果列表
|
||
item = QListWidgetItem(f"{basename} → {os.path.basename(pdf_path)}")
|
||
item.setData(Qt.UserRole, pdf_path)
|
||
self.result_list.addItem(item)
|
||
|
||
self.add_log(f"✅ 转换成功: {basename} -> {os.path.basename(pdf_path)}", "success")
|
||
else:
|
||
# 失败时显示错误信息
|
||
self.add_log(f"❌ 转换失败: {basename} - {message}", "error")
|
||
|
||
def handle_finished_all(self):
|
||
"""所有文件转换完成"""
|
||
success_count = len(self.converted_files)
|
||
fail_count = len(self.files) - success_count
|
||
|
||
# 更新状态
|
||
self.status_label.setText(f"转换完成! 成功: {success_count}, 失败: {fail_count}")
|
||
self.total_progress.setValue(self.total_progress.maximum())
|
||
self.file_progress.setValue(100)
|
||
self.convert_btn.setEnabled(True)
|
||
self.download_btn.setEnabled(bool(self.converted_files))
|
||
|
||
# 添加完成日志
|
||
if success_count:
|
||
self.add_log(f"🎉 全部转换完成! 成功转换 {success_count} 个文件", "success")
|
||
if fail_count:
|
||
self.add_log(f"⚠️ 有 {fail_count} 个文件转换失败", "warning")
|
||
|
||
if self.converted_files:
|
||
self.add_log("点击'全部下载'按钮保存转换后的文件", "info")
|
||
|
||
def download_all(self):
|
||
"""下载所有转换后的文件"""
|
||
if not self.converted_files:
|
||
self.add_log("没有可下载的文件", "warning")
|
||
return
|
||
|
||
folder = QFileDialog.getExistingDirectory(self, "选择保存位置")
|
||
if not folder:
|
||
self.add_log("下载已取消", "info")
|
||
return
|
||
|
||
success = 0
|
||
errors = []
|
||
|
||
# 开始下载
|
||
self.status_label.setText("正在下载文件...")
|
||
self.add_log(f"开始下载 {len(self.converted_files)} 个文件到 {folder}", "info")
|
||
|
||
for pdf_path in self.converted_files.values():
|
||
try:
|
||
file_name = os.path.basename(pdf_path)
|
||
destination = os.path.join(folder, file_name)
|
||
|
||
# 复制文件
|
||
with open(pdf_path, 'rb') as src_file:
|
||
with open(destination, 'wb') as dest_file:
|
||
dest_file.write(src_file.read())
|
||
success += 1
|
||
self.add_log(f"已下载: {file_name}", "success")
|
||
except Exception as e:
|
||
errors.append(f"{os.path.basename(pdf_path)}: {str(e)}")
|
||
self.add_log(f"下载失败: {os.path.basename(pdf_path)} - {str(e)}", "error")
|
||
|
||
# 更新状态
|
||
self.status_label.setText(f"下载完成! 成功: {success}, 失败: {len(errors)}")
|
||
|
||
# 显示结果
|
||
if errors:
|
||
self.add_log(f"⚠️ 部分文件下载失败 ({len(errors)} 个)", "warning")
|
||
else:
|
||
self.add_log(f"✅ 全部文件下载成功!", "success")
|
||
|
||
self.add_log(f"文件已保存到: {folder}", "info")
|
||
|
||
def add_log(self, message, log_type="info"):
|
||
"""添加日志项"""
|
||
item = QListWidgetItem(f"[{datetime.datetime.now().strftime('%H:%M:%S')}] {message}")
|
||
item.setData(Qt.UserRole + 1, log_type) # 存储日志类型用于样式
|
||
self.log_content.addItem(item)
|
||
self.log_content.scrollToBottom()
|
||
|
||
def paintEvent(self, event):
|
||
"""为拖拽区域添加悬停效果"""
|
||
if self.underMouse():
|
||
self.findChild(QFrame, "uploadArea").setProperty("hover", True)
|
||
self.findChild(QFrame, "uploadArea").style().polish(self.findChild(QFrame, "uploadArea"))
|
||
else:
|
||
self.findChild(QFrame, "uploadArea").setProperty("hover", False)
|
||
self.findChild(QFrame, "uploadArea").style().polish(self.findChild(QFrame, "uploadArea"))
|
||
super().paintEvent(event) |