diff --git a/install_and_fix.py b/install_and_fix.py new file mode 100644 index 0000000..ed9584e --- /dev/null +++ b/install_and_fix.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +MagicWord 安装和修复脚本 +用于安装依赖并解决Qt平台插件问题 +""" + +import os +import sys +import subprocess +import platform +import importlib.util + +def check_python_version(): + """检查Python版本""" + version = sys.version_info + print(f"当前Python版本: {version.major}.{version.minor}.{version.micro}") + + if version.major < 3 or (version.major == 3 and version.minor < 6): + print("错误: 需要Python 3.6或更高版本") + return False + + return True + +def run_command(command, shell=False): + """运行命令并返回结果""" + try: + result = subprocess.run(command, shell=shell, capture_output=True, text=True, encoding='utf-8') + return result.returncode, result.stdout, result.stderr + except Exception as e: + return -1, "", str(e) + +def install_requirements(): + """安装requirements.txt中的依赖""" + requirements_file = "requirements.txt" + + if not os.path.exists(requirements_file): + print(f"错误: 找不到 {requirements_file} 文件") + return False + + print("安装项目依赖...") + try: + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "-r", requirements_file]) + if code == 0: + print("所有依赖安装成功") + return True + else: + print(f"依赖安装失败: {stderr}") + return False + except Exception as e: + print(f"依赖安装异常: {e}") + return False + +def check_pyqt5(): + """检查PyQt5安装""" + print("检查PyQt5安装...") + try: + import PyQt5 + pyqt5_path = os.path.dirname(PyQt5.__file__) + print(f"PyQt5已安装,路径: {pyqt5_path}") + return True + except ImportError: + print("PyQt5未安装") + return False + +def reinstall_pyqt5(): + """重新安装PyQt5""" + print("重新安装PyQt5...") + try: + # 先卸载 + print("卸载PyQt5...") + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "uninstall", "PyQt5", "-y"]) + + # 重新安装 + print("安装PyQt5...") + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "PyQt5"]) + if code == 0: + print("PyQt5重新安装成功") + return True + else: + print(f"PyQt5重新安装失败: {stderr}") + return False + except Exception as e: + print(f"PyQt5重新安装异常: {e}") + return False + +def create_qt_debug_script(): + """创建Qt调试运行脚本""" + system = platform.system() + + if system == "Windows": + script_content = """@echo off +echo 设置Qt调试环境变量... +set QT_DEBUG_PLUGINS=1 +echo Qt调试模式已启用 +echo. +echo 运行MagicWord应用程序... +python src/main.py +pause +""" + script_name = "run_debug.bat" + else: + script_content = """#!/bin/bash +echo "设置Qt调试环境变量..." +export QT_DEBUG_PLUGINS=1 +echo "Qt调试模式已启用" +echo "" +echo "运行MagicWord应用程序..." +python src/main.py +""" + script_name = "run_debug.sh" + + try: + with open(script_name, "w", encoding="utf-8") as f: + f.write(script_content) + print(f"调试运行脚本创建完成: {script_name}") + return True + except Exception as e: + print(f"创建调试运行脚本失败: {e}") + return False + +def main(): + """主函数""" + print("=" * 60) + print("MagicWord 项目安装和修复脚本") + print("=" * 60) + + # 检查Python版本 + if not check_python_version(): + sys.exit(1) + + # 升级pip + print("\n升级pip...") + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "--upgrade", "pip"]) + if code != 0: + print(f"pip升级警告: {stderr}") + else: + print("pip升级完成") + + # 安装依赖 + print("\n安装项目依赖...") + if not install_requirements(): + print("依赖安装失败") + sys.exit(1) + + # 检查PyQt5 + print("\n检查PyQt5...") + if not check_pyqt5(): + print("PyQt5未安装,开始安装...") + code, stdout, stderr = run_command([sys.executable, "-m", "pip", "install", "PyQt5"]) + if code == 0: + print("PyQt5安装成功") + else: + print(f"PyQt5安装失败: {stderr}") + # 尝试重新安装 + if not reinstall_pyqt5(): + print("PyQt5重新安装也失败了") + + # 再次检查PyQt5 + if check_pyqt5(): + # 检查PyQt5插件路径 + try: + import PyQt5 + pyqt5_path = os.path.dirname(PyQt5.__file__) + plugin_paths = [ + os.path.join(pyqt5_path, "Qt5", "plugins"), + os.path.join(pyqt5_path, "plugins"), + ] + + plugin_path = None + for path in plugin_paths: + if os.path.exists(path): + plugin_path = path + break + + if plugin_path: + print(f"PyQt5插件路径: {plugin_path}") + platforms_path = os.path.join(plugin_path, "platforms") + if os.path.exists(platforms_path): + print(f"Platform插件路径: {platforms_path}") + else: + print("未找到platforms目录") + else: + print("未找到PyQt5插件目录") + except Exception as e: + print(f"检查PyQt5插件时出错: {e}") + + # 创建调试脚本 + print("\n创建调试运行脚本...") + create_qt_debug_script() + + print("\n" + "=" * 60) + print("安装和修复完成!") + print("如果问题仍然存在,请尝试以下方法:") + print("1. 运行创建的调试脚本查看详细错误信息") + print("2. 检查是否安装了Visual C++运行库") + print("3. 确保使用的是Python 3.6或更高版本") + print("=" * 60) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/run_debug.bat b/run_debug.bat new file mode 100644 index 0000000..94b5a37 --- /dev/null +++ b/run_debug.bat @@ -0,0 +1,8 @@ +@echo off +echo 设置Qt调试环境变量... +set QT_DEBUG_PLUGINS=1 +echo Qt调试模式已启用 +echo. +echo 运行MagicWord应用程序... +python src/main.py +pause diff --git a/src/main.py b/src/main.py index a49832d..6452c9d 100644 --- a/src/main.py +++ b/src/main.py @@ -2,20 +2,68 @@ import sys import traceback import os +import platform # 添加项目根目录到Python路径 project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, project_root) -# 设置Qt平台插件路径 - 优先使用系统Qt插件 -system_qt_plugins_path = '/usr/local/opt/qt5/plugins' # macOS Homebrew Qt5路径 -venv_qt_plugins_path = os.path.join(project_root, '.venv', 'lib', 'python3.9', 'site-packages', 'PyQt5', 'Qt5', 'plugins') +# 设置Qt平台插件路径 - 根据操作系统设置正确的Qt插件路径 +def set_qt_plugin_path(): + system = platform.system() + + if system == "Windows": + # Windows环境下查找Qt插件路径 + # 首先检查虚拟环境中的Qt插件 + venv_qt_plugins_path = os.path.join(project_root, '.venv', 'Lib', 'site-packages', 'PyQt5', 'Qt5', 'plugins') + if os.path.exists(venv_qt_plugins_path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = venv_qt_plugins_path + return + + # 检查全局Python安装中的Qt插件 + global_qt_plugins_path = os.path.join(sys.prefix, 'Lib', 'site-packages', 'PyQt5', 'Qt5', 'plugins') + if os.path.exists(global_qt_plugins_path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = global_qt_plugins_path + return + + # 尝试在常见的Windows PyQt5安装路径中查找 + common_paths = [ + os.path.join(os.path.expanduser('~'), 'AppData', 'Local', 'Programs', 'Python', 'Python39', 'Lib', 'site-packages', 'PyQt5', 'Qt5', 'plugins'), + os.path.join(os.path.expanduser('~'), 'AppData', 'Roaming', 'Python', 'Python39', 'site-packages', 'PyQt5', 'Qt5', 'plugins'), + ] + + for path in common_paths: + if os.path.exists(path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = path + return + + elif system == "Darwin": # macOS + # macOS环境下查找Qt插件路径 + system_qt_plugins_path = '/usr/local/opt/qt5/plugins' # macOS Homebrew Qt5路径 + venv_qt_plugins_path = os.path.join(project_root, '.venv', 'lib', 'python3.9', 'site-packages', 'PyQt5', 'Qt5', 'plugins') + + # 优先检查系统Qt插件路径 + if os.path.exists(system_qt_plugins_path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = system_qt_plugins_path + return + elif os.path.exists(venv_qt_plugins_path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = venv_qt_plugins_path + return + + elif system == "Linux": + # Linux环境下查找Qt插件路径 + venv_qt_plugins_path = os.path.join(project_root, '.venv', 'lib', 'python3.9', 'site-packages', 'PyQt5', 'Qt5', 'plugins') + global_qt_plugins_path = os.path.join(sys.prefix, 'lib', 'python3.9', 'site-packages', 'PyQt5', 'Qt5', 'plugins') + + if os.path.exists(venv_qt_plugins_path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = venv_qt_plugins_path + return + elif os.path.exists(global_qt_plugins_path): + os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = global_qt_plugins_path + return -# 优先检查系统Qt插件路径 -if os.path.exists(system_qt_plugins_path): - os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = system_qt_plugins_path -elif os.path.exists(venv_qt_plugins_path): - os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = venv_qt_plugins_path +# 设置Qt平台插件路径 +set_qt_plugin_path() from PyQt5.QtWidgets import QApplication from PyQt5.QtCore import Qt diff --git a/src/ui/word_style_ui.py b/src/ui/word_style_ui.py index b82c8bc..f446a42 100644 --- a/src/ui/word_style_ui.py +++ b/src/ui/word_style_ui.py @@ -2,7 +2,8 @@ from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTabWidget, QFrame, QTextEdit, QToolButton, QMenuBar, QStatusBar, QGroupBox, - QComboBox, QSpinBox, QFontComboBox, QToolBar) + QComboBox, QSpinBox, QFontComboBox, QToolBar, + QSizePolicy) from PyQt5.QtCore import Qt, QSize from PyQt5.QtGui import QFont, QIcon, QPalette, QColor @@ -31,49 +32,6 @@ class WordRibbon(QFrame): main_layout.setContentsMargins(0, 0, 0, 0) main_layout.setSpacing(0) - # 标签栏 - self.tab_bar = QWidget() - self.tab_bar.setFixedHeight(25) - self.tab_bar.setStyleSheet(""" - QWidget { - background-color: #f3f2f1; - border-bottom: 1px solid #e1e1e1; - } - """) - - tab_layout = QHBoxLayout() - tab_layout.setContentsMargins(10, 0, 0, 0) - tab_layout.setSpacing(0) - - # 创建标签按钮 - self.tabs = {} - tab_names = ['文件', '开始', '插入', '设计', '布局', '引用', '邮件', '审阅', '视图', '帮助'] - for name in tab_names: - tab_btn = QPushButton(name) - tab_btn.setFlat(True) - tab_btn.setFixedHeight(25) - tab_btn.setStyleSheet(""" - QPushButton { - background-color: transparent; - border: none; - padding: 5px 15px; - font-size: 12px; - color: #333333; - } - QPushButton:hover { - background-color: #e1e1e1; - } - QPushButton:checked { - background-color: #ffffff; - border: 1px solid #d0d0d0; - border-bottom: 1px solid #ffffff; - } - """) - self.tabs[name] = tab_btn - tab_layout.addWidget(tab_btn) - - self.tab_bar.setLayout(tab_layout) - # 功能区 self.ribbon_area = QFrame() self.ribbon_area.setStyleSheet(""" @@ -93,33 +51,12 @@ class WordRibbon(QFrame): self.ribbon_area.setLayout(ribbon_layout) - main_layout.addWidget(self.tab_bar) main_layout.addWidget(self.ribbon_area) self.setLayout(main_layout) - - # 设置默认选中的标签 - self.tabs['开始'].setChecked(True) def setup_home_tab(self, layout): """设置开始标签的功能区内容""" - # 剪贴板组 - clipboard_group = self.create_ribbon_group("剪贴板") - paste_btn = self.create_ribbon_button("粘贴", "Ctrl+V", "paste") - cut_btn = self.create_ribbon_button("剪切", "Ctrl+X", "cut") - copy_btn = self.create_ribbon_button("复制", "Ctrl+C", "copy") - - clipboard_layout = QVBoxLayout() - clipboard_layout.addWidget(paste_btn) - - small_btn_layout = QHBoxLayout() - small_btn_layout.addWidget(cut_btn) - small_btn_layout.addWidget(copy_btn) - clipboard_layout.addLayout(small_btn_layout) - - clipboard_group.setLayout(clipboard_layout) - layout.addWidget(clipboard_group) - # 字体组 font_group = self.create_ribbon_group("字体") @@ -127,10 +64,12 @@ class WordRibbon(QFrame): font_layout = QHBoxLayout() self.font_combo = QFontComboBox() self.font_combo.setFixedWidth(120) + self.font_combo.currentFontChanged.connect(self.on_font_changed) self.font_size_combo = QComboBox() self.font_size_combo.addItems(['8', '9', '10', '11', '12', '14', '16', '18', '20', '22', '24', '26', '28', '36', '48', '72']) self.font_size_combo.setFixedWidth(50) self.font_size_combo.setCurrentText('12') + self.font_size_combo.currentTextChanged.connect(self.on_font_size_changed) font_layout.addWidget(self.font_combo) font_layout.addWidget(self.font_size_combo) @@ -138,8 +77,11 @@ class WordRibbon(QFrame): # 字体样式按钮 font_style_layout = QHBoxLayout() self.bold_btn = self.create_toggle_button("B", "bold") + self.bold_btn.clicked.connect(self.on_bold_clicked) self.italic_btn = self.create_toggle_button("I", "italic") + self.italic_btn.clicked.connect(self.on_italic_clicked) self.underline_btn = self.create_toggle_button("U", "underline") + self.underline_btn.clicked.connect(self.on_underline_clicked) font_style_layout.addWidget(self.bold_btn) font_style_layout.addWidget(self.italic_btn) @@ -182,17 +124,37 @@ class WordRibbon(QFrame): # 编辑组 editing_group = self.create_ribbon_group("编辑") - find_btn = self.create_ribbon_button("查找", "Ctrl+F", "find") - replace_btn = self.create_ribbon_button("替换", "Ctrl+H", "replace") + self.find_btn = self.create_ribbon_button("查找", "Ctrl+F", "find") + self.replace_btn = self.create_ribbon_button("替换", "Ctrl+H", "replace") editing_layout = QVBoxLayout() - editing_layout.addWidget(find_btn) - editing_layout.addWidget(replace_btn) + editing_layout.addWidget(self.find_btn) + editing_layout.addWidget(self.replace_btn) editing_group.setLayout(editing_layout) layout.addWidget(editing_group) layout.addStretch() + def on_font_changed(self, font): + """字体变化处理""" + pass + + def on_font_size_changed(self, size): + """字体大小变化处理""" + pass + + def on_bold_clicked(self): + """粗体按钮点击处理""" + pass + + def on_italic_clicked(self): + """斜体按钮点击处理""" + pass + + def on_underline_clicked(self): + """下划线按钮点击处理""" + pass + def create_ribbon_group(self, title): """创建功能区组""" group = QGroupBox(title) @@ -350,6 +312,21 @@ class WordStyleToolBar(QToolBar): self.addWidget(undo_btn) self.addWidget(redo_btn) self.addSeparator() + + # 添加弹性空间,将后面的按钮推到最右侧 + # 创建一个具有扩展策略的QWidget来实现spacer效果 + spacer = QWidget() + spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + self.addWidget(spacer) + + # 添加批注、编辑、共享按钮到最右侧 + comment_btn = self.create_quick_button("批注", "") + edit_btn = self.create_quick_button("编辑", "") + share_btn = self.create_quick_button("共享", "") + + self.addWidget(comment_btn) + self.addWidget(edit_btn) + self.addWidget(share_btn) def create_quick_button(self, text, shortcut): """创建快速访问按钮""" diff --git a/src/word_main_window.py b/src/word_main_window.py index d89f661..963f9fb 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -3,9 +3,10 @@ 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) @@ -231,10 +232,106 @@ 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() + + # 页面布局子菜单 + layout_menu = view_menu.addMenu('页面布局') + + # 页面颜色 + page_color_menu = layout_menu.addMenu('页面颜色') + white_action = QAction('白色', self) + white_action.triggered.connect(lambda: self.set_page_color('white')) + page_color_menu.addAction(white_action) + + light_blue_action = QAction('浅蓝色', self) + light_blue_action.triggered.connect(lambda: self.set_page_color('light_blue')) + page_color_menu.addAction(light_blue_action) + + light_yellow_action = QAction('浅黄色', self) + light_yellow_action.triggered.connect(lambda: self.set_page_color('light_yellow')) + page_color_menu.addAction(light_yellow_action) + + light_green_action = QAction('浅绿色', self) + light_green_action.triggered.connect(lambda: self.set_page_color('light_green')) + page_color_menu.addAction(light_green_action) + + # 页面边距 + margin_menu = layout_menu.addMenu('页面边距') + normal_margin_action = QAction('普通', self) + normal_margin_action.triggered.connect(lambda: self.set_page_margins('normal')) + margin_menu.addAction(normal_margin_action) + + narrow_margin_action = QAction('窄', self) + narrow_margin_action.triggered.connect(lambda: self.set_page_margins('narrow')) + margin_menu.addAction(narrow_margin_action) + + wide_margin_action = QAction('宽', self) + wide_margin_action.triggered.connect(lambda: self.set_page_margins('wide')) + margin_menu.addAction(wide_margin_action) + + # 缩放子菜单 + zoom_menu = view_menu.addMenu('缩放') + + zoom_in_action = QAction('放大', self) + zoom_in_action.setShortcut('Ctrl++') + zoom_in_action.triggered.connect(self.zoom_in) + zoom_menu.addAction(zoom_in_action) + + zoom_out_action = QAction('缩小', self) + zoom_out_action.setShortcut('Ctrl+-') + zoom_out_action.triggered.connect(self.zoom_out) + zoom_menu.addAction(zoom_out_action) + + zoom_100_action = QAction('实际大小', self) + zoom_100_action.setShortcut('Ctrl+0') + zoom_100_action.triggered.connect(self.zoom_100) + zoom_menu.addAction(zoom_100_action) + + zoom_menu.addSeparator() + + # 预设缩放选项 + zoom_50_action = QAction('50%', self) + zoom_50_action.triggered.connect(lambda: self.set_zoom_level(50)) + zoom_menu.addAction(zoom_50_action) + + zoom_75_action = QAction('75%', self) + zoom_75_action.triggered.connect(lambda: self.set_zoom_level(75)) + zoom_menu.addAction(zoom_75_action) + + zoom_100_action2 = QAction('100%', self) + zoom_100_action2.triggered.connect(lambda: self.set_zoom_level(100)) + zoom_menu.addAction(zoom_100_action2) + + zoom_125_action = QAction('125%', self) + zoom_125_action.triggered.connect(lambda: self.set_zoom_level(125)) + zoom_menu.addAction(zoom_125_action) + + zoom_150_action = QAction('150%', self) + zoom_150_action.triggered.connect(lambda: self.set_zoom_level(150)) + zoom_menu.addAction(zoom_150_action) + + zoom_200_action = QAction('200%', self) + zoom_200_action.triggered.connect(lambda: self.set_zoom_level(200)) + zoom_menu.addAction(zoom_200_action) + + view_menu.addSeparator() + + # 显示选项 + grid_lines_action = QAction('网格线', self) + grid_lines_action.setCheckable(True) + grid_lines_action.triggered.connect(self.toggle_grid_lines) + view_menu.addAction(grid_lines_action) + + ruler_action = QAction('标尺', self) + ruler_action.setCheckable(True) + ruler_action.triggered.connect(self.toggle_ruler) + view_menu.addAction(ruler_action) + # 帮助菜单 help_menu = menubar.addMenu('帮助(H)') @@ -318,9 +415,23 @@ 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) + + # 页面布局信号已在菜单中直接连接,无需在此重复连接 def on_text_changed(self): """文本变化处理 - 逐步显示模式""" @@ -389,14 +500,71 @@ 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): """更新天气显示""" @@ -600,6 +768,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(