|
|
|
|
@ -3,14 +3,16 @@ import sys
|
|
|
|
|
import os
|
|
|
|
|
from PyQt5.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
|
|
|
|
|
QTextEdit, QLabel, QSplitter, QFrame, QMenuBar,
|
|
|
|
|
QAction, QFileDialog, QMessageBox, QApplication)
|
|
|
|
|
QAction, QFileDialog, QMessageBox, QApplication,
|
|
|
|
|
QDialog, QLineEdit, QCheckBox, QPushButton)
|
|
|
|
|
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QTimer, QRect
|
|
|
|
|
from PyQt5.QtGui import QFont, QPalette, QColor, QIcon, QPixmap, QTextCharFormat
|
|
|
|
|
from PyQt5.QtGui import QFont, QPalette, QColor, QIcon, QPixmap, QTextCharFormat, QTextCursor, QTextDocument
|
|
|
|
|
|
|
|
|
|
from ui.word_style_ui import (WordRibbon, WordStatusBar, WordTextEdit,
|
|
|
|
|
WordStyleToolBar)
|
|
|
|
|
from services.network_service import NetworkService
|
|
|
|
|
from typing_logic import TypingLogic
|
|
|
|
|
from ui.word_style_ui import WeatherAPI
|
|
|
|
|
from file_parser import FileParser
|
|
|
|
|
|
|
|
|
|
class WeatherFetchThread(QThread):
|
|
|
|
|
@ -18,12 +20,26 @@ class WeatherFetchThread(QThread):
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
super().__init__()
|
|
|
|
|
self.network_service = NetworkService()
|
|
|
|
|
self.weather_api = WeatherAPI()
|
|
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
|
try:
|
|
|
|
|
weather_data = self.network_service.get_weather()
|
|
|
|
|
self.weather_fetched.emit(weather_data)
|
|
|
|
|
# 使用智能定位获取天气数据,自动获取用户位置
|
|
|
|
|
weather_data = self.weather_api.get_weather_data()
|
|
|
|
|
|
|
|
|
|
if weather_data:
|
|
|
|
|
self.weather_fetched.emit(weather_data)
|
|
|
|
|
else:
|
|
|
|
|
# 使用模拟数据作为后备
|
|
|
|
|
mock_data = {
|
|
|
|
|
'city': '北京',
|
|
|
|
|
'temperature': 25,
|
|
|
|
|
'description': '晴天',
|
|
|
|
|
'humidity': 45,
|
|
|
|
|
'wind_scale': 2,
|
|
|
|
|
'forecast': []
|
|
|
|
|
}
|
|
|
|
|
self.weather_fetched.emit(mock_data)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.weather_fetched.emit({'error': str(e)})
|
|
|
|
|
|
|
|
|
|
@ -50,8 +66,10 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
self.is_loading_file = False # 添加文件加载标志
|
|
|
|
|
self.imported_content = "" # 存储导入的完整内容
|
|
|
|
|
self.displayed_chars = 0 # 已显示的字符数
|
|
|
|
|
self.setup_ui()
|
|
|
|
|
|
|
|
|
|
# 初始化网络服务和WeatherAPI
|
|
|
|
|
self.network_service = NetworkService()
|
|
|
|
|
self.weather_api = WeatherAPI()
|
|
|
|
|
|
|
|
|
|
# 设置窗口属性
|
|
|
|
|
self.setWindowTitle("文档1 - MagicWord")
|
|
|
|
|
@ -63,14 +81,21 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
# 初始化UI
|
|
|
|
|
self.setup_ui()
|
|
|
|
|
|
|
|
|
|
# 连接信号
|
|
|
|
|
self.connect_signals()
|
|
|
|
|
|
|
|
|
|
# 初始化网络服务
|
|
|
|
|
self.init_network_services()
|
|
|
|
|
|
|
|
|
|
# 初始化打字逻辑
|
|
|
|
|
self.init_typing_logic()
|
|
|
|
|
|
|
|
|
|
# 连接信号和槽
|
|
|
|
|
self.connect_signals()
|
|
|
|
|
# 连接Ribbon的天气功能
|
|
|
|
|
self.ribbon.on_refresh_weather = self.refresh_weather
|
|
|
|
|
self.ribbon.on_city_changed = self.on_city_changed
|
|
|
|
|
|
|
|
|
|
# 初始化时刷新天气
|
|
|
|
|
self.refresh_weather()
|
|
|
|
|
|
|
|
|
|
def set_window_icon(self):
|
|
|
|
|
"""设置窗口图标"""
|
|
|
|
|
@ -87,6 +112,67 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
icon.addPixmap(pixmap)
|
|
|
|
|
self.setWindowIcon(icon)
|
|
|
|
|
|
|
|
|
|
def on_city_changed(self, city):
|
|
|
|
|
"""城市选择变化处理"""
|
|
|
|
|
print(f"城市选择变化: {city}")
|
|
|
|
|
if city == '自动定位':
|
|
|
|
|
self.refresh_weather() # 重新自动定位
|
|
|
|
|
else:
|
|
|
|
|
# 手动选择城市
|
|
|
|
|
print(f"手动选择城市: {city}")
|
|
|
|
|
weather_data = self.weather_api.get_weather_data(city)
|
|
|
|
|
if weather_data:
|
|
|
|
|
print(f"获取到天气数据: {weather_data}")
|
|
|
|
|
# 格式化数据以匹配状态栏期望的格式
|
|
|
|
|
formatted_data = {
|
|
|
|
|
'city': weather_data['city'],
|
|
|
|
|
'temperature': weather_data['current']['temp'],
|
|
|
|
|
'description': weather_data['current']['weather'],
|
|
|
|
|
'humidity': weather_data['current']['humidity'],
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale']
|
|
|
|
|
}
|
|
|
|
|
print(f"格式化后的数据: {formatted_data}")
|
|
|
|
|
self.update_weather_display(formatted_data)
|
|
|
|
|
else:
|
|
|
|
|
print(f"无法获取城市 {city} 的天气数据")
|
|
|
|
|
|
|
|
|
|
def refresh_weather(self):
|
|
|
|
|
"""刷新天气"""
|
|
|
|
|
current_city = self.ribbon.city_combo.currentText()
|
|
|
|
|
print(f"当前选择的城市: {current_city}")
|
|
|
|
|
if current_city == '自动定位':
|
|
|
|
|
# 使用自动定位
|
|
|
|
|
print("使用自动定位")
|
|
|
|
|
weather_data = self.weather_api.get_weather_data()
|
|
|
|
|
else:
|
|
|
|
|
# 使用选中的城市
|
|
|
|
|
print(f"使用选中的城市: {current_city}")
|
|
|
|
|
weather_data = self.weather_api.get_weather_data(current_city)
|
|
|
|
|
|
|
|
|
|
if weather_data:
|
|
|
|
|
print(f"更新天气信息: {weather_data}")
|
|
|
|
|
# 格式化数据以匹配状态栏期望的格式
|
|
|
|
|
formatted_data = {
|
|
|
|
|
'city': weather_data['city'],
|
|
|
|
|
'temperature': weather_data['current']['temp'],
|
|
|
|
|
'description': weather_data['current']['weather'],
|
|
|
|
|
'humidity': weather_data['current']['humidity'],
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale']
|
|
|
|
|
}
|
|
|
|
|
print(f"格式化后的数据: {formatted_data}")
|
|
|
|
|
self.update_weather_display(formatted_data)
|
|
|
|
|
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
|
icon_path = os.path.join(project_root, 'resources', 'icons', 'app_icon.png')
|
|
|
|
|
if os.path.exists(icon_path):
|
|
|
|
|
self.setWindowIcon(QIcon(icon_path))
|
|
|
|
|
else:
|
|
|
|
|
# 如果图标文件不存在,创建简单的Word风格图标
|
|
|
|
|
icon = QIcon()
|
|
|
|
|
pixmap = QPixmap(32, 32)
|
|
|
|
|
pixmap.fill(QColor("#2B579A"))
|
|
|
|
|
icon.addPixmap(pixmap)
|
|
|
|
|
self.setWindowIcon(icon)
|
|
|
|
|
|
|
|
|
|
def setup_ui(self):
|
|
|
|
|
"""设置Word风格的UI界面"""
|
|
|
|
|
|
|
|
|
|
@ -231,10 +317,27 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
|
|
|
|
|
# 打印布局
|
|
|
|
|
print_layout_action = QAction('打印布局', self)
|
|
|
|
|
print_layout_action.setCheckable(True)
|
|
|
|
|
print_layout_action.setChecked(True)
|
|
|
|
|
print_layout_action.triggered.connect(self.toggle_print_layout)
|
|
|
|
|
view_menu.addAction(print_layout_action)
|
|
|
|
|
|
|
|
|
|
view_menu.addSeparator()
|
|
|
|
|
|
|
|
|
|
# 天气功能
|
|
|
|
|
weather_menu = view_menu.addMenu('天气信息')
|
|
|
|
|
|
|
|
|
|
# 刷新天气
|
|
|
|
|
refresh_weather_action = QAction('刷新天气', self)
|
|
|
|
|
refresh_weather_action.setShortcut('F5')
|
|
|
|
|
refresh_weather_action.triggered.connect(self.refresh_weather)
|
|
|
|
|
weather_menu.addAction(refresh_weather_action)
|
|
|
|
|
|
|
|
|
|
# 显示详细天气
|
|
|
|
|
show_weather_action = QAction('显示详细天气', self)
|
|
|
|
|
show_weather_action.triggered.connect(self.show_detailed_weather)
|
|
|
|
|
weather_menu.addAction(show_weather_action)
|
|
|
|
|
|
|
|
|
|
# 帮助菜单
|
|
|
|
|
help_menu = menubar.addMenu('帮助(H)')
|
|
|
|
|
|
|
|
|
|
@ -318,9 +421,29 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
self.text_edit.textChanged.connect(self.on_text_changed)
|
|
|
|
|
|
|
|
|
|
# Ribbon按钮信号
|
|
|
|
|
if hasattr(self.ribbon, 'tabs'):
|
|
|
|
|
for tab_name, tab_btn in self.ribbon.tabs.items():
|
|
|
|
|
tab_btn.clicked.connect(lambda checked, name=tab_name: self.on_tab_changed(name))
|
|
|
|
|
# 标签栏已删除,相关代码已移除
|
|
|
|
|
|
|
|
|
|
# 字体设置信号
|
|
|
|
|
if hasattr(self.ribbon, 'font_combo'):
|
|
|
|
|
self.ribbon.font_combo.currentFontChanged.connect(self.on_font_changed)
|
|
|
|
|
self.ribbon.font_size_combo.currentTextChanged.connect(self.on_font_size_changed)
|
|
|
|
|
self.ribbon.bold_btn.clicked.connect(self.on_bold_clicked)
|
|
|
|
|
self.ribbon.italic_btn.clicked.connect(self.on_italic_clicked)
|
|
|
|
|
self.ribbon.underline_btn.clicked.connect(self.on_underline_clicked)
|
|
|
|
|
|
|
|
|
|
# 查找和替换按钮信号
|
|
|
|
|
if hasattr(self.ribbon, 'find_btn'):
|
|
|
|
|
self.ribbon.find_btn.clicked.connect(self.show_find_dialog)
|
|
|
|
|
if hasattr(self.ribbon, 'replace_btn'):
|
|
|
|
|
self.ribbon.replace_btn.clicked.connect(self.show_replace_dialog)
|
|
|
|
|
|
|
|
|
|
# 页面布局信号已在菜单中直接连接,无需在此重复连接
|
|
|
|
|
|
|
|
|
|
# 天气功能信号
|
|
|
|
|
if hasattr(self.ribbon, 'city_combo'):
|
|
|
|
|
self.ribbon.city_combo.currentTextChanged.connect(self.on_city_changed)
|
|
|
|
|
if hasattr(self.ribbon, 'refresh_weather_btn'):
|
|
|
|
|
self.ribbon.refresh_weather_btn.clicked.connect(self.refresh_weather)
|
|
|
|
|
|
|
|
|
|
def on_text_changed(self):
|
|
|
|
|
"""文本变化处理 - 逐步显示模式"""
|
|
|
|
|
@ -389,23 +512,199 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
self.is_modified = True
|
|
|
|
|
self.update_window_title()
|
|
|
|
|
|
|
|
|
|
def on_tab_changed(self, tab_name):
|
|
|
|
|
"""标签切换处理"""
|
|
|
|
|
# 更新标签状态
|
|
|
|
|
for name, btn in self.ribbon.tabs.items():
|
|
|
|
|
btn.setChecked(name == tab_name)
|
|
|
|
|
|
|
|
|
|
# 这里可以根据不同标签切换不同的功能区内容
|
|
|
|
|
print(f"切换到标签: {tab_name}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_font_changed(self, font):
|
|
|
|
|
"""字体更改处理"""
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
if cursor.hasSelection():
|
|
|
|
|
# 如果有选中文本,只更改选中文本的字体
|
|
|
|
|
fmt = cursor.charFormat()
|
|
|
|
|
fmt.setFontFamily(font.family())
|
|
|
|
|
cursor.setCharFormat(fmt)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有选中文本,更改整个文档的默认字体
|
|
|
|
|
self.text_edit.setFontFamily(font.family())
|
|
|
|
|
|
|
|
|
|
def on_font_size_changed(self, size):
|
|
|
|
|
"""字体大小更改处理"""
|
|
|
|
|
try:
|
|
|
|
|
font_size = int(size)
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
if cursor.hasSelection():
|
|
|
|
|
# 如果有选中文本,只更改选中文本的字体大小
|
|
|
|
|
fmt = cursor.charFormat()
|
|
|
|
|
fmt.setFontPointSize(font_size)
|
|
|
|
|
cursor.setCharFormat(fmt)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有选中文本,更改整个文档的默认字体大小
|
|
|
|
|
self.text_edit.setFontPointSize(font_size)
|
|
|
|
|
except ValueError:
|
|
|
|
|
pass # 忽略无效的字体大小
|
|
|
|
|
|
|
|
|
|
def on_bold_clicked(self, checked):
|
|
|
|
|
"""粗体按钮点击处理"""
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
if cursor.hasSelection():
|
|
|
|
|
# 如果有选中文本,只更改选中文本的粗体样式
|
|
|
|
|
fmt = cursor.charFormat()
|
|
|
|
|
fmt.setFontWeight(QFont.Bold if checked else QFont.Normal)
|
|
|
|
|
cursor.setCharFormat(fmt)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有选中文本,更改整个文档的默认粗体样式
|
|
|
|
|
self.text_edit.setFontWeight(QFont.Bold if checked else QFont.Normal)
|
|
|
|
|
|
|
|
|
|
def on_italic_clicked(self, checked):
|
|
|
|
|
"""斜体按钮点击处理"""
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
if cursor.hasSelection():
|
|
|
|
|
# 如果有选中文本,只更改选中文本的斜体样式
|
|
|
|
|
fmt = cursor.charFormat()
|
|
|
|
|
fmt.setFontItalic(checked)
|
|
|
|
|
cursor.setCharFormat(fmt)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有选中文本,更改整个文档的默认斜体样式
|
|
|
|
|
self.text_edit.setFontItalic(checked)
|
|
|
|
|
|
|
|
|
|
def on_underline_clicked(self, checked):
|
|
|
|
|
"""下划线按钮点击处理"""
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
if cursor.hasSelection():
|
|
|
|
|
# 如果有选中文本,只更改选中文本的下划线样式
|
|
|
|
|
fmt = cursor.charFormat()
|
|
|
|
|
fmt.setFontUnderline(checked)
|
|
|
|
|
cursor.setCharFormat(fmt)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有选中文本,更改整个文档的默认下划线样式
|
|
|
|
|
self.text_edit.setFontUnderline(checked)
|
|
|
|
|
|
|
|
|
|
def update_weather_display(self, weather_data):
|
|
|
|
|
"""更新天气显示"""
|
|
|
|
|
print(f"接收到天气数据: {weather_data}")
|
|
|
|
|
if 'error' in weather_data:
|
|
|
|
|
print(f"天气显示错误: {weather_data['error']}")
|
|
|
|
|
self.status_bar.showMessage(f"天气信息获取失败: {weather_data['error']}", 3000)
|
|
|
|
|
else:
|
|
|
|
|
city = weather_data.get('city', '未知城市')
|
|
|
|
|
temp = weather_data.get('temperature', 'N/A')
|
|
|
|
|
desc = weather_data.get('description', 'N/A')
|
|
|
|
|
self.status_bar.showMessage(f"天气: {desc}, {temp}°C", 5000)
|
|
|
|
|
humidity = weather_data.get('humidity', 'N/A')
|
|
|
|
|
wind_scale = weather_data.get('wind_scale', 'N/A')
|
|
|
|
|
|
|
|
|
|
# 在状态栏显示简要天气信息
|
|
|
|
|
weather_message = f"{city}: {desc}, {temp}°C, 湿度{humidity}%, 风力{wind_scale}级"
|
|
|
|
|
print(f"显示天气信息: {weather_message}")
|
|
|
|
|
self.status_bar.showMessage(weather_message, 5000)
|
|
|
|
|
|
|
|
|
|
# 存储天气数据供其他功能使用
|
|
|
|
|
self.current_weather_data = weather_data
|
|
|
|
|
print("天气数据已存储")
|
|
|
|
|
|
|
|
|
|
def refresh_weather(self):
|
|
|
|
|
"""手动刷新天气信息"""
|
|
|
|
|
try:
|
|
|
|
|
# 获取当前选择的城市
|
|
|
|
|
current_city = self.ribbon.city_combo.currentText()
|
|
|
|
|
print(f"刷新天气 - 当前选择的城市: {current_city}")
|
|
|
|
|
|
|
|
|
|
if current_city == '自动定位':
|
|
|
|
|
# 使用自动定位
|
|
|
|
|
weather_data = self.weather_api.get_weather_data()
|
|
|
|
|
else:
|
|
|
|
|
# 使用选中的城市
|
|
|
|
|
weather_data = self.weather_api.get_weather_data(current_city)
|
|
|
|
|
|
|
|
|
|
if weather_data:
|
|
|
|
|
# 格式化天气数据
|
|
|
|
|
formatted_data = {
|
|
|
|
|
'city': weather_data['city'],
|
|
|
|
|
'temperature': weather_data['current']['temp'],
|
|
|
|
|
'description': weather_data['current']['weather'],
|
|
|
|
|
'humidity': weather_data['current']['humidity'],
|
|
|
|
|
'wind_scale': weather_data['current']['wind_scale'],
|
|
|
|
|
'forecast': weather_data['forecast']
|
|
|
|
|
}
|
|
|
|
|
self.update_weather_display(formatted_data)
|
|
|
|
|
self.status_bar.showMessage("天气信息已刷新", 2000)
|
|
|
|
|
else:
|
|
|
|
|
self.status_bar.showMessage("天气信息刷新失败,请检查API密钥", 3000)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
self.status_bar.showMessage(f"天气刷新失败: {str(e)}", 3000)
|
|
|
|
|
|
|
|
|
|
def show_detailed_weather(self):
|
|
|
|
|
"""显示详细天气信息对话框"""
|
|
|
|
|
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTextEdit
|
|
|
|
|
|
|
|
|
|
# 检查是否有天气数据
|
|
|
|
|
if not hasattr(self, 'current_weather_data') or not self.current_weather_data:
|
|
|
|
|
QMessageBox.information(self, "天气信息", "暂无天气数据,请先刷新天气信息")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
weather_data = self.current_weather_data
|
|
|
|
|
|
|
|
|
|
# 创建对话框
|
|
|
|
|
dialog = QDialog(self)
|
|
|
|
|
dialog.setWindowTitle("详细天气信息")
|
|
|
|
|
dialog.setMinimumWidth(400)
|
|
|
|
|
|
|
|
|
|
layout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
# 城市信息
|
|
|
|
|
city_label = QLabel(f"<h2>{weather_data.get('city', '未知城市')}</h2>")
|
|
|
|
|
layout.addWidget(city_label)
|
|
|
|
|
|
|
|
|
|
# 当前天气信息
|
|
|
|
|
current_layout = QVBoxLayout()
|
|
|
|
|
current_layout.addWidget(QLabel("<b>当前天气:</b>"))
|
|
|
|
|
|
|
|
|
|
current_info = f"""
|
|
|
|
|
温度: {weather_data.get('temperature', 'N/A')}°C
|
|
|
|
|
天气状况: {weather_data.get('description', 'N/A')}
|
|
|
|
|
湿度: {weather_data.get('humidity', 'N/A')}%
|
|
|
|
|
风力: {weather_data.get('wind_scale', 'N/A')}级
|
|
|
|
|
"""
|
|
|
|
|
current_text = QTextEdit()
|
|
|
|
|
current_text.setPlainText(current_info.strip())
|
|
|
|
|
current_text.setReadOnly(True)
|
|
|
|
|
current_layout.addWidget(current_text)
|
|
|
|
|
|
|
|
|
|
layout.addLayout(current_layout)
|
|
|
|
|
|
|
|
|
|
# 天气预报信息
|
|
|
|
|
if 'forecast' in weather_data and weather_data['forecast']:
|
|
|
|
|
forecast_layout = QVBoxLayout()
|
|
|
|
|
forecast_layout.addWidget(QLabel("<b>天气预报:</b>"))
|
|
|
|
|
|
|
|
|
|
forecast_text = QTextEdit()
|
|
|
|
|
forecast_info = ""
|
|
|
|
|
for i, day in enumerate(weather_data['forecast'][:3]): # 显示最近3天的预报
|
|
|
|
|
if i < len(weather_data['forecast']):
|
|
|
|
|
day_data = weather_data['forecast'][i]
|
|
|
|
|
forecast_info += f"第{i+1}天: {day_data.get('fxDate', 'N/A')} - {day_data.get('textDay', 'N/A')}, {day_data.get('tempMin', 'N/A')}~{day_data.get('tempMax', 'N/A')}°C\n"
|
|
|
|
|
|
|
|
|
|
forecast_text.setPlainText(forecast_info.strip())
|
|
|
|
|
forecast_text.setReadOnly(True)
|
|
|
|
|
forecast_layout.addWidget(forecast_text)
|
|
|
|
|
layout.addLayout(forecast_layout)
|
|
|
|
|
|
|
|
|
|
# 按钮
|
|
|
|
|
button_layout = QHBoxLayout()
|
|
|
|
|
refresh_button = QPushButton("刷新")
|
|
|
|
|
refresh_button.clicked.connect(lambda: self.refresh_weather_and_close(dialog))
|
|
|
|
|
close_button = QPushButton("关闭")
|
|
|
|
|
close_button.clicked.connect(dialog.close)
|
|
|
|
|
|
|
|
|
|
button_layout.addWidget(refresh_button)
|
|
|
|
|
button_layout.addWidget(close_button)
|
|
|
|
|
layout.addLayout(button_layout)
|
|
|
|
|
|
|
|
|
|
dialog.setLayout(layout)
|
|
|
|
|
dialog.exec_()
|
|
|
|
|
|
|
|
|
|
def refresh_weather_and_close(self, dialog):
|
|
|
|
|
"""刷新天气并关闭对话框"""
|
|
|
|
|
self.refresh_weather()
|
|
|
|
|
dialog.close()
|
|
|
|
|
|
|
|
|
|
def update_quote_display(self, quote_data):
|
|
|
|
|
"""更新名言显示"""
|
|
|
|
|
@ -600,6 +899,319 @@ class WordStyleMainWindow(QMainWindow):
|
|
|
|
|
# 这里可以实现打印布局的逻辑
|
|
|
|
|
self.status_bar.showMessage("打印布局功能开发中...", 3000)
|
|
|
|
|
|
|
|
|
|
def set_page_color(self, color):
|
|
|
|
|
"""设置页面颜色"""
|
|
|
|
|
color_map = {
|
|
|
|
|
'white': '#ffffff',
|
|
|
|
|
'light_blue': '#e6f3ff',
|
|
|
|
|
'light_yellow': '#fffde6',
|
|
|
|
|
'light_green': '#e6ffe6'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if color in color_map:
|
|
|
|
|
bg_color = color_map[color]
|
|
|
|
|
# 更新文本编辑区域的背景色
|
|
|
|
|
current_style = self.text_edit.styleSheet()
|
|
|
|
|
# 移除旧的背景色设置
|
|
|
|
|
import re
|
|
|
|
|
current_style = re.sub(r'background-color:\s*#[a-fA-F0-9]+;', '', current_style)
|
|
|
|
|
# 添加新的背景色设置
|
|
|
|
|
new_style = current_style + f"\nbackground-color: {bg_color};"
|
|
|
|
|
self.text_edit.setStyleSheet(new_style)
|
|
|
|
|
self.status_bar.showMessage(f"页面颜色已设置为{color}", 2000)
|
|
|
|
|
|
|
|
|
|
def set_page_margins(self, margin_type):
|
|
|
|
|
"""设置页面边距"""
|
|
|
|
|
margin_map = {
|
|
|
|
|
'normal': (50, 50, 50, 50),
|
|
|
|
|
'narrow': (20, 20, 20, 20),
|
|
|
|
|
'wide': (80, 80, 80, 80)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if margin_type in margin_map:
|
|
|
|
|
margins = margin_map[margin_type]
|
|
|
|
|
# 更新文档容器的边距
|
|
|
|
|
# text_edit的父级是document_layout,父级的父级是document_container
|
|
|
|
|
container = self.text_edit.parent().parent() # 获取文档容器
|
|
|
|
|
if container and hasattr(container, 'layout'):
|
|
|
|
|
layout = container.layout()
|
|
|
|
|
if layout:
|
|
|
|
|
layout.setContentsMargins(margins[0], margins[1], margins[2], margins[3])
|
|
|
|
|
self.status_bar.showMessage(f"页面边距已设置为{margin_type}", 2000)
|
|
|
|
|
|
|
|
|
|
def zoom_in(self):
|
|
|
|
|
"""放大"""
|
|
|
|
|
self.adjust_zoom_level(10)
|
|
|
|
|
|
|
|
|
|
def zoom_out(self):
|
|
|
|
|
"""缩小"""
|
|
|
|
|
self.adjust_zoom_level(-10)
|
|
|
|
|
|
|
|
|
|
def zoom_100(self):
|
|
|
|
|
"""实际大小"""
|
|
|
|
|
self.set_zoom_level(100)
|
|
|
|
|
|
|
|
|
|
def set_zoom_level(self, level):
|
|
|
|
|
"""设置缩放级别"""
|
|
|
|
|
if 10 <= level <= 500: # 限制缩放范围在10%到500%之间
|
|
|
|
|
# 获取当前字体大小并调整
|
|
|
|
|
current_font = self.text_edit.currentFont()
|
|
|
|
|
base_size = 12 # 基准字体大小
|
|
|
|
|
new_size = base_size * (level / 100)
|
|
|
|
|
|
|
|
|
|
# 应用新的字体大小
|
|
|
|
|
current_font.setPointSizeF(new_size)
|
|
|
|
|
self.text_edit.setFont(current_font)
|
|
|
|
|
|
|
|
|
|
self.status_bar.showMessage(f"缩放级别: {level}%", 2000)
|
|
|
|
|
|
|
|
|
|
def adjust_zoom_level(self, delta):
|
|
|
|
|
"""调整缩放级别"""
|
|
|
|
|
# 获取当前字体大小
|
|
|
|
|
current_font = self.text_edit.currentFont()
|
|
|
|
|
current_size = current_font.pointSizeF()
|
|
|
|
|
base_size = 12 # 基准字体大小
|
|
|
|
|
|
|
|
|
|
# 计算当前缩放百分比
|
|
|
|
|
current_zoom = (current_size / base_size) * 100
|
|
|
|
|
new_zoom = current_zoom + delta
|
|
|
|
|
|
|
|
|
|
# 限制缩放范围
|
|
|
|
|
if 10 <= new_zoom <= 500:
|
|
|
|
|
self.set_zoom_level(int(new_zoom))
|
|
|
|
|
|
|
|
|
|
def toggle_grid_lines(self):
|
|
|
|
|
"""切换网格线显示"""
|
|
|
|
|
self.status_bar.showMessage("网格线功能开发中...", 3000)
|
|
|
|
|
|
|
|
|
|
def toggle_ruler(self):
|
|
|
|
|
"""切换标尺显示"""
|
|
|
|
|
self.status_bar.showMessage("标尺功能开发中...", 3000)
|
|
|
|
|
|
|
|
|
|
def show_find_dialog(self):
|
|
|
|
|
"""显示查找对话框"""
|
|
|
|
|
# 创建查找对话框
|
|
|
|
|
dialog = QDialog(self)
|
|
|
|
|
dialog.setWindowTitle("查找")
|
|
|
|
|
dialog.setFixedSize(400, 150)
|
|
|
|
|
|
|
|
|
|
layout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
# 查找内容输入
|
|
|
|
|
find_layout = QHBoxLayout()
|
|
|
|
|
find_label = QLabel("查找内容:")
|
|
|
|
|
self.find_edit = QLineEdit()
|
|
|
|
|
find_layout.addWidget(find_label)
|
|
|
|
|
find_layout.addWidget(self.find_edit)
|
|
|
|
|
layout.addLayout(find_layout)
|
|
|
|
|
|
|
|
|
|
# 选项
|
|
|
|
|
options_layout = QHBoxLayout()
|
|
|
|
|
self.case_sensitive_checkbox = QCheckBox("区分大小写")
|
|
|
|
|
self.whole_words_checkbox = QCheckBox("全字匹配")
|
|
|
|
|
options_layout.addWidget(self.case_sensitive_checkbox)
|
|
|
|
|
options_layout.addWidget(self.whole_words_checkbox)
|
|
|
|
|
options_layout.addStretch()
|
|
|
|
|
layout.addLayout(options_layout)
|
|
|
|
|
|
|
|
|
|
# 按钮
|
|
|
|
|
buttons_layout = QHBoxLayout()
|
|
|
|
|
find_next_btn = QPushButton("查找下一个")
|
|
|
|
|
find_next_btn.clicked.connect(lambda: self.find_text(dialog))
|
|
|
|
|
cancel_btn = QPushButton("取消")
|
|
|
|
|
cancel_btn.clicked.connect(dialog.close)
|
|
|
|
|
buttons_layout.addWidget(find_next_btn)
|
|
|
|
|
buttons_layout.addWidget(cancel_btn)
|
|
|
|
|
layout.addLayout(buttons_layout)
|
|
|
|
|
|
|
|
|
|
dialog.setLayout(layout)
|
|
|
|
|
dialog.exec_()
|
|
|
|
|
|
|
|
|
|
def find_text(self, dialog):
|
|
|
|
|
"""执行查找操作"""
|
|
|
|
|
search_text = self.find_edit.text()
|
|
|
|
|
if not search_text:
|
|
|
|
|
QMessageBox.warning(self, "查找", "请输入查找内容")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 获取当前光标位置
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
start_pos = cursor.position()
|
|
|
|
|
|
|
|
|
|
# 设置查找选项
|
|
|
|
|
flags = QTextDocument.FindFlags()
|
|
|
|
|
if self.case_sensitive_checkbox.isChecked():
|
|
|
|
|
flags |= QTextDocument.FindCaseSensitively
|
|
|
|
|
if self.whole_words_checkbox.isChecked():
|
|
|
|
|
flags |= QTextDocument.FindWholeWords
|
|
|
|
|
|
|
|
|
|
# 执行查找
|
|
|
|
|
found_cursor = self.text_edit.document().find(search_text, start_pos, flags)
|
|
|
|
|
|
|
|
|
|
if found_cursor.isNull():
|
|
|
|
|
# 如果没找到,从文档开始处重新查找
|
|
|
|
|
found_cursor = self.text_edit.document().find(search_text, 0, flags)
|
|
|
|
|
|
|
|
|
|
if not found_cursor.isNull():
|
|
|
|
|
# 选中找到的文本
|
|
|
|
|
self.text_edit.setTextCursor(found_cursor)
|
|
|
|
|
self.text_edit.ensureCursorVisible()
|
|
|
|
|
else:
|
|
|
|
|
QMessageBox.information(self, "查找", f"找不到 '{search_text}'")
|
|
|
|
|
|
|
|
|
|
def show_replace_dialog(self):
|
|
|
|
|
"""显示替换对话框"""
|
|
|
|
|
# 创建替换对话框
|
|
|
|
|
dialog = QDialog(self)
|
|
|
|
|
dialog.setWindowTitle("替换")
|
|
|
|
|
dialog.setFixedSize(400, 200)
|
|
|
|
|
|
|
|
|
|
layout = QVBoxLayout()
|
|
|
|
|
|
|
|
|
|
# 查找内容输入
|
|
|
|
|
find_layout = QHBoxLayout()
|
|
|
|
|
find_label = QLabel("查找内容:")
|
|
|
|
|
self.replace_find_edit = QLineEdit()
|
|
|
|
|
find_layout.addWidget(find_label)
|
|
|
|
|
find_layout.addWidget(self.replace_find_edit)
|
|
|
|
|
layout.addLayout(find_layout)
|
|
|
|
|
|
|
|
|
|
# 替换为输入
|
|
|
|
|
replace_layout = QHBoxLayout()
|
|
|
|
|
replace_label = QLabel("替换为:")
|
|
|
|
|
self.replace_edit = QLineEdit()
|
|
|
|
|
replace_layout.addWidget(replace_label)
|
|
|
|
|
replace_layout.addWidget(self.replace_edit)
|
|
|
|
|
layout.addLayout(replace_layout)
|
|
|
|
|
|
|
|
|
|
# 选项
|
|
|
|
|
options_layout = QHBoxLayout()
|
|
|
|
|
self.replace_case_sensitive_checkbox = QCheckBox("区分大小写")
|
|
|
|
|
self.replace_whole_words_checkbox = QCheckBox("全字匹配")
|
|
|
|
|
options_layout.addWidget(self.replace_case_sensitive_checkbox)
|
|
|
|
|
options_layout.addWidget(self.replace_whole_words_checkbox)
|
|
|
|
|
options_layout.addStretch()
|
|
|
|
|
layout.addLayout(options_layout)
|
|
|
|
|
|
|
|
|
|
# 按钮
|
|
|
|
|
buttons_layout = QHBoxLayout()
|
|
|
|
|
find_next_btn = QPushButton("查找下一个")
|
|
|
|
|
replace_btn = QPushButton("替换")
|
|
|
|
|
replace_all_btn = QPushButton("全部替换")
|
|
|
|
|
cancel_btn = QPushButton("取消")
|
|
|
|
|
|
|
|
|
|
find_next_btn.clicked.connect(lambda: self.find_text_for_replace(dialog))
|
|
|
|
|
replace_btn.clicked.connect(lambda: self.replace_text(dialog))
|
|
|
|
|
replace_all_btn.clicked.connect(lambda: self.replace_all_text(dialog))
|
|
|
|
|
cancel_btn.clicked.connect(dialog.close)
|
|
|
|
|
|
|
|
|
|
buttons_layout.addWidget(find_next_btn)
|
|
|
|
|
buttons_layout.addWidget(replace_btn)
|
|
|
|
|
buttons_layout.addWidget(replace_all_btn)
|
|
|
|
|
buttons_layout.addWidget(cancel_btn)
|
|
|
|
|
layout.addLayout(buttons_layout)
|
|
|
|
|
|
|
|
|
|
dialog.setLayout(layout)
|
|
|
|
|
dialog.exec_()
|
|
|
|
|
|
|
|
|
|
def find_text_for_replace(self, dialog):
|
|
|
|
|
"""在替换对话框中执行查找操作"""
|
|
|
|
|
search_text = self.replace_find_edit.text()
|
|
|
|
|
if not search_text:
|
|
|
|
|
QMessageBox.warning(self, "查找", "请输入查找内容")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 获取当前光标位置
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
start_pos = cursor.position()
|
|
|
|
|
|
|
|
|
|
# 设置查找选项
|
|
|
|
|
flags = QTextDocument.FindFlags()
|
|
|
|
|
if self.replace_case_sensitive_checkbox.isChecked():
|
|
|
|
|
flags |= QTextDocument.FindCaseSensitively
|
|
|
|
|
if self.replace_whole_words_checkbox.isChecked():
|
|
|
|
|
flags |= QTextDocument.FindWholeWords
|
|
|
|
|
|
|
|
|
|
# 执行查找
|
|
|
|
|
found_cursor = self.text_edit.document().find(search_text, start_pos, flags)
|
|
|
|
|
|
|
|
|
|
if found_cursor.isNull():
|
|
|
|
|
# 如果没找到,从文档开始处重新查找
|
|
|
|
|
found_cursor = self.text_edit.document().find(search_text, 0, flags)
|
|
|
|
|
|
|
|
|
|
if not found_cursor.isNull():
|
|
|
|
|
# 选中找到的文本
|
|
|
|
|
self.text_edit.setTextCursor(found_cursor)
|
|
|
|
|
self.text_edit.ensureCursorVisible()
|
|
|
|
|
else:
|
|
|
|
|
QMessageBox.information(self, "查找", f"找不到 '{search_text}'")
|
|
|
|
|
|
|
|
|
|
def replace_text(self, dialog):
|
|
|
|
|
"""替换当前选中的文本"""
|
|
|
|
|
search_text = self.replace_find_edit.text()
|
|
|
|
|
replace_text = self.replace_edit.text()
|
|
|
|
|
|
|
|
|
|
# 检查是否有选中的文本且与查找内容匹配
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
selected_text = cursor.selectedText()
|
|
|
|
|
|
|
|
|
|
# 检查是否匹配(考虑大小写敏感选项)
|
|
|
|
|
match = False
|
|
|
|
|
if self.replace_case_sensitive_checkbox.isChecked():
|
|
|
|
|
match = selected_text == search_text
|
|
|
|
|
else:
|
|
|
|
|
match = selected_text.lower() == search_text.lower()
|
|
|
|
|
|
|
|
|
|
if match:
|
|
|
|
|
# 替换选中的文本
|
|
|
|
|
cursor.insertText(replace_text)
|
|
|
|
|
# 继续查找下一个
|
|
|
|
|
self.find_text_for_replace(dialog)
|
|
|
|
|
else:
|
|
|
|
|
# 如果没有匹配的选中文本,执行查找
|
|
|
|
|
self.find_text_for_replace(dialog)
|
|
|
|
|
|
|
|
|
|
def replace_all_text(self, dialog):
|
|
|
|
|
"""替换所有匹配的文本"""
|
|
|
|
|
search_text = self.replace_find_edit.text()
|
|
|
|
|
replace_text = self.replace_edit.text()
|
|
|
|
|
|
|
|
|
|
if not search_text:
|
|
|
|
|
QMessageBox.warning(self, "替换", "请输入查找内容")
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# 设置查找选项
|
|
|
|
|
flags = QTextDocument.FindFlags()
|
|
|
|
|
if self.replace_case_sensitive_checkbox.isChecked():
|
|
|
|
|
flags |= QTextDocument.FindCaseSensitively
|
|
|
|
|
if self.replace_whole_words_checkbox.isChecked():
|
|
|
|
|
flags |= QTextDocument.FindWholeWords
|
|
|
|
|
|
|
|
|
|
# 保存当前光标位置
|
|
|
|
|
original_cursor = self.text_edit.textCursor()
|
|
|
|
|
|
|
|
|
|
# 从文档开始处查找并替换所有匹配项
|
|
|
|
|
count = 0
|
|
|
|
|
cursor = self.text_edit.textCursor()
|
|
|
|
|
cursor.movePosition(QTextCursor.Start)
|
|
|
|
|
self.text_edit.setTextCursor(cursor)
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
found_cursor = self.text_edit.document().find(search_text, cursor, flags)
|
|
|
|
|
if found_cursor.isNull():
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
# 替换文本
|
|
|
|
|
found_cursor.insertText(replace_text)
|
|
|
|
|
count += 1
|
|
|
|
|
cursor = found_cursor
|
|
|
|
|
|
|
|
|
|
# 恢复原始光标位置
|
|
|
|
|
self.text_edit.setTextCursor(original_cursor)
|
|
|
|
|
|
|
|
|
|
# 显示替换结果
|
|
|
|
|
QMessageBox.information(self, "替换", f"已完成 {count} 处替换。")
|
|
|
|
|
|
|
|
|
|
def show_about(self):
|
|
|
|
|
"""显示关于对话框"""
|
|
|
|
|
QMessageBox.about(
|
|
|
|
|
|