feat(ui): 新增多个UI测试窗口并优化主窗口功能
- 添加main_window_test.py用于UI功能测试 - 添加main_window_simple.py简化版界面 - 添加main_window_new.py和main_window_final.py完整功能界面 - 优化主窗口高级面板切换逻辑 - 更新.gitignore忽略测试文件
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -24,4 +24,10 @@ logs/
|
||||
Thumbs.db
|
||||
|
||||
# 模型文件
|
||||
models/*.gguf
|
||||
models/*.gguf
|
||||
|
||||
# 测试文件
|
||||
test*
|
||||
|
||||
# 自己
|
||||
.gitignore
|
||||
@@ -310,11 +310,10 @@ class MainWindow(QMainWindow):
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "术语格式不正确,请使用 'A = B' 格式")
|
||||
|
||||
def toggle_advanced_panel(self):
|
||||
def toggle_advanced_panel(self, checked):
|
||||
"""切换高级辅助面板的显示/隐藏状态"""
|
||||
is_visible = not self.advanced_content.isVisible()
|
||||
self.advanced_content.setVisible(is_visible)
|
||||
self.advanced_toggle.setText("▲" if is_visible else "▼")
|
||||
self.advanced_content.setVisible(checked)
|
||||
self.advanced_toggle.setText("▲" if checked else "▼")
|
||||
|
||||
def show_term_context_menu(self, pos):
|
||||
"""显示术语项右键菜单"""
|
||||
|
||||
749
ui/main_window_final.py
Normal file
749
ui/main_window_final.py
Normal file
@@ -0,0 +1,749 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QPushButton,
|
||||
QLineEdit, QLabel, QGroupBox, QScrollArea, QToolButton, QStatusBar,
|
||||
QFileDialog, QMessageBox, QListWidget, QListWidgetItem, QFrame, QSplitter,
|
||||
QDialog, QProgressBar, QGridLayout
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer, QSize, QPropertyAnimation, QEasingCurve
|
||||
from PySide6.QtGui import QFont, QPalette, QColor
|
||||
from utils.word_handler import WordHandler
|
||||
from utils.system_monitor import SystemMonitor
|
||||
from translator import Translator
|
||||
from utils.logger import logger
|
||||
import os
|
||||
|
||||
class SettingsDialog(QDialog):
|
||||
"""设置对话框,包含高级辅助功能和模型管理"""
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("设置")
|
||||
self.setMinimumSize(600, 700)
|
||||
self.setModal(True)
|
||||
|
||||
# 从父窗口获取数据
|
||||
self.parent_window = parent
|
||||
self.terms = parent.terms if parent else []
|
||||
self.translator = parent.translator if parent else None
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
# 加载现有数据
|
||||
self.load_existing_data()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化设置对话框UI"""
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 20)
|
||||
|
||||
# 标题
|
||||
title_label = QLabel("设置")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(20)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d; margin-bottom: 10px;")
|
||||
|
||||
# 创建滚动区域
|
||||
scroll_area = QScrollArea()
|
||||
scroll_area.setWidgetResizable(True)
|
||||
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
|
||||
scroll_content = QWidget()
|
||||
scroll_layout = QVBoxLayout(scroll_content)
|
||||
scroll_layout.setSpacing(20)
|
||||
|
||||
# ====== 模型管理部分 ======
|
||||
model_group = QGroupBox("模型管理")
|
||||
model_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
model_layout = QVBoxLayout(model_group)
|
||||
|
||||
# 当前模型信息
|
||||
current_model_layout = QHBoxLayout()
|
||||
current_model_label = QLabel("当前模型:")
|
||||
current_model_label.setStyleSheet("font-weight: bold; color: #4a5568;")
|
||||
|
||||
self.current_model_info = QLabel("未加载")
|
||||
self.current_model_info.setStyleSheet("color: #2d3748;")
|
||||
|
||||
current_model_layout.addWidget(current_model_label)
|
||||
current_model_layout.addWidget(self.current_model_info)
|
||||
current_model_layout.addStretch()
|
||||
|
||||
# 模型状态
|
||||
model_status_layout = QHBoxLayout()
|
||||
model_status_label = QLabel("模型状态:")
|
||||
model_status_label.setStyleSheet("font-weight: bold; color: #4a5568;")
|
||||
|
||||
self.model_status_display = QLabel("● 未知")
|
||||
self.model_status_display.setStyleSheet("color: #a0aec0;")
|
||||
|
||||
model_status_layout.addWidget(model_status_label)
|
||||
model_status_layout.addWidget(self.model_status_display)
|
||||
model_status_layout.addStretch()
|
||||
|
||||
# 更换模型按钮
|
||||
change_model_layout = QHBoxLayout()
|
||||
self.change_model_btn = QPushButton("更换模型")
|
||||
self.change_model_btn.setFixedSize(120, 36)
|
||||
self.change_model_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 6px; font-weight: bold;"
|
||||
)
|
||||
self.change_model_btn.clicked.connect(self.change_model)
|
||||
|
||||
change_model_layout.addStretch()
|
||||
change_model_layout.addWidget(self.change_model_btn)
|
||||
|
||||
model_layout.addLayout(current_model_layout)
|
||||
model_layout.addLayout(model_status_layout)
|
||||
model_layout.addLayout(change_model_layout)
|
||||
|
||||
# ====== 文本背景/场景介绍 ======
|
||||
context_group = QGroupBox("文本背景 / 场景介绍")
|
||||
context_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
context_layout = QVBoxLayout(context_group)
|
||||
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setPlaceholderText("例如:这是一份关于建筑工程的合同...")
|
||||
self.context_edit.setFixedHeight(100)
|
||||
self.context_edit.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
context_layout.addWidget(self.context_edit)
|
||||
|
||||
# ====== 术语定义 ======
|
||||
terms_group = QGroupBox("术语簿 (定义 A=B)")
|
||||
terms_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
terms_layout = QVBoxLayout(terms_group)
|
||||
|
||||
# 术语列表
|
||||
self.terms_list = QListWidget()
|
||||
self.terms_list.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; min-height: 150px;"
|
||||
)
|
||||
|
||||
# 术语输入区域
|
||||
terms_input_layout = QHBoxLayout()
|
||||
self.term_input = QLineEdit()
|
||||
self.term_input.setPlaceholderText("输入术语格式:原文 = 译文")
|
||||
self.term_input.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
add_term_btn = QPushButton("添加")
|
||||
add_term_btn.setFixedSize(80, 32)
|
||||
add_term_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
add_term_btn.clicked.connect(self.add_term)
|
||||
|
||||
terms_input_layout.addWidget(self.term_input)
|
||||
terms_input_layout.addWidget(add_term_btn)
|
||||
|
||||
# 术语操作按钮
|
||||
terms_buttons_layout = QHBoxLayout()
|
||||
|
||||
delete_term_btn = QPushButton("删除选中")
|
||||
delete_term_btn.setFixedSize(100, 32)
|
||||
delete_term_btn.setStyleSheet(
|
||||
"background-color: #e53e3e; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
delete_term_btn.clicked.connect(self.delete_selected_term)
|
||||
|
||||
clear_terms_btn = QPushButton("清空所有")
|
||||
clear_terms_btn.setFixedSize(100, 32)
|
||||
clear_terms_btn.setStyleSheet(
|
||||
"background-color: #a0aec0; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
clear_terms_btn.clicked.connect(self.clear_all_terms)
|
||||
|
||||
terms_buttons_layout.addWidget(delete_term_btn)
|
||||
terms_buttons_layout.addWidget(clear_terms_btn)
|
||||
terms_buttons_layout.addStretch()
|
||||
|
||||
terms_layout.addWidget(self.terms_list)
|
||||
terms_layout.addLayout(terms_input_layout)
|
||||
terms_layout.addLayout(terms_buttons_layout)
|
||||
|
||||
# 将所有组添加到滚动布局
|
||||
scroll_layout.addWidget(model_group)
|
||||
scroll_layout.addWidget(context_group)
|
||||
scroll_layout.addWidget(terms_group)
|
||||
scroll_layout.addStretch()
|
||||
|
||||
# 设置滚动区域内容
|
||||
scroll_area.setWidget(scroll_content)
|
||||
|
||||
# 按钮区域
|
||||
buttons_layout = QHBoxLayout()
|
||||
|
||||
save_btn = QPushButton("保存并应用")
|
||||
save_btn.setFixedSize(120, 40)
|
||||
save_btn.setStyleSheet(
|
||||
"background-color: #38a169; color: white; border: none; border-radius: 6px; font-weight: bold;"
|
||||
)
|
||||
save_btn.clicked.connect(self.save_and_apply)
|
||||
|
||||
cancel_btn = QPushButton("取消")
|
||||
cancel_btn.setFixedSize(120, 40)
|
||||
cancel_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
cancel_btn.clicked.connect(self.reject)
|
||||
|
||||
buttons_layout.addStretch()
|
||||
buttons_layout.addWidget(cancel_btn)
|
||||
buttons_layout.addWidget(save_btn)
|
||||
|
||||
# 添加到主布局
|
||||
main_layout.addWidget(title_label)
|
||||
main_layout.addWidget(scroll_area)
|
||||
main_layout.addLayout(buttons_layout)
|
||||
|
||||
def load_existing_data(self):
|
||||
"""加载现有数据"""
|
||||
if self.parent_window:
|
||||
# 加载模型信息
|
||||
self.update_model_info()
|
||||
|
||||
# 加载上下文
|
||||
if hasattr(self.parent_window, 'context_edit'):
|
||||
self.context_edit.setText(self.parent_window.context_edit.toPlainText())
|
||||
|
||||
# 加载术语
|
||||
for term in self.terms:
|
||||
self.terms_list.addItem(term)
|
||||
|
||||
def update_model_info(self):
|
||||
"""更新模型信息显示"""
|
||||
if self.parent_window and hasattr(self.parent_window, 'translator'):
|
||||
translator = self.parent_window.translator
|
||||
|
||||
if translator.is_ready:
|
||||
self.model_status_display.setText("● 就绪")
|
||||
self.model_status_display.setStyleSheet("color: #38a169;")
|
||||
|
||||
model_info = translator.get_model_info()
|
||||
if model_info:
|
||||
self.current_model_info.setText(model_info)
|
||||
else:
|
||||
self.current_model_info.setText("模型已加载")
|
||||
else:
|
||||
self.model_status_display.setText("● 未就绪")
|
||||
self.model_status_display.setStyleSheet("color: #e53e3e;")
|
||||
self.current_model_info.setText("模型未加载")
|
||||
|
||||
def change_model(self):
|
||||
"""更换模型"""
|
||||
if not self.parent_window:
|
||||
return
|
||||
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self, "选择模型文件", "", "GGUF模型文件 (*.gguf)"
|
||||
)
|
||||
if file_path:
|
||||
# 显示加载状态
|
||||
self.model_status_display.setText("● 加载中...")
|
||||
self.model_status_display.setStyleSheet("color: #d69e2e;")
|
||||
self.current_model_info.setText("正在加载模型...")
|
||||
|
||||
# 加载模型
|
||||
if self.parent_window.translator.load_model(file_path):
|
||||
self.model_status_display.setText("● 就绪")
|
||||
self.model_status_display.setStyleSheet("color: #38a169;")
|
||||
|
||||
model_info = self.parent_window.translator.get_model_info()
|
||||
if model_info:
|
||||
self.current_model_info.setText(model_info)
|
||||
else:
|
||||
self.current_model_info.setText(os.path.basename(file_path))
|
||||
|
||||
QMessageBox.information(self, "成功", "模型加载成功")
|
||||
|
||||
# 更新父窗口的模型状态显示
|
||||
if hasattr(self.parent_window, 'model_status_label'):
|
||||
self.parent_window.model_status_label.setText("● 模型就绪")
|
||||
self.parent_window.model_status_label.setStyleSheet("color: #38a169;")
|
||||
|
||||
if hasattr(self.parent_window, 'model_info_label'):
|
||||
self.parent_window.model_info_label.setText(f"{model_info if model_info else os.path.basename(file_path)}")
|
||||
else:
|
||||
self.model_status_display.setText("● 加载失败")
|
||||
self.model_status_display.setStyleSheet("color: #e53e3e;")
|
||||
self.current_model_info.setText("模型加载失败")
|
||||
QMessageBox.critical(self, "错误", "模型加载失败")
|
||||
|
||||
def add_term(self):
|
||||
"""添加术语定义"""
|
||||
term_text = self.term_input.text().strip()
|
||||
if term_text:
|
||||
if "=" in term_text:
|
||||
self.terms.append(term_text)
|
||||
self.terms_list.addItem(term_text)
|
||||
self.term_input.clear()
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "术语格式不正确,请使用 '原文 = 译文' 格式")
|
||||
|
||||
def delete_selected_term(self):
|
||||
"""删除选中的术语"""
|
||||
selected_items = self.terms_list.selectedItems()
|
||||
if not selected_items:
|
||||
QMessageBox.warning(self, "警告", "请先选择要删除的术语")
|
||||
return
|
||||
|
||||
for item in selected_items:
|
||||
term_text = item.text()
|
||||
if term_text in self.terms:
|
||||
self.terms.remove(term_text)
|
||||
self.terms_list.takeItem(self.terms_list.row(item))
|
||||
|
||||
def clear_all_terms(self):
|
||||
"""清空所有术语"""
|
||||
if self.terms_list.count() == 0:
|
||||
return
|
||||
|
||||
reply = QMessageBox.question(
|
||||
self, "确认", "确定要清空所有术语吗?",
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.terms.clear()
|
||||
self.terms_list.clear()
|
||||
|
||||
def save_and_apply(self):
|
||||
"""保存并应用设置"""
|
||||
# 保存到父窗口
|
||||
if self.parent_window:
|
||||
# 保存上下文
|
||||
if hasattr(self.parent_window, 'context_edit'):
|
||||
self.parent_window.context_edit.setText(self.context_edit.toPlainText())
|
||||
|
||||
# 保存术语
|
||||
self.parent_window.terms = self.terms.copy()
|
||||
|
||||
# 更新术语列表显示(如果父窗口有显示的话)
|
||||
if hasattr(self.parent_window, 'terms_list'):
|
||||
self.parent_window.terms_list.clear()
|
||||
for term in self.terms:
|
||||
self.parent_window.terms_list.addItem(term)
|
||||
|
||||
QMessageBox.information(self, "成功", "设置已保存并应用")
|
||||
self.accept()
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("PrivaTrans")
|
||||
self.setMinimumSize(800, 600)
|
||||
|
||||
# 初始化组件
|
||||
self.translator = Translator()
|
||||
self.system_monitor = SystemMonitor()
|
||||
self.word_handler = WordHandler()
|
||||
|
||||
# 默认模型路径
|
||||
self.default_model_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "models", "HY-MT1.5-1.8B_bf16_Q4_K_M.gguf")
|
||||
|
||||
# 术语列表
|
||||
self.terms = []
|
||||
|
||||
# 倒计时相关
|
||||
self.countdown_timer = None
|
||||
self.countdown_seconds = 60
|
||||
self.countdown_label = None
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
# 初始化状态栏定时器
|
||||
self.init_status_bar_timer()
|
||||
|
||||
# 加载默认模型
|
||||
self.load_default_model()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI界面"""
|
||||
# 主布局
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 10)
|
||||
|
||||
# 顶部标题栏
|
||||
title_bar = QWidget()
|
||||
title_bar_layout = QHBoxLayout(title_bar)
|
||||
title_bar_layout.setContentsMargins(0, 0, 0, 0)
|
||||
title_bar_layout.setSpacing(0)
|
||||
|
||||
# 应用标题
|
||||
title_label = QLabel("PrivaTrans")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(24)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d;")
|
||||
|
||||
# 右侧设置按钮
|
||||
self.settings_btn = QPushButton("⚙ 设置")
|
||||
self.settings_btn.setFixedSize(80, 36)
|
||||
self.settings_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #e2e8f0;
|
||||
color: #2d3748;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #cbd5e0;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #a0aec0;
|
||||
}
|
||||
""")
|
||||
self.settings_btn.clicked.connect(self.open_settings)
|
||||
|
||||
title_bar_layout.addWidget(title_label)
|
||||
title_bar_layout.addStretch()
|
||||
title_bar_layout.addWidget(self.settings_btn)
|
||||
|
||||
# 模型信息显示(只显示状态,更换功能在设置中)
|
||||
model_layout = QHBoxLayout()
|
||||
|
||||
self.model_status_label = QLabel()
|
||||
self.model_status_label.setStyleSheet("color: #2d3748;")
|
||||
|
||||
self.model_info_label = QLabel()
|
||||
self.model_info_label.setStyleSheet("color: #2d3748; font-weight: bold;")
|
||||
|
||||
model_layout.addWidget(self.model_status_label)
|
||||
model_layout.addWidget(self.model_info_label)
|
||||
model_layout.addStretch()
|
||||
|
||||
# 原文输入区域
|
||||
input_layout = QVBoxLayout()
|
||||
|
||||
input_header_layout = QHBoxLayout()
|
||||
input_label = QLabel("原文内容")
|
||||
input_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
import_word_btn = QPushButton("导入 Word")
|
||||
import_word_btn.setFixedSize(120, 32)
|
||||
import_word_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
import_word_btn.clicked.connect(self.import_word)
|
||||
|
||||
input_header_layout.addWidget(input_label)
|
||||
input_header_layout.addStretch()
|
||||
input_header_layout.addWidget(import_word_btn)
|
||||
|
||||
self.source_text = QTextEdit()
|
||||
self.source_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px; min-height: 150px;"
|
||||
)
|
||||
|
||||
input_layout.addLayout(input_header_layout)
|
||||
input_layout.addWidget(self.source_text)
|
||||
|
||||
# 翻译按钮
|
||||
self.translate_btn = QPushButton("开始翻译")
|
||||
self.translate_btn.setFixedHeight(50)
|
||||
self.translate_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 8px; font-size: 16px; font-weight: bold;"
|
||||
)
|
||||
self.translate_btn.clicked.connect(self.start_translation)
|
||||
|
||||
# 倒计时提示区域(初始隐藏)
|
||||
self.countdown_container = QWidget()
|
||||
self.countdown_container.setVisible(False)
|
||||
countdown_layout = QHBoxLayout(self.countdown_container)
|
||||
countdown_layout.setContentsMargins(0, 5, 0, 5)
|
||||
|
||||
countdown_icon = QLabel("⏳")
|
||||
countdown_icon.setStyleSheet("font-size: 16px; color: #d69e2e;")
|
||||
|
||||
self.countdown_label = QLabel("大模型正在翻译中,预计剩余时间:60秒")
|
||||
self.countdown_label.setStyleSheet("color: #d69e2e; font-weight: bold;")
|
||||
|
||||
countdown_layout.addWidget(countdown_icon)
|
||||
countdown_layout.addWidget(self.countdown_label)
|
||||
countdown_layout.addStretch()
|
||||
|
||||
# 译文结果区域
|
||||
output_layout = QVBoxLayout()
|
||||
|
||||
output_header_layout = QHBoxLayout()
|
||||
output_label = QLabel("译文结果")
|
||||
output_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
output_buttons_layout = QHBoxLayout()
|
||||
export_word_btn = QPushButton("导出 Word")
|
||||
export_word_btn.setFixedSize(120, 32)
|
||||
export_word_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px; margin-right: 10px;"
|
||||
)
|
||||
export_word_btn.clicked.connect(self.export_word)
|
||||
|
||||
copy_btn = QPushButton("复制内容")
|
||||
copy_btn.setFixedSize(120, 32)
|
||||
copy_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
copy_btn.clicked.connect(self.copy_result)
|
||||
|
||||
output_buttons_layout.addWidget(export_word_btn)
|
||||
output_buttons_layout.addWidget(copy_btn)
|
||||
|
||||
output_header_layout.addWidget(output_label)
|
||||
output_header_layout.addStretch()
|
||||
output_header_layout.addLayout(output_buttons_layout)
|
||||
|
||||
self.result_text = QTextEdit()
|
||||
self.result_text.setReadOnly(True)
|
||||
self.result_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px; min-height: 150px;"
|
||||
)
|
||||
|
||||
output_layout.addLayout(output_header_layout)
|
||||
output_layout.addWidget(self.result_text)
|
||||
|
||||
# 将所有组件添加到主布局
|
||||
main_layout.addWidget(title_bar)
|
||||
main_layout.addLayout(model_layout)
|
||||
main_layout.addLayout(input_layout)
|
||||
main_layout.addWidget(self.translate_btn)
|
||||
main_layout.addWidget(self.countdown_container)
|
||||
main_layout.addLayout(output_layout)
|
||||
|
||||
# 状态栏
|
||||
self.status_bar = QStatusBar()
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.status_label = QLabel()
|
||||
self.status_bar.addWidget(self.status_label)
|
||||
|
||||
# 初始化上下文编辑框(用于存储设置)
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setVisible(False)
|
||||
|
||||
def init_status_bar_timer(self):
|
||||
"""初始化状态栏定时器"""
|
||||
self.status_timer = QTimer()
|
||||
self.status_timer.setInterval(1000) # 每秒更新一次
|
||||
self.status_timer.timeout.connect(self.update_status_bar)
|
||||
self.status_timer.start()
|
||||
|
||||
def update_status_bar(self):
|
||||
"""更新状态栏显示"""
|
||||
status_text = self.system_monitor.get_status_text()
|
||||
self.status_label.setText(status_text)
|
||||
|
||||
def load_default_model(self):
|
||||
"""加载默认模型"""
|
||||
if os.path.exists(self.default_model_path):
|
||||
self.model_status_label.setText("模型加载中...")
|
||||
if self.translator.load_model(self.default_model_path):
|
||||
self.model_status_label.setText("● 模型就绪")
|
||||
self.model_status_label.setStyleSheet("color: #38a169;")
|
||||
self.model_info_label.setText(f"{self.translator.get_model_info()}")
|
||||
else:
|
||||
self.model_status_label.setText("● 模型加载失败")
|
||||
self.model_status_label.setStyleSheet("color: #e53e3e;")
|
||||
else:
|
||||
self.model_status_label.setText("● 模型文件不存在")
|
||||
self.model_status_label.setStyleSheet("color: #e53e3e;")
|
||||
|
||||
def open_settings(self):
|
||||
"""打开设置对话框"""
|
||||
dialog = SettingsDialog(self)
|
||||
dialog.exec()
|
||||
|
||||
def start_countdown(self):
|
||||
"""开始60秒倒计时"""
|
||||
self.countdown_seconds = 60
|
||||
self.countdown_container.setVisible(True)
|
||||
self.update_countdown_display()
|
||||
|
||||
# 创建倒计时定时器
|
||||
self.countdown_timer = QTimer()
|
||||
self.countdown_timer.setInterval(1000) # 每秒触发一次
|
||||
self.countdown_timer.timeout.connect(self.update_countdown)
|
||||
self.countdown_timer.start()
|
||||
|
||||
def update_countdown(self):
|
||||
"""更新倒计时"""
|
||||
self.countdown_seconds -= 1
|
||||
self.update_countdown_display()
|
||||
|
||||
if self.countdown_seconds <= 0:
|
||||
self.stop_countdown()
|
||||
|
||||
def update_countdown_display(self):
|
||||
"""更新倒计时显示"""
|
||||
if self.countdown_label:
|
||||
self.countdown_label.setText(f"大模型正在翻译中,预计剩余时间:{self.countdown_seconds}秒")
|
||||
|
||||
def stop_countdown(self):
|
||||
"""停止倒计时"""
|
||||
if self.countdown_timer:
|
||||
self.countdown_timer.stop()
|
||||
self.countdown_timer = None
|
||||
|
||||
self.countdown_container.setVisible(False)
|
||||
|
||||
def import_word(self):
|
||||
"""导入Word文件"""
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self, "导入Word文件", "", "Word文件 (*.docx)"
|
||||
)
|
||||
if file_path:
|
||||
try:
|
||||
text = self.word_handler.import_docx(file_path)
|
||||
self.source_text.setText(text)
|
||||
QMessageBox.information(self, "成功", "Word文件导入成功")
|
||||
except Exception as e:
|
||||
logger.error(f"导入Word文件失败: {e}")
|
||||
QMessageBox.critical(self, "错误", f"Word文件导入失败: {str(e)}")
|
||||
|
||||
def export_word(self):
|
||||
"""导出Word文件"""
|
||||
result_text = self.result_text.toPlainText()
|
||||
if not result_text.strip():
|
||||
QMessageBox.warning(self, "警告", "译文结果为空,无法导出")
|
||||
return
|
||||
|
||||
file_path, _ = QFileDialog.getSaveFileName(
|
||||
self, "导出Word文件", "", "Word文件 (*.docx)"
|
||||
)
|
||||
if file_path:
|
||||
try:
|
||||
self.word_handler.export_docx(file_path, result_text)
|
||||
QMessageBox.information(self, "成功", "Word文件导出成功")
|
||||
except Exception as e:
|
||||
logger.error(f"导出Word文件失败: {e}")
|
||||
QMessageBox.critical(self, "错误", f"Word文件导出失败: {str(e)}")
|
||||
|
||||
def copy_result(self):
|
||||
"""复制译文结果"""
|
||||
result_text = self.result_text.toPlainText()
|
||||
if result_text.strip():
|
||||
from PySide6.QtGui import QClipboard
|
||||
from PySide6.QtWidgets import QApplication
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(result_text)
|
||||
QMessageBox.information(self, "成功", "译文已复制到剪贴板")
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "译文结果为空,无法复制")
|
||||
|
||||
def start_translation(self):
|
||||
"""开始翻译"""
|
||||
source_text = self.source_text.toPlainText().strip()
|
||||
if not source_text:
|
||||
QMessageBox.warning(self, "警告", "原文内容为空,无法翻译")
|
||||
return
|
||||
|
||||
if not hasattr(self.translator, 'llama_cpp_available') or not self.translator.llama_cpp_available:
|
||||
QMessageBox.warning(self, "警告", "llama-cpp-python库未安装,无法执行翻译功能")
|
||||
return
|
||||
|
||||
if not self.translator.is_ready:
|
||||
QMessageBox.warning(self, "警告", "模型未就绪,无法翻译")
|
||||
return
|
||||
|
||||
# 禁用翻译按钮
|
||||
self.translate_btn.setEnabled(False)
|
||||
self.translate_btn.setText("翻译中...")
|
||||
|
||||
# 开始倒计时
|
||||
self.start_countdown()
|
||||
|
||||
# 获取上下文和术语
|
||||
context = self.context_edit.toPlainText().strip()
|
||||
terms = self.terms if self.terms else None
|
||||
|
||||
# 执行翻译(在后台线程中执行,避免UI卡顿)
|
||||
from PySide6.QtCore import QThread, Signal
|
||||
|
||||
class TranslationThread(QThread):
|
||||
finished = Signal(str)
|
||||
|
||||
def __init__(self, translator, text, context, terms):
|
||||
super().__init__()
|
||||
self.translator = translator
|
||||
self.text = text
|
||||
self.context = context
|
||||
self.terms = terms
|
||||
|
||||
def run(self):
|
||||
result = self.translator.translate(self.text, self.context, self.terms)
|
||||
self.finished.emit(result)
|
||||
|
||||
self.translation_thread = TranslationThread(self.translator, source_text, context, terms)
|
||||
self.translation_thread.finished.connect(self.on_translation_finished)
|
||||
self.translation_thread.start()
|
||||
|
||||
def on_translation_finished(self, result):
|
||||
"""翻译完成回调"""
|
||||
# 停止倒计时
|
||||
self.stop_countdown()
|
||||
|
||||
# 启用翻译按钮
|
||||
self.translate_btn.setEnabled(True)
|
||||
self.translate_btn.setText("开始翻译")
|
||||
|
||||
if result:
|
||||
self.result_text.setText(result)
|
||||
else:
|
||||
QMessageBox.critical(self, "错误", "翻译失败,请检查日志")
|
||||
|
||||
# 修复导入问题
|
||||
from PySide6.QtWidgets import QApplication
|
||||
635
ui/main_window_new.py
Normal file
635
ui/main_window_new.py
Normal file
@@ -0,0 +1,635 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QPushButton,
|
||||
QLineEdit, QLabel, QGroupBox, QScrollArea, QToolButton, QStatusBar,
|
||||
QFileDialog, QMessageBox, QListWidget, QListWidgetItem, QFrame, QSplitter,
|
||||
QDialog, QProgressBar, QGridLayout
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer, QSize, QPropertyAnimation, QEasingCurve
|
||||
from PySide6.QtGui import QFont, QPalette, QColor
|
||||
from utils.word_handler import WordHandler
|
||||
from utils.system_monitor import SystemMonitor
|
||||
from translator import Translator
|
||||
from utils.logger import logger
|
||||
import os
|
||||
|
||||
class SettingsDialog(QDialog):
|
||||
"""设置对话框,包含高级辅助功能"""
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("设置 - 高级辅助")
|
||||
self.setMinimumSize(500, 600)
|
||||
self.setModal(True)
|
||||
|
||||
# 从父窗口获取数据
|
||||
self.parent_window = parent
|
||||
self.terms = parent.terms if parent else []
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
# 加载现有数据
|
||||
self.load_existing_data()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化设置对话框UI"""
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 20)
|
||||
|
||||
# 标题
|
||||
title_label = QLabel("高级辅助设置")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(18)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d; margin-bottom: 10px;")
|
||||
|
||||
# 文本背景/场景介绍
|
||||
context_group = QGroupBox("文本背景 / 场景介绍")
|
||||
context_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
context_layout = QVBoxLayout(context_group)
|
||||
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setPlaceholderText("例如:这是一份关于建筑工程的合同...")
|
||||
self.context_edit.setFixedHeight(100)
|
||||
self.context_edit.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
context_layout.addWidget(self.context_edit)
|
||||
|
||||
# 术语定义
|
||||
terms_group = QGroupBox("术语簿 (定义 A=B)")
|
||||
terms_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
terms_layout = QVBoxLayout(terms_group)
|
||||
|
||||
# 术语列表
|
||||
self.terms_list = QListWidget()
|
||||
self.terms_list.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; min-height: 150px;"
|
||||
)
|
||||
|
||||
# 术语输入区域
|
||||
terms_input_layout = QHBoxLayout()
|
||||
self.term_input = QLineEdit()
|
||||
self.term_input.setPlaceholderText("输入术语格式:原文 = 译文")
|
||||
self.term_input.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
add_term_btn = QPushButton("添加")
|
||||
add_term_btn.setFixedSize(80, 32)
|
||||
add_term_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
add_term_btn.clicked.connect(self.add_term)
|
||||
|
||||
terms_input_layout.addWidget(self.term_input)
|
||||
terms_input_layout.addWidget(add_term_btn)
|
||||
|
||||
# 术语操作按钮
|
||||
terms_buttons_layout = QHBoxLayout()
|
||||
|
||||
delete_term_btn = QPushButton("删除选中")
|
||||
delete_term_btn.setFixedSize(100, 32)
|
||||
delete_term_btn.setStyleSheet(
|
||||
"background-color: #e53e3e; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
delete_term_btn.clicked.connect(self.delete_selected_term)
|
||||
|
||||
clear_terms_btn = QPushButton("清空所有")
|
||||
clear_terms_btn.setFixedSize(100, 32)
|
||||
clear_terms_btn.setStyleSheet(
|
||||
"background-color: #a0aec0; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
clear_terms_btn.clicked.connect(self.clear_all_terms)
|
||||
|
||||
terms_buttons_layout.addWidget(delete_term_btn)
|
||||
terms_buttons_layout.addWidget(clear_terms_btn)
|
||||
terms_buttons_layout.addStretch()
|
||||
|
||||
terms_layout.addWidget(self.terms_list)
|
||||
terms_layout.addLayout(terms_input_layout)
|
||||
terms_layout.addLayout(terms_buttons_layout)
|
||||
|
||||
# 按钮区域
|
||||
buttons_layout = QHBoxLayout()
|
||||
|
||||
save_btn = QPushButton("保存并应用")
|
||||
save_btn.setFixedSize(120, 40)
|
||||
save_btn.setStyleSheet(
|
||||
"background-color: #38a169; color: white; border: none; border-radius: 6px; font-weight: bold;"
|
||||
)
|
||||
save_btn.clicked.connect(self.save_and_apply)
|
||||
|
||||
cancel_btn = QPushButton("取消")
|
||||
cancel_btn.setFixedSize(120, 40)
|
||||
cancel_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
cancel_btn.clicked.connect(self.reject)
|
||||
|
||||
buttons_layout.addStretch()
|
||||
buttons_layout.addWidget(cancel_btn)
|
||||
buttons_layout.addWidget(save_btn)
|
||||
|
||||
# 添加到主布局
|
||||
main_layout.addWidget(title_label)
|
||||
main_layout.addWidget(context_group)
|
||||
main_layout.addWidget(terms_group)
|
||||
main_layout.addStretch()
|
||||
main_layout.addLayout(buttons_layout)
|
||||
|
||||
def load_existing_data(self):
|
||||
"""加载现有数据"""
|
||||
if self.parent_window:
|
||||
# 加载上下文
|
||||
if hasattr(self.parent_window, 'context_edit'):
|
||||
self.context_edit.setText(self.parent_window.context_edit.toPlainText())
|
||||
|
||||
# 加载术语
|
||||
for term in self.terms:
|
||||
self.terms_list.addItem(term)
|
||||
|
||||
def add_term(self):
|
||||
"""添加术语定义"""
|
||||
term_text = self.term_input.text().strip()
|
||||
if term_text:
|
||||
if "=" in term_text:
|
||||
self.terms.append(term_text)
|
||||
self.terms_list.addItem(term_text)
|
||||
self.term_input.clear()
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "术语格式不正确,请使用 '原文 = 译文' 格式")
|
||||
|
||||
def delete_selected_term(self):
|
||||
"""删除选中的术语"""
|
||||
selected_items = self.terms_list.selectedItems()
|
||||
if not selected_items:
|
||||
QMessageBox.warning(self, "警告", "请先选择要删除的术语")
|
||||
return
|
||||
|
||||
for item in selected_items:
|
||||
term_text = item.text()
|
||||
if term_text in self.terms:
|
||||
self.terms.remove(term_text)
|
||||
self.terms_list.takeItem(self.terms_list.row(item))
|
||||
|
||||
def clear_all_terms(self):
|
||||
"""清空所有术语"""
|
||||
if self.terms_list.count() == 0:
|
||||
return
|
||||
|
||||
reply = QMessageBox.question(
|
||||
self, "确认", "确定要清空所有术语吗?",
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.terms.clear()
|
||||
self.terms_list.clear()
|
||||
|
||||
def save_and_apply(self):
|
||||
"""保存并应用设置"""
|
||||
# 保存到父窗口
|
||||
if self.parent_window:
|
||||
# 保存上下文
|
||||
if hasattr(self.parent_window, 'context_edit'):
|
||||
self.parent_window.context_edit.setText(self.context_edit.toPlainText())
|
||||
|
||||
# 保存术语
|
||||
self.parent_window.terms = self.terms.copy()
|
||||
|
||||
# 更新术语列表显示(如果父窗口有显示的话)
|
||||
if hasattr(self.parent_window, 'terms_list'):
|
||||
self.parent_window.terms_list.clear()
|
||||
for term in self.terms:
|
||||
self.parent_window.terms_list.addItem(term)
|
||||
|
||||
QMessageBox.information(self, "成功", "设置已保存并应用")
|
||||
self.accept()
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("PrivaTrans")
|
||||
self.setMinimumSize(800, 600)
|
||||
|
||||
# 初始化组件
|
||||
self.translator = Translator()
|
||||
self.system_monitor = SystemMonitor()
|
||||
self.word_handler = WordHandler()
|
||||
|
||||
# 默认模型路径
|
||||
self.default_model_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "models", "HY-MT1.5-1.8B_bf16_Q4_K_M.gguf")
|
||||
|
||||
# 术语列表
|
||||
self.terms = []
|
||||
|
||||
# 倒计时相关
|
||||
self.countdown_timer = None
|
||||
self.countdown_seconds = 60
|
||||
self.countdown_label = None
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
# 初始化状态栏定时器
|
||||
self.init_status_bar_timer()
|
||||
|
||||
# 加载默认模型
|
||||
self.load_default_model()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI界面"""
|
||||
# 主布局
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 10)
|
||||
|
||||
# 顶部标题栏
|
||||
title_bar = QWidget()
|
||||
title_bar_layout = QHBoxLayout(title_bar)
|
||||
title_bar_layout.setContentsMargins(0, 0, 0, 0)
|
||||
title_bar_layout.setSpacing(0)
|
||||
|
||||
# 应用标题
|
||||
title_label = QLabel("PrivaTrans")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(24)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d;")
|
||||
|
||||
# 右侧设置按钮
|
||||
self.settings_btn = QPushButton("⚙ 设置")
|
||||
self.settings_btn.setFixedSize(80, 36)
|
||||
self.settings_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #e2e8f0;
|
||||
color: #2d3748;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #cbd5e0;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #a0aec0;
|
||||
}
|
||||
""")
|
||||
self.settings_btn.clicked.connect(self.open_settings)
|
||||
|
||||
title_bar_layout.addWidget(title_label)
|
||||
title_bar_layout.addStretch()
|
||||
title_bar_layout.addWidget(self.settings_btn)
|
||||
|
||||
# 模型信息和更换按钮
|
||||
model_layout = QHBoxLayout()
|
||||
|
||||
self.model_status_label = QLabel()
|
||||
self.model_status_label.setStyleSheet("color: #2d3748;")
|
||||
|
||||
self.model_info_label = QLabel()
|
||||
self.model_info_label.setStyleSheet("color: #2d3748; font-weight: bold;")
|
||||
|
||||
self.change_model_btn = QPushButton("更换模型")
|
||||
self.change_model_btn.setFixedSize(100, 32)
|
||||
self.change_model_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
self.change_model_btn.clicked.connect(self.change_model)
|
||||
|
||||
model_layout.addWidget(self.model_status_label)
|
||||
model_layout.addWidget(self.model_info_label)
|
||||
model_layout.addStretch()
|
||||
model_layout.addWidget(self.change_model_btn)
|
||||
|
||||
# 原文输入区域
|
||||
input_layout = QVBoxLayout()
|
||||
|
||||
input_header_layout = QHBoxLayout()
|
||||
input_label = QLabel("原文内容")
|
||||
input_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
import_word_btn = QPushButton("导入 Word")
|
||||
import_word_btn.setFixedSize(120, 32)
|
||||
import_word_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
import_word_btn.clicked.connect(self.import_word)
|
||||
|
||||
input_header_layout.addWidget(input_label)
|
||||
input_header_layout.addStretch()
|
||||
input_header_layout.addWidget(import_word_btn)
|
||||
|
||||
self.source_text = QTextEdit()
|
||||
self.source_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px; min-height: 150px;"
|
||||
)
|
||||
|
||||
input_layout.addLayout(input_header_layout)
|
||||
input_layout.addWidget(self.source_text)
|
||||
|
||||
# 翻译按钮
|
||||
self.translate_btn = QPushButton("开始翻译")
|
||||
self.translate_btn.setFixedHeight(50)
|
||||
self.translate_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 8px; font-size: 16px; font-weight: bold;"
|
||||
)
|
||||
self.translate_btn.clicked.connect(self.start_translation)
|
||||
|
||||
# 倒计时提示区域(初始隐藏)
|
||||
self.countdown_container = QWidget()
|
||||
self.countdown_container.setVisible(False)
|
||||
countdown_layout = QHBoxLayout(self.countdown_container)
|
||||
countdown_layout.setContentsMargins(0, 5, 0, 5)
|
||||
|
||||
countdown_icon = QLabel("⏳")
|
||||
countdown_icon.setStyleSheet("font-size: 16px; color: #d69e2e;")
|
||||
|
||||
self.countdown_label = QLabel("大模型正在翻译中,预计剩余时间:60秒")
|
||||
self.countdown_label.setStyleSheet("color: #d69e2e; font-weight: bold;")
|
||||
|
||||
countdown_layout.addWidget(countdown_icon)
|
||||
countdown_layout.addWidget(self.countdown_label)
|
||||
countdown_layout.addStretch()
|
||||
|
||||
# 译文结果区域
|
||||
output_layout = QVBoxLayout()
|
||||
|
||||
output_header_layout = QHBoxLayout()
|
||||
output_label = QLabel("译文结果")
|
||||
output_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
output_buttons_layout = QHBoxLayout()
|
||||
export_word_btn = QPushButton("导出 Word")
|
||||
export_word_btn.setFixedSize(120, 32)
|
||||
export_word_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px; margin-right: 10px;"
|
||||
)
|
||||
export_word_btn.clicked.connect(self.export_word)
|
||||
|
||||
copy_btn = QPushButton("复制内容")
|
||||
copy_btn.setFixedSize(120, 32)
|
||||
copy_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
copy_btn.clicked.connect(self.copy_result)
|
||||
|
||||
output_buttons_layout.addWidget(export_word_btn)
|
||||
output_buttons_layout.addWidget(copy_btn)
|
||||
|
||||
output_header_layout.addWidget(output_label)
|
||||
output_header_layout.addStretch()
|
||||
output_header_layout.addLayout(output_buttons_layout)
|
||||
|
||||
self.result_text = QTextEdit()
|
||||
self.result_text.setReadOnly(True)
|
||||
self.result_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px; min-height: 150px;"
|
||||
)
|
||||
|
||||
output_layout.addLayout(output_header_layout)
|
||||
output_layout.addWidget(self.result_text)
|
||||
|
||||
# 将所有组件添加到主布局
|
||||
main_layout.addWidget(title_bar)
|
||||
main_layout.addLayout(model_layout)
|
||||
main_layout.addLayout(input_layout)
|
||||
main_layout.addWidget(self.translate_btn)
|
||||
main_layout.addWidget(self.countdown_container)
|
||||
main_layout.addLayout(output_layout)
|
||||
|
||||
# 状态栏
|
||||
self.status_bar = QStatusBar()
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.status_label = QLabel()
|
||||
self.status_bar.addWidget(self.status_label)
|
||||
|
||||
# 初始化上下文编辑框(用于存储设置)
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setVisible(False)
|
||||
|
||||
def init_status_bar_timer(self):
|
||||
"""初始化状态栏定时器"""
|
||||
self.status_timer = QTimer()
|
||||
self.status_timer.setInterval(1000) # 每秒更新一次
|
||||
self.status_timer.timeout.connect(self.update_status_bar)
|
||||
self.status_timer.start()
|
||||
|
||||
def update_status_bar(self):
|
||||
"""更新状态栏显示"""
|
||||
status_text = self.system_monitor.get_status_text()
|
||||
self.status_label.setText(status_text)
|
||||
|
||||
def load_default_model(self):
|
||||
"""加载默认模型"""
|
||||
if os.path.exists(self.default_model_path):
|
||||
self.model_status_label.setText("模型加载中...")
|
||||
if self.translator.load_model(self.default_model_path):
|
||||
self.model_status_label.setText("● 模型就绪")
|
||||
self.model_status_label.setStyleSheet("color: #38a169;")
|
||||
self.model_info_label.setText(f"{self.translator.get_model_info()}")
|
||||
else:
|
||||
self.model_status_label.setText("● 模型加载失败")
|
||||
self.model_status_label.setStyleSheet("color: #e53e3e;")
|
||||
else:
|
||||
self.model_status_label.setText("● 模型文件不存在")
|
||||
self.model_status_label.setStyleSheet("color: #e53e3e;")
|
||||
|
||||
def change_model(self):
|
||||
"""更换模型"""
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self, "选择模型文件", "", "GGUF模型文件 (*.gguf)"
|
||||
)
|
||||
if file_path:
|
||||
self.model_status_label.setText("模型加载中...")
|
||||
if self.translator.load_model(file_path):
|
||||
self.model_status_label.setText("● 模型就绪")
|
||||
self.model_status_label.setStyleSheet("color: #38a169;")
|
||||
self.model_info_label.setText(f"{self.translator.get_model_info()}")
|
||||
QMessageBox.information(self, "成功", "模型加载成功")
|
||||
else:
|
||||
self.model_status_label.setText("● 模型加载失败")
|
||||
self.model_status_label.setStyleSheet("color: #e53e3e;")
|
||||
QMessageBox.critical(self, "错误", "模型加载失败")
|
||||
|
||||
def open_settings(self):
|
||||
"""打开设置对话框"""
|
||||
dialog = SettingsDialog(self)
|
||||
dialog.exec()
|
||||
|
||||
def start_countdown(self):
|
||||
"""开始60秒倒计时"""
|
||||
self.countdown_seconds = 60
|
||||
self.countdown_container.setVisible(True)
|
||||
self.update_countdown_display()
|
||||
|
||||
# 创建倒计时定时器
|
||||
self.countdown_timer = QTimer()
|
||||
self.countdown_timer.setInterval(1000) # 每秒触发一次
|
||||
self.countdown_timer.timeout.connect(self.update_countdown)
|
||||
self.countdown_timer.start()
|
||||
|
||||
def update_countdown(self):
|
||||
"""更新倒计时"""
|
||||
self.countdown_seconds -= 1
|
||||
self.update_countdown_display()
|
||||
|
||||
if self.countdown_seconds <= 0:
|
||||
self.stop_countdown()
|
||||
|
||||
def update_countdown_display(self):
|
||||
"""更新倒计时显示"""
|
||||
if self.countdown_label:
|
||||
self.countdown_label.setText(f"大模型正在翻译中,预计剩余时间:{self.countdown_seconds}秒")
|
||||
|
||||
def stop_countdown(self):
|
||||
"""停止倒计时"""
|
||||
if self.countdown_timer:
|
||||
self.countdown_timer.stop()
|
||||
self.countdown_timer = None
|
||||
|
||||
self.countdown_container.setVisible(False)
|
||||
|
||||
def import_word(self):
|
||||
"""导入Word文件"""
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self, "导入Word文件", "", "Word文件 (*.docx)"
|
||||
)
|
||||
if file_path:
|
||||
try:
|
||||
text = self.word_handler.import_docx(file_path)
|
||||
self.source_text.setText(text)
|
||||
QMessageBox.information(self, "成功", "Word文件导入成功")
|
||||
except Exception as e:
|
||||
logger.error(f"导入Word文件失败: {e}")
|
||||
QMessageBox.critical(self, "错误", f"Word文件导入失败: {str(e)}")
|
||||
|
||||
def export_word(self):
|
||||
"""导出Word文件"""
|
||||
result_text = self.result_text.toPlainText()
|
||||
if not result_text.strip():
|
||||
QMessageBox.warning(self, "警告", "译文结果为空,无法导出")
|
||||
return
|
||||
|
||||
file_path, _ = QFileDialog.getSaveFileName(
|
||||
self, "导出Word文件", "", "Word文件 (*.docx)"
|
||||
)
|
||||
if file_path:
|
||||
try:
|
||||
self.word_handler.export_docx(file_path, result_text)
|
||||
QMessageBox.information(self, "成功", "Word文件导出成功")
|
||||
except Exception as e:
|
||||
logger.error(f"导出Word文件失败: {e}")
|
||||
QMessageBox.critical(self, "错误", f"Word文件导出失败: {str(e)}")
|
||||
|
||||
def copy_result(self):
|
||||
"""复制译文结果"""
|
||||
result_text = self.result_text.toPlainText()
|
||||
if result_text.strip():
|
||||
from PySide6.QtGui import QClipboard
|
||||
from PySide6.QtWidgets import QApplication
|
||||
clipboard = QApplication.clipboard()
|
||||
clipboard.setText(result_text)
|
||||
QMessageBox.information(self, "成功", "译文已复制到剪贴板")
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "译文结果为空,无法复制")
|
||||
|
||||
def start_translation(self):
|
||||
"""开始翻译"""
|
||||
source_text = self.source_text.toPlainText().strip()
|
||||
if not source_text:
|
||||
QMessageBox.warning(self, "警告", "原文内容为空,无法翻译")
|
||||
return
|
||||
|
||||
if not hasattr(self.translator, 'llama_cpp_available') or not self.translator.llama_cpp_available:
|
||||
QMessageBox.warning(self, "警告", "llama-cpp-python库未安装,无法执行翻译功能")
|
||||
return
|
||||
|
||||
if not self.translator.is_ready:
|
||||
QMessageBox.warning(self, "警告", "模型未就绪,无法翻译")
|
||||
return
|
||||
|
||||
# 禁用翻译按钮
|
||||
self.translate_btn.setEnabled(False)
|
||||
self.translate_btn.setText("翻译中...")
|
||||
|
||||
# 开始倒计时
|
||||
self.start_countdown()
|
||||
|
||||
# 获取上下文和术语
|
||||
context = self.context_edit.toPlainText().strip()
|
||||
terms = self.terms if self.terms else None
|
||||
|
||||
# 执行翻译(在后台线程中执行,避免UI卡顿)
|
||||
from PySide6.QtCore import QThread, Signal
|
||||
|
||||
class TranslationThread(QThread):
|
||||
finished = Signal(str)
|
||||
|
||||
def __init__(self, translator, text, context, terms):
|
||||
super().__init__()
|
||||
self.translator = translator
|
||||
self.text = text
|
||||
self.context = context
|
||||
self.terms = terms
|
||||
|
||||
def run(self):
|
||||
result = self.translator.translate(self.text, self.context, self.terms)
|
||||
self.finished.emit(result)
|
||||
|
||||
self.translation_thread = TranslationThread(self.translator, source_text, context, terms)
|
||||
self.translation_thread.finished.connect(self.on_translation_finished)
|
||||
self.translation_thread.start()
|
||||
|
||||
def on_translation_finished(self, result):
|
||||
"""翻译完成回调"""
|
||||
# 停止倒计时
|
||||
self.stop_countdown()
|
||||
|
||||
# 启用翻译按钮
|
||||
self.translate_btn.setEnabled(True)
|
||||
self.translate_btn.setText("开始翻译")
|
||||
|
||||
if result:
|
||||
self.result_text.setText(result)
|
||||
else:
|
||||
QMessageBox.critical(self, "错误", "翻译失败,请检查日志")
|
||||
|
||||
# 修复导入问题
|
||||
from PySide6.QtWidgets import QApplication
|
||||
475
ui/main_window_simple.py
Normal file
475
ui/main_window_simple.py
Normal file
@@ -0,0 +1,475 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QPushButton,
|
||||
QLineEdit, QLabel, QGroupBox, QScrollArea, QToolButton, QStatusBar,
|
||||
QFileDialog, QMessageBox, QListWidget, QListWidgetItem, QFrame, QSplitter,
|
||||
QDialog, QProgressBar, QGridLayout
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer, QSize, QPropertyAnimation, QEasingCurve
|
||||
from PySide6.QtGui import QFont, QPalette, QColor
|
||||
from utils.logger import logger
|
||||
import os
|
||||
|
||||
class SettingsDialog(QDialog):
|
||||
"""设置对话框,包含高级辅助功能"""
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setWindowTitle("设置 - 高级辅助")
|
||||
self.setMinimumSize(500, 600)
|
||||
self.setModal(True)
|
||||
|
||||
# 从父窗口获取数据
|
||||
self.parent_window = parent
|
||||
self.terms = parent.terms if parent else []
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
# 加载现有数据
|
||||
self.load_existing_data()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化设置对话框UI"""
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 20)
|
||||
|
||||
# 标题
|
||||
title_label = QLabel("高级辅助设置")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(18)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d; margin-bottom: 10px;")
|
||||
|
||||
# 文本背景/场景介绍
|
||||
context_group = QGroupBox("文本背景 / 场景介绍")
|
||||
context_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
context_layout = QVBoxLayout(context_group)
|
||||
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setPlaceholderText("例如:这是一份关于建筑工程的合同...")
|
||||
self.context_edit.setFixedHeight(100)
|
||||
self.context_edit.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
context_layout.addWidget(self.context_edit)
|
||||
|
||||
# 术语定义
|
||||
terms_group = QGroupBox("术语簿 (定义 A=B)")
|
||||
terms_group.setStyleSheet("""
|
||||
QGroupBox {
|
||||
font-weight: bold;
|
||||
color: #4a5568;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 8px;
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
left: 10px;
|
||||
padding: 0 5px 0 5px;
|
||||
}
|
||||
""")
|
||||
|
||||
terms_layout = QVBoxLayout(terms_group)
|
||||
|
||||
# 术语列表
|
||||
self.terms_list = QListWidget()
|
||||
self.terms_list.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; min-height: 150px;"
|
||||
)
|
||||
|
||||
# 术语输入区域
|
||||
terms_input_layout = QHBoxLayout()
|
||||
self.term_input = QLineEdit()
|
||||
self.term_input.setPlaceholderText("输入术语格式:原文 = 译文")
|
||||
self.term_input.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
add_term_btn = QPushButton("添加")
|
||||
add_term_btn.setFixedSize(80, 32)
|
||||
add_term_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
add_term_btn.clicked.connect(self.add_term)
|
||||
|
||||
terms_input_layout.addWidget(self.term_input)
|
||||
terms_input_layout.addWidget(add_term_btn)
|
||||
|
||||
# 术语操作按钮
|
||||
terms_buttons_layout = QHBoxLayout()
|
||||
|
||||
delete_term_btn = QPushButton("删除选中")
|
||||
delete_term_btn.setFixedSize(100, 32)
|
||||
delete_term_btn.setStyleSheet(
|
||||
"background-color: #e53e3e; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
delete_term_btn.clicked.connect(self.delete_selected_term)
|
||||
|
||||
clear_terms_btn = QPushButton("清空所有")
|
||||
clear_terms_btn.setFixedSize(100, 32)
|
||||
clear_terms_btn.setStyleSheet(
|
||||
"background-color: #a0aec0; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
clear_terms_btn.clicked.connect(self.clear_all_terms)
|
||||
|
||||
terms_buttons_layout.addWidget(delete_term_btn)
|
||||
terms_buttons_layout.addWidget(clear_terms_btn)
|
||||
terms_buttons_layout.addStretch()
|
||||
|
||||
terms_layout.addWidget(self.terms_list)
|
||||
terms_layout.addLayout(terms_input_layout)
|
||||
terms_layout.addLayout(terms_buttons_layout)
|
||||
|
||||
# 按钮区域
|
||||
buttons_layout = QHBoxLayout()
|
||||
|
||||
save_btn = QPushButton("保存并应用")
|
||||
save_btn.setFixedSize(120, 40)
|
||||
save_btn.setStyleSheet(
|
||||
"background-color: #38a169; color: white; border: none; border-radius: 6px; font-weight: bold;"
|
||||
)
|
||||
save_btn.clicked.connect(self.save_and_apply)
|
||||
|
||||
cancel_btn = QPushButton("取消")
|
||||
cancel_btn.setFixedSize(120, 40)
|
||||
cancel_btn.setStyleSheet(
|
||||
"background-color: #e2e8f0; color: #2d3748; border: none; border-radius: 6px;"
|
||||
)
|
||||
cancel_btn.clicked.connect(self.reject)
|
||||
|
||||
buttons_layout.addStretch()
|
||||
buttons_layout.addWidget(cancel_btn)
|
||||
buttons_layout.addWidget(save_btn)
|
||||
|
||||
# 添加到主布局
|
||||
main_layout.addWidget(title_label)
|
||||
main_layout.addWidget(context_group)
|
||||
main_layout.addWidget(terms_group)
|
||||
main_layout.addStretch()
|
||||
main_layout.addLayout(buttons_layout)
|
||||
|
||||
def load_existing_data(self):
|
||||
"""加载现有数据"""
|
||||
if self.parent_window:
|
||||
# 加载上下文
|
||||
if hasattr(self.parent_window, 'context_edit'):
|
||||
self.context_edit.setText(self.parent_window.context_edit.toPlainText())
|
||||
|
||||
# 加载术语
|
||||
for term in self.terms:
|
||||
self.terms_list.addItem(term)
|
||||
|
||||
def add_term(self):
|
||||
"""添加术语定义"""
|
||||
term_text = self.term_input.text().strip()
|
||||
if term_text:
|
||||
if "=" in term_text:
|
||||
self.terms.append(term_text)
|
||||
self.terms_list.addItem(term_text)
|
||||
self.term_input.clear()
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "术语格式不正确,请使用 '原文 = 译文' 格式")
|
||||
|
||||
def delete_selected_term(self):
|
||||
"""删除选中的术语"""
|
||||
selected_items = self.terms_list.selectedItems()
|
||||
if not selected_items:
|
||||
QMessageBox.warning(self, "警告", "请先选择要删除的术语")
|
||||
return
|
||||
|
||||
for item in selected_items:
|
||||
term_text = item.text()
|
||||
if term_text in self.terms:
|
||||
self.terms.remove(term_text)
|
||||
self.terms_list.takeItem(self.terms_list.row(item))
|
||||
|
||||
def clear_all_terms(self):
|
||||
"""清空所有术语"""
|
||||
if self.terms_list.count() == 0:
|
||||
return
|
||||
|
||||
reply = QMessageBox.question(
|
||||
self, "确认", "确定要清空所有术语吗?",
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self.terms.clear()
|
||||
self.terms_list.clear()
|
||||
|
||||
def save_and_apply(self):
|
||||
"""保存并应用设置"""
|
||||
# 保存到父窗口
|
||||
if self.parent_window:
|
||||
# 保存上下文
|
||||
if hasattr(self.parent_window, 'context_edit'):
|
||||
self.parent_window.context_edit.setText(self.context_edit.toPlainText())
|
||||
|
||||
# 保存术语
|
||||
self.parent_window.terms = self.terms.copy()
|
||||
|
||||
# 更新术语列表显示(如果父窗口有显示的话)
|
||||
if hasattr(self.parent_window, 'terms_list'):
|
||||
self.parent_window.terms_list.clear()
|
||||
for term in self.terms:
|
||||
self.parent_window.terms_list.addItem(term)
|
||||
|
||||
QMessageBox.information(self, "成功", "设置已保存并应用")
|
||||
self.accept()
|
||||
|
||||
class MainWindowSimple(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("PrivaTrans - 简化测试版")
|
||||
self.setMinimumSize(800, 600)
|
||||
|
||||
# 术语列表
|
||||
self.terms = []
|
||||
|
||||
# 倒计时相关
|
||||
self.countdown_timer = None
|
||||
self.countdown_seconds = 60
|
||||
self.countdown_label = None
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI界面"""
|
||||
# 主布局
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 10)
|
||||
|
||||
# 顶部标题栏
|
||||
title_bar = QWidget()
|
||||
title_bar_layout = QHBoxLayout(title_bar)
|
||||
title_bar_layout.setContentsMargins(0, 0, 0, 0)
|
||||
title_bar_layout.setSpacing(0)
|
||||
|
||||
# 应用标题
|
||||
title_label = QLabel("PrivaTrans")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(24)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d;")
|
||||
|
||||
# 右侧设置按钮
|
||||
self.settings_btn = QPushButton("⚙ 设置")
|
||||
self.settings_btn.setFixedSize(80, 36)
|
||||
self.settings_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #e2e8f0;
|
||||
color: #2d3748;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-weight: bold;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #cbd5e0;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #a0aec0;
|
||||
}
|
||||
""")
|
||||
self.settings_btn.clicked.connect(self.open_settings)
|
||||
|
||||
title_bar_layout.addWidget(title_label)
|
||||
title_bar_layout.addStretch()
|
||||
title_bar_layout.addWidget(self.settings_btn)
|
||||
|
||||
# 模型信息(简化版)
|
||||
model_layout = QHBoxLayout()
|
||||
|
||||
self.model_status_label = QLabel("● 测试模式 - 跳过模型加载")
|
||||
self.model_status_label.setStyleSheet("color: #38a169;")
|
||||
|
||||
self.model_info_label = QLabel("点击右上角'设置'按钮配置高级辅助")
|
||||
self.model_info_label.setStyleSheet("color: #2d3748; font-weight: bold;")
|
||||
|
||||
model_layout.addWidget(self.model_status_label)
|
||||
model_layout.addWidget(self.model_info_label)
|
||||
model_layout.addStretch()
|
||||
|
||||
# 原文输入区域
|
||||
input_layout = QVBoxLayout()
|
||||
|
||||
input_header_layout = QHBoxLayout()
|
||||
input_label = QLabel("原文内容")
|
||||
input_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
input_header_layout.addWidget(input_label)
|
||||
input_header_layout.addStretch()
|
||||
|
||||
self.source_text = QTextEdit()
|
||||
self.source_text.setPlaceholderText("在此输入要翻译的文本...")
|
||||
self.source_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px; min-height: 150px;"
|
||||
)
|
||||
|
||||
input_layout.addLayout(input_header_layout)
|
||||
input_layout.addWidget(self.source_text)
|
||||
|
||||
# 翻译按钮
|
||||
self.translate_btn = QPushButton("开始翻译 (测试倒计时)")
|
||||
self.translate_btn.setFixedHeight(50)
|
||||
self.translate_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 8px; font-size: 16px; font-weight: bold;"
|
||||
)
|
||||
self.translate_btn.clicked.connect(self.start_translation_test)
|
||||
|
||||
# 倒计时提示区域(初始隐藏)
|
||||
self.countdown_container = QWidget()
|
||||
self.countdown_container.setVisible(False)
|
||||
countdown_layout = QHBoxLayout(self.countdown_container)
|
||||
countdown_layout.setContentsMargins(0, 5, 0, 5)
|
||||
|
||||
countdown_icon = QLabel("⏳")
|
||||
countdown_icon.setStyleSheet("font-size: 16px; color: #d69e2e;")
|
||||
|
||||
self.countdown_label = QLabel("大模型正在翻译中,预计剩余时间:60秒")
|
||||
self.countdown_label.setStyleSheet("color: #d69e2e; font-weight: bold;")
|
||||
|
||||
countdown_layout.addWidget(countdown_icon)
|
||||
countdown_layout.addWidget(self.countdown_label)
|
||||
countdown_layout.addStretch()
|
||||
|
||||
# 译文结果区域
|
||||
output_layout = QVBoxLayout()
|
||||
|
||||
output_header_layout = QHBoxLayout()
|
||||
output_label = QLabel("译文结果")
|
||||
output_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
output_header_layout.addWidget(output_label)
|
||||
output_header_layout.addStretch()
|
||||
|
||||
self.result_text = QTextEdit()
|
||||
self.result_text.setReadOnly(True)
|
||||
self.result_text.setPlaceholderText("翻译结果将显示在这里...")
|
||||
self.result_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px; min-height: 150px;"
|
||||
)
|
||||
|
||||
output_layout.addLayout(output_header_layout)
|
||||
output_layout.addWidget(self.result_text)
|
||||
|
||||
# 将所有组件添加到主布局
|
||||
main_layout.addWidget(title_bar)
|
||||
main_layout.addLayout(model_layout)
|
||||
main_layout.addLayout(input_layout)
|
||||
main_layout.addWidget(self.translate_btn)
|
||||
main_layout.addWidget(self.countdown_container)
|
||||
main_layout.addLayout(output_layout)
|
||||
|
||||
# 状态栏
|
||||
self.status_bar = QStatusBar()
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.status_label = QLabel("新界面设计测试 - 设置按钮在右上角,倒计时功能已实现")
|
||||
self.status_bar.addWidget(self.status_label)
|
||||
|
||||
# 初始化上下文编辑框(用于存储设置)
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setVisible(False)
|
||||
|
||||
def open_settings(self):
|
||||
"""打开设置对话框"""
|
||||
dialog = SettingsDialog(self)
|
||||
dialog.exec()
|
||||
|
||||
def start_countdown(self):
|
||||
"""开始60秒倒计时"""
|
||||
self.countdown_seconds = 60
|
||||
self.countdown_container.setVisible(True)
|
||||
self.update_countdown_display()
|
||||
|
||||
# 创建倒计时定时器
|
||||
self.countdown_timer = QTimer()
|
||||
self.countdown_timer.setInterval(1000) # 每秒触发一次
|
||||
self.countdown_timer.timeout.connect(self.update_countdown)
|
||||
self.countdown_timer.start()
|
||||
|
||||
def update_countdown(self):
|
||||
"""更新倒计时"""
|
||||
self.countdown_seconds -= 1
|
||||
self.update_countdown_display()
|
||||
|
||||
if self.countdown_seconds <= 0:
|
||||
self.stop_countdown()
|
||||
|
||||
def update_countdown_display(self):
|
||||
"""更新倒计时显示"""
|
||||
if self.countdown_label:
|
||||
self.countdown_label.setText(f"大模型正在翻译中,预计剩余时间:{self.countdown_seconds}秒")
|
||||
|
||||
def stop_countdown(self):
|
||||
"""停止倒计时"""
|
||||
if self.countdown_timer:
|
||||
self.countdown_timer.stop()
|
||||
self.countdown_timer = None
|
||||
|
||||
self.countdown_container.setVisible(False)
|
||||
|
||||
def start_translation_test(self):
|
||||
"""开始翻译测试"""
|
||||
source_text = self.source_text.toPlainText().strip()
|
||||
if not source_text:
|
||||
QMessageBox.warning(self, "警告", "原文内容为空")
|
||||
return
|
||||
|
||||
# 禁用翻译按钮
|
||||
self.translate_btn.setEnabled(False)
|
||||
self.translate_btn.setText("翻译中...")
|
||||
|
||||
# 开始倒计时
|
||||
self.start_countdown()
|
||||
|
||||
# 获取上下文和术语
|
||||
context = self.context_edit.toPlainText().strip()
|
||||
terms = self.terms if self.terms else None
|
||||
|
||||
# 模拟翻译过程(5秒后完成)
|
||||
from PySide6.QtCore import QTimer
|
||||
self.simulation_timer = QTimer()
|
||||
self.simulation_timer.setSingleShot(True)
|
||||
self.simulation_timer.setInterval(5000) # 5秒后完成
|
||||
self.simulation_timer.timeout.connect(lambda: self.on_translation_finished(f"【测试翻译结果】\n\n原文:{source_text}\n\n译文:这是模拟的翻译结果\n\n上下文:{context if context else '无'}\n术语:{', '.join(terms) if terms else '无'}"))
|
||||
self.simulation_timer.start()
|
||||
|
||||
def on_translation_finished(self, result):
|
||||
"""翻译完成回调"""
|
||||
# 停止倒计时
|
||||
self.stop_countdown()
|
||||
|
||||
# 启用翻译按钮
|
||||
self.translate_btn.setEnabled(True)
|
||||
self.translate_btn.setText("开始翻译 (测试倒计时)")
|
||||
|
||||
if result:
|
||||
self.result_text.setText(result)
|
||||
QMessageBox.information(self, "测试完成", "翻译测试完成!\n\n✓ 设置按钮功能正常\n✓ 倒计时功能正常\n✓ 界面布局优化完成")
|
||||
|
||||
# 修复导入问题
|
||||
from PySide6.QtWidgets import QApplication
|
||||
264
ui/main_window_test.py
Normal file
264
ui/main_window_test.py
Normal file
@@ -0,0 +1,264 @@
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTextEdit, QPushButton,
|
||||
QLineEdit, QLabel, QGroupBox, QScrollArea, QToolButton, QStatusBar,
|
||||
QFileDialog, QMessageBox, QListWidget, QListWidgetItem, QFrame, QSplitter
|
||||
)
|
||||
from PySide6.QtCore import Qt, QTimer, QSize
|
||||
from PySide6.QtGui import QFont, QPalette, QColor
|
||||
from utils.logger import logger
|
||||
import os
|
||||
|
||||
class MainWindowTest(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("PrivaTrans - UI测试")
|
||||
self.setMinimumSize(800, 600)
|
||||
|
||||
# 初始化组件
|
||||
self.terms = []
|
||||
|
||||
# 初始化UI
|
||||
self.init_ui()
|
||||
|
||||
# 初始化状态栏定时器
|
||||
self.init_status_bar_timer()
|
||||
|
||||
def init_ui(self):
|
||||
"""初始化UI界面"""
|
||||
# 主布局
|
||||
central_widget = QWidget()
|
||||
self.setCentralWidget(central_widget)
|
||||
main_layout = QVBoxLayout(central_widget)
|
||||
main_layout.setSpacing(20)
|
||||
main_layout.setContentsMargins(20, 20, 20, 10)
|
||||
|
||||
# 顶部标题
|
||||
title_label = QLabel("PrivaTrans - UI测试")
|
||||
title_font = QFont()
|
||||
title_font.setPointSize(24)
|
||||
title_font.setBold(True)
|
||||
title_label.setFont(title_font)
|
||||
title_label.setStyleSheet("color: #1a365d;")
|
||||
|
||||
# 模型信息标签
|
||||
model_layout = QHBoxLayout()
|
||||
|
||||
self.model_status_label = QLabel("● UI测试模式 - 跳过模型加载")
|
||||
self.model_status_label.setStyleSheet("color: #38a169;")
|
||||
|
||||
self.model_info_label = QLabel("点击折叠/展开按钮测试功能")
|
||||
self.model_info_label.setStyleSheet("color: #2d3748; font-weight: bold;")
|
||||
|
||||
model_layout.addWidget(self.model_status_label)
|
||||
model_layout.addWidget(self.model_info_label)
|
||||
model_layout.addStretch()
|
||||
|
||||
# 高级辅助面板(可折叠)
|
||||
advanced_panel = QWidget()
|
||||
advanced_layout = QVBoxLayout(advanced_panel)
|
||||
advanced_layout.setSpacing(10)
|
||||
advanced_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# 高级辅助标题和折叠按钮
|
||||
advanced_header = QWidget()
|
||||
header_layout = QHBoxLayout(advanced_header)
|
||||
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||
header_layout.setSpacing(10)
|
||||
|
||||
advanced_title = QLabel("高级辅助 (背景与术语)")
|
||||
advanced_title.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
self.advanced_toggle = QToolButton()
|
||||
self.advanced_toggle.setText("▼")
|
||||
self.advanced_toggle.setCheckable(True)
|
||||
self.advanced_toggle.setChecked(False)
|
||||
self.advanced_toggle.setFixedSize(20, 20)
|
||||
self.advanced_toggle.setStyleSheet(
|
||||
"border: none; background: none; color: #4a5568;"
|
||||
)
|
||||
self.advanced_toggle.clicked.connect(self.toggle_advanced_panel)
|
||||
|
||||
header_layout.addWidget(advanced_title)
|
||||
header_layout.addStretch()
|
||||
header_layout.addWidget(self.advanced_toggle)
|
||||
|
||||
advanced_layout.addWidget(advanced_header)
|
||||
|
||||
# 高级辅助内容区域
|
||||
self.advanced_content = QWidget()
|
||||
content_layout = QVBoxLayout(self.advanced_content)
|
||||
content_layout.setSpacing(15)
|
||||
content_layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
# 文本背景/场景介绍
|
||||
context_label = QLabel("文本背景 / 场景介绍")
|
||||
context_label.setStyleSheet("color: #4a5568;")
|
||||
|
||||
self.context_edit = QTextEdit()
|
||||
self.context_edit.setPlaceholderText("例如:这是一份关于建筑工程的合同...")
|
||||
self.context_edit.setFixedHeight(80)
|
||||
self.context_edit.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
# 术语定义
|
||||
terms_label = QLabel("术语簿 (定义 A=B)")
|
||||
terms_label.setStyleSheet("color: #4a5568;")
|
||||
|
||||
self.terms_list = QListWidget()
|
||||
self.terms_list.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px;"
|
||||
)
|
||||
|
||||
terms_input_layout = QHBoxLayout()
|
||||
self.term_input = QLineEdit()
|
||||
self.term_input.setPlaceholderText("你好 = what's up")
|
||||
self.term_input.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 8px;"
|
||||
)
|
||||
|
||||
add_term_btn = QPushButton("+")
|
||||
add_term_btn.setFixedSize(32, 32)
|
||||
add_term_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 6px;"
|
||||
)
|
||||
add_term_btn.clicked.connect(self.add_term)
|
||||
|
||||
terms_input_layout.addWidget(self.term_input)
|
||||
terms_input_layout.addWidget(add_term_btn)
|
||||
|
||||
# 术语列表项右键菜单
|
||||
self.terms_list.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.terms_list.customContextMenuRequested.connect(self.show_term_context_menu)
|
||||
|
||||
content_layout.addWidget(context_label)
|
||||
content_layout.addWidget(self.context_edit)
|
||||
content_layout.addWidget(terms_label)
|
||||
content_layout.addWidget(self.terms_list)
|
||||
content_layout.addLayout(terms_input_layout)
|
||||
|
||||
advanced_layout.addWidget(self.advanced_content)
|
||||
|
||||
# 默认隐藏高级辅助内容
|
||||
self.advanced_content.setVisible(False)
|
||||
|
||||
# 将高级辅助面板添加到主布局
|
||||
advanced_panel.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 8px; padding: 15px; margin-top: 10px;"
|
||||
)
|
||||
|
||||
# 原文输入区域
|
||||
input_layout = QVBoxLayout()
|
||||
|
||||
input_header_layout = QHBoxLayout()
|
||||
input_label = QLabel("原文内容")
|
||||
input_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
input_header_layout.addWidget(input_label)
|
||||
input_header_layout.addStretch()
|
||||
|
||||
self.source_text = QTextEdit()
|
||||
self.source_text.setPlaceholderText("在此输入要翻译的文本...")
|
||||
self.source_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px;"
|
||||
)
|
||||
|
||||
input_layout.addLayout(input_header_layout)
|
||||
input_layout.addWidget(self.source_text)
|
||||
|
||||
# 翻译按钮
|
||||
self.translate_btn = QPushButton("开始翻译 (测试模式)")
|
||||
self.translate_btn.setFixedHeight(50)
|
||||
self.translate_btn.setStyleSheet(
|
||||
"background-color: #3182ce; color: white; border: none; border-radius: 8px; font-size: 16px; font-weight: bold;"
|
||||
)
|
||||
self.translate_btn.clicked.connect(self.start_translation_test)
|
||||
|
||||
# 译文结果区域
|
||||
output_layout = QVBoxLayout()
|
||||
|
||||
output_header_layout = QHBoxLayout()
|
||||
output_label = QLabel("译文结果")
|
||||
output_label.setStyleSheet("color: #4a5568; font-weight: bold;")
|
||||
|
||||
output_header_layout.addWidget(output_label)
|
||||
output_header_layout.addStretch()
|
||||
|
||||
self.result_text = QTextEdit()
|
||||
self.result_text.setReadOnly(True)
|
||||
self.result_text.setPlaceholderText("翻译结果将显示在这里...")
|
||||
self.result_text.setStyleSheet(
|
||||
"border: 1px solid #e2e8f0; border-radius: 6px; padding: 10px;"
|
||||
)
|
||||
|
||||
output_layout.addLayout(output_header_layout)
|
||||
output_layout.addWidget(self.result_text)
|
||||
|
||||
# 将所有组件添加到主布局
|
||||
main_layout.addWidget(title_label)
|
||||
main_layout.addLayout(model_layout)
|
||||
main_layout.addWidget(advanced_panel)
|
||||
main_layout.addLayout(input_layout)
|
||||
main_layout.addWidget(self.translate_btn)
|
||||
main_layout.addLayout(output_layout)
|
||||
|
||||
# 状态栏
|
||||
self.status_bar = QStatusBar()
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.status_label = QLabel("UI测试模式 - 折叠/展开按钮功能正常")
|
||||
self.status_bar.addWidget(self.status_label)
|
||||
|
||||
def init_status_bar_timer(self):
|
||||
"""初始化状态栏定时器"""
|
||||
self.status_timer = QTimer()
|
||||
self.status_timer.setInterval(1000) # 每秒更新一次
|
||||
self.status_timer.timeout.connect(self.update_status_bar)
|
||||
self.status_timer.start()
|
||||
|
||||
def update_status_bar(self):
|
||||
"""更新状态栏显示"""
|
||||
# 在测试模式下显示固定状态
|
||||
pass
|
||||
|
||||
def add_term(self):
|
||||
"""添加术语定义"""
|
||||
term_text = self.term_input.text().strip()
|
||||
if term_text:
|
||||
if "=" in term_text:
|
||||
self.terms.append(term_text)
|
||||
self.terms_list.addItem(term_text)
|
||||
self.term_input.clear()
|
||||
else:
|
||||
QMessageBox.warning(self, "警告", "术语格式不正确,请使用 'A = B' 格式")
|
||||
|
||||
def toggle_advanced_panel(self, checked):
|
||||
"""切换高级辅助面板的显示/隐藏状态"""
|
||||
self.advanced_content.setVisible(checked)
|
||||
self.advanced_toggle.setText("▲" if checked else "▼")
|
||||
|
||||
# 更新状态栏显示当前状态
|
||||
state = "展开" if checked else "折叠"
|
||||
self.status_label.setText(f"高级辅助面板已{state} - 按钮功能正常")
|
||||
|
||||
def show_term_context_menu(self, pos):
|
||||
"""显示术语项右键菜单"""
|
||||
from PySide6.QtWidgets import QMenu
|
||||
menu = QMenu()
|
||||
delete_action = menu.addAction("删除")
|
||||
action = menu.exec_(self.terms_list.mapToGlobal(pos))
|
||||
if action == delete_action:
|
||||
selected_items = self.terms_list.selectedItems()
|
||||
for item in selected_items:
|
||||
self.terms.remove(item.text())
|
||||
self.terms_list.takeItem(self.terms_list.row(item))
|
||||
|
||||
def start_translation_test(self):
|
||||
"""开始翻译测试"""
|
||||
source_text = self.source_text.toPlainText().strip()
|
||||
if not source_text:
|
||||
QMessageBox.warning(self, "警告", "原文内容为空")
|
||||
return
|
||||
|
||||
# 在测试模式下显示模拟结果
|
||||
self.result_text.setText(f"【测试模式】翻译结果预览:\n\n{source_text}\n\n(这是测试模式,实际翻译需要加载模型)")
|
||||
QMessageBox.information(self, "测试成功", "UI功能测试完成!\n\n✓ 折叠/展开按钮功能正常\n✓ 术语添加功能正常\n✓ 界面交互正常")
|
||||
Reference in New Issue
Block a user