From 7a85f3654485936202af6551ad31d7fb75da170e Mon Sep 17 00:00:00 2001 From: Maziang <929110464@qq.com> Date: Thu, 20 Nov 2025 20:14:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=A9=E6=B0=94=E6=82=AC=E6=B5=AE=E7=AA=97?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/weather_floating_widget.py | 609 ++++++++++++++++++++++++++++++ src/ui/word_style_ui.py | 11 + src/word_main_window.py | 50 +++ 3 files changed, 670 insertions(+) create mode 100644 src/ui/weather_floating_widget.py diff --git a/src/ui/weather_floating_widget.py b/src/ui/weather_floating_widget.py new file mode 100644 index 0000000..d520962 --- /dev/null +++ b/src/ui/weather_floating_widget.py @@ -0,0 +1,609 @@ +# -*- coding: utf-8 -*- + +""" +天气悬浮窗口模块 +提供一个可拖拽的天气悬浮窗口,显示当前天气信息 +""" + +import sys +from PyQt5.QtWidgets import ( + QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, + QFrame, QTextEdit, QDialog, QComboBox +) +from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QPoint, QThread +from PyQt5.QtGui import QFont, QPalette, QColor + +# 导入主题管理器 +from .theme_manager import theme_manager + + +class WeatherFloatingWidget(QDialog): + """天气悬浮窗口类""" + + # 自定义信号 + closed = pyqtSignal() + refresh_requested = pyqtSignal() + + def __init__(self, parent=None): + super().__init__(parent) + self.drag_position = None + self.is_dragging = False + self.weather_data = None + self.setup_ui() + self.setup_connections() + self.setup_theme() + self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.Tool) + self.setAttribute(Qt.WA_TranslucentBackground) + + def setup_ui(self): + """设置UI界面""" + # 设置窗口属性 + self.setWindowTitle("天气") + self.setFixedSize(400, 320) # 增加窗口尺寸 + + # 创建主框架,用于实现圆角和阴影效果 + self.main_frame = QFrame() + self.main_frame.setObjectName("mainFrame") + + # 主布局 + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.addWidget(self.main_frame) + + # 内容布局 + content_layout = QVBoxLayout(self.main_frame) + content_layout.setContentsMargins(15, 15, 15, 15) # 减小内边距 + content_layout.setSpacing(10) # 减小间距 + + # 设置最小尺寸策略 + self.main_frame.setMinimumSize(380, 300) + + # 标题栏 + title_layout = QHBoxLayout() + + self.title_label = QLabel("天气信息") + self.title_label.setFont(QFont("Arial", 12, QFont.Bold)) + title_layout.addWidget(self.title_label) + title_layout.addStretch() + + # 关闭按钮 + self.close_btn = QPushButton("×") + self.close_btn.setFixedSize(20, 20) + self.close_btn.setObjectName("closeButton") + title_layout.addWidget(self.close_btn) + + content_layout.addLayout(title_layout) + + # 分隔线 + separator = QFrame() + separator.setFrameShape(QFrame.HLine) + separator.setObjectName("separator") + content_layout.addWidget(separator) + + # 天气图标和温度显示区域 + weather_display_layout = QHBoxLayout() + weather_display_layout.setSpacing(8) # 适当间距 + weather_display_layout.setContentsMargins(2, 2, 2, 2) # 减小内边距 + + self.weather_icon_label = QLabel("🌞") + self.weather_icon_label.setFont(QFont("Arial", 28)) + self.weather_icon_label.setAlignment(Qt.AlignCenter) + self.weather_icon_label.setFixedSize(60, 60) + weather_display_layout.addWidget(self.weather_icon_label) + + # 温度和城市信息 + temp_city_layout = QVBoxLayout() + temp_city_layout.setSpacing(8) # 增加间距 + temp_city_layout.setContentsMargins(0, 0, 0, 0) + + self.temperature_label = QLabel("25°C") + self.temperature_label.setFont(QFont("Arial", 20, QFont.Bold)) + self.temperature_label.setObjectName("temperatureLabel") + temp_city_layout.addWidget(self.temperature_label) + + self.city_label = QLabel("北京") + self.city_label.setFont(QFont("Arial", 12)) + self.city_label.setObjectName("cityLabel") + temp_city_layout.addWidget(self.city_label) + + weather_display_layout.addLayout(temp_city_layout) + weather_display_layout.addStretch() + + content_layout.addLayout(weather_display_layout) + + # 天气描述 + self.weather_desc_label = QLabel("晴天") + self.weather_desc_label.setFont(QFont("Arial", 12)) + self.weather_desc_label.setObjectName("weatherDescLabel") + self.weather_desc_label.setAlignment(Qt.AlignCenter) + content_layout.addWidget(self.weather_desc_label) + + # 详细信息(湿度、风速) + details_layout = QHBoxLayout() + details_layout.setSpacing(10) # 适当间距 + details_layout.setContentsMargins(2, 2, 2, 2) # 减小内边距 + + self.humidity_label = QLabel("湿度: 45%") + self.humidity_label.setFont(QFont("Arial", 11)) + self.humidity_label.setObjectName("detailLabel") + details_layout.addWidget(self.humidity_label) + + self.wind_label = QLabel("风速: 2级") + self.wind_label.setFont(QFont("Arial", 11)) + self.wind_label.setObjectName("detailLabel") + details_layout.addWidget(self.wind_label) + + content_layout.addLayout(details_layout) + + # 城市选择区域 + city_layout = QHBoxLayout() + city_layout.setSpacing(10) + city_layout.setContentsMargins(0, 0, 0, 0) + + self.city_combo = QComboBox() + self.city_combo.setObjectName("cityCombo") + # 添加所有省会城市,与主窗口保持一致 + self.city_combo.addItems([ + '自动定位', + '北京', '上海', '广州', '深圳', '杭州', '南京', '武汉', '成都', '西安', # 一线城市 + '天津', '重庆', '苏州', '青岛', '大连', '宁波', '厦门', '无锡', '佛山', # 新一线城市 + '石家庄', '太原', '呼和浩特', '沈阳', '长春', '哈尔滨', # 东北华北 + '合肥', '福州', '南昌', '济南', '郑州', '长沙', '南宁', '海口', # 华东华中华南 + '贵阳', '昆明', '拉萨', '兰州', '西宁', '银川', '乌鲁木齐' # 西南西北 + ]) + self.city_combo.setFixedWidth(120) # 增加城市选择框宽度,与主窗口保持一致 + city_layout.addWidget(self.city_combo) + + city_layout.addStretch() + + content_layout.addLayout(city_layout) + + # 按钮区域 + button_layout = QHBoxLayout() + button_layout.setSpacing(10) + button_layout.setContentsMargins(0, 0, 0, 0) + + self.refresh_btn = QPushButton("刷新") + self.refresh_btn.setObjectName("refreshButton") + button_layout.addWidget(self.refresh_btn) + + button_layout.addStretch() + + self.detail_btn = QPushButton("详情") + self.detail_btn.setObjectName("detailButton") + button_layout.addWidget(self.detail_btn) + + content_layout.addLayout(button_layout) + + # 添加弹性空间 + content_layout.addStretch() + + def setup_connections(self): + """设置信号连接""" + self.close_btn.clicked.connect(self.close_window) + self.refresh_btn.clicked.connect(self.on_refresh_clicked) + self.detail_btn.clicked.connect(self.show_detailed_weather) + self.city_combo.currentTextChanged.connect(self.on_city_changed) + + def setup_theme(self): + """设置主题""" + # 连接主题切换信号 + theme_manager.theme_changed.connect(self.on_theme_changed) + + # 应用当前主题 + self.apply_theme() + + def apply_theme(self): + """应用主题样式""" + is_dark = theme_manager.is_dark_theme() + colors = theme_manager.get_current_theme_colors() + + if is_dark: + # 深色主题样式 + self.main_frame.setStyleSheet(f""" + QFrame#mainFrame {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 8px; + }} + QLabel {{ + color: {colors['text']}; + background-color: transparent; + padding: 4px 6px; + margin: 2px; + }} + QLabel#temperatureLabel {{ + color: {colors['accent']}; + font-size: 20px; + font-weight: bold; + padding: 6px 8px; + margin: 3px; + }} + QLabel#cityLabel {{ + color: {colors['text_secondary']}; + font-size: 12px; + padding: 3px 5px; + margin: 2px; + }} + QLabel#weatherDescLabel {{ + color: {colors['text']}; + font-size: 12px; + font-weight: 500; + padding: 4px 6px; + margin: 2px; + }} + QLabel#detailLabel {{ + color: {colors['text_secondary']}; + font-size: 11px; + padding: 3px 5px; + margin: 2px; + }} + QFrame#separator {{ + background-color: {colors['border']}; + }} + QPushButton#closeButton {{ + background-color: transparent; + border: none; + color: {colors['text']}; + font-weight: bold; + }} + QPushButton#closeButton:hover {{ + background-color: #e81123; + color: white; + border-radius: 3px; + }} + QPushButton#refreshButton, QPushButton#detailButton {{ + background-color: {colors['accent']}; + color: white; + border: none; + border-radius: 6px; + padding: 6px 16px; + font-size: 11px; + font-weight: 500; + }} + QPushButton#refreshButton:hover, QPushButton#detailButton:hover {{ + background-color: {colors['accent_hover']}; + }} + QComboBox#cityCombo {{ + background-color: {colors['surface']}; + color: {colors['text']}; + border: 1px solid {colors['border']}; + border-radius: 6px; + padding: 4px 8px; + font-size: 11px; + font-weight: 500; + min-height: 24px; + }} + QComboBox#cityCombo:hover {{ + border-color: {colors['accent']}; + }} + QComboBox#cityCombo::drop-down {{ + border: none; + width: 15px; + }} + QComboBox#cityCombo::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + else: + # 浅色主题样式 + self.main_frame.setStyleSheet(f""" + QFrame#mainFrame {{ + background-color: {colors['surface']}; + border: 1px solid {colors['border']}; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + }} + QLabel {{ + color: {colors['text']}; + background-color: transparent; + padding: 4px 6px; + margin: 2px; + }} + QLabel#temperatureLabel {{ + color: {colors['accent']}; + font-size: 20px; + font-weight: bold; + padding: 6px 8px; + margin: 3px; + }} + QLabel#cityLabel {{ + color: {colors['text_secondary']}; + font-size: 12px; + padding: 3px 5px; + margin: 2px; + }} + QLabel#weatherDescLabel {{ + color: {colors['text']}; + font-size: 12px; + font-weight: 500; + padding: 4px 6px; + margin: 2px; + }} + QLabel#detailLabel {{ + color: {colors['text_secondary']}; + font-size: 11px; + padding: 3px 5px; + margin: 2px; + }} + QFrame#separator {{ + background-color: {colors['border']}; + }} + QPushButton#closeButton {{ + background-color: transparent; + border: none; + color: {colors['text']}; + font-weight: bold; + }} + QPushButton#closeButton:hover {{ + background-color: #e81123; + color: white; + border-radius: 3px; + }} + QPushButton#refreshButton, QPushButton#detailButton {{ + background-color: {colors['accent']}; + color: white; + border: none; + border-radius: 6px; + padding: 6px 16px; + font-size: 11px; + font-weight: 500; + }} + QPushButton#refreshButton:hover, QPushButton#detailButton:hover {{ + background-color: {colors['accent_hover']}; + }} + QComboBox#cityCombo {{ + background-color: {colors['surface']}; + color: {colors['text']}; + border: 1px solid {colors['border']}; + border-radius: 6px; + padding: 4px 8px; + font-size: 11px; + font-weight: 500; + min-height: 24px; + }} + QComboBox#cityCombo:hover {{ + border-color: {colors['accent']}; + }} + QComboBox#cityCombo::drop-down {{ + border: none; + width: 15px; + }} + QComboBox#cityCombo::down-arrow {{ + image: none; + border-left: 3px solid transparent; + border-right: 3px solid transparent; + border-top: 5px solid {colors['text']}; + }} + """) + + def on_theme_changed(self, is_dark): + """主题切换槽函数""" + self.apply_theme() + + def mousePressEvent(self, event): + """鼠标按下事件,用于拖拽""" + if event.button() == Qt.LeftButton: + # 检查是否点击在标题栏区域 + if event.pos().y() <= 40: # 假设标题栏高度为40像素 + self.is_dragging = True + self.drag_position = event.globalPos() - self.frameGeometry().topLeft() + event.accept() + + def mouseMoveEvent(self, event): + """鼠标移动事件,用于拖拽""" + if self.is_dragging and event.buttons() == Qt.LeftButton: + self.move(event.globalPos() - self.drag_position) + event.accept() + + def mouseReleaseEvent(self, event): + """鼠标释放事件""" + self.is_dragging = False + + def update_weather(self, weather_data): + """更新天气信息""" + self.weather_data = weather_data + + if weather_data and 'error' not in weather_data: + # 获取天气数据 + city = weather_data.get('city', '未知城市') + current_data = weather_data.get('current', {}) + temp = current_data.get('temp', 'N/A') + desc = current_data.get('weather', 'N/A') + humidity = current_data.get('humidity', 'N/A') + wind_scale = current_data.get('wind_scale', 'N/A') + + # 更新显示 + self.city_label.setText(city) + self.temperature_label.setText(f"{temp}°C") + self.weather_desc_label.setText(desc) + self.humidity_label.setText(f"湿度: {humidity}%") + self.wind_label.setText(f"风速: {wind_scale}级") + + # 更新天气图标 + emoji = self.get_weather_emoji(desc) + self.weather_icon_label.setText(emoji) + else: + # 显示错误信息 + self.city_label.setText("获取失败") + self.temperature_label.setText("--°C") + self.weather_desc_label.setText("无法获取天气数据") + self.humidity_label.setText("湿度: --%") + self.wind_label.setText("风速: --级") + self.weather_icon_label.setText("❓") + + def get_weather_emoji(self, weather_desc): + """根据天气描述返回对应的emoji""" + if not weather_desc: + return "🌞" + + weather_desc_lower = weather_desc.lower() + + # 天气图标映射 + weather_emoji_map = { + '晴': '🌞', + '多云': '⛅', + '阴': '☁️', + '雨': '🌧️', + '小雨': '🌦️', + '中雨': '🌧️', + '大雨': '⛈️', + '暴雨': '🌩️', + '雪': '❄️', + '小雪': '🌨️', + '中雪': '❄️', + '大雪': '☃️', + '雾': '🌫️', + '霾': '😷', + '风': '💨', + '大风': '🌪️', + '雷': '⛈️', + '雷阵雨': '⛈️', + '冰雹': '🌨️', + '沙尘': '🌪️' + } + + for key, emoji in weather_emoji_map.items(): + if key in weather_desc_lower: + return emoji + + # 默认返回晴天图标 + return '🌞' + + def on_refresh_clicked(self): + """刷新按钮点击事件""" + self.refresh_requested.emit() + + def on_city_changed(self, city_name): + """城市选择变化事件""" + # 发射城市变化信号,通知主窗口更新天气 + if hasattr(self.parent(), 'on_city_changed'): + self.parent().on_city_changed(city_name) + + def set_current_city(self, city_name): + """设置当前城市""" + # 阻止信号发射,避免循环调用 + self.city_combo.blockSignals(True) + index = self.city_combo.findText(city_name) + if index >= 0: + self.city_combo.setCurrentIndex(index) + self.city_combo.blockSignals(False) + + def close_window(self): + """关闭窗口 - 只是隐藏而不是销毁""" + try: + self.closed.emit() + self.hide() # 隐藏窗口而不是销毁 + except Exception as e: + print(f"Error in close_window: {e}") + + def show_detailed_weather(self): + """显示详细天气信息对话框""" + # 检查是否有天气数据 + if not self.weather_data or 'error' in self.weather_data: + from PyQt5.QtWidgets import QMessageBox + QMessageBox.information(self, "天气信息", "暂无天气数据,请先刷新天气信息") + return + + from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTextEdit + + weather_data = self.weather_data + + # 创建对话框 + dialog = QDialog(self) + dialog.setWindowTitle("详细天气") + dialog.setMinimumWidth(400) + + layout = QVBoxLayout() + + # 城市信息 + city_label = QLabel(f"

{weather_data.get('city', '未知城市')}

") + layout.addWidget(city_label) + + # 当前天气信息 + current_layout = QVBoxLayout() + current_layout.addWidget(QLabel("当前天气:")) + + # 获取温度信息,支持嵌套结构 + current_data = weather_data.get('current', {}) + temp = current_data.get('temp', 'N/A') + if temp != 'N/A' and isinstance(temp, str): + temp = float(temp) if temp.replace('.', '').isdigit() else temp + + # 从预报数据中获取最高和最低气温 + temp_range = "" + temp_max = 'N/A' + temp_min = 'N/A' + if 'forecast' in weather_data and weather_data['forecast']: + forecast_data = weather_data['forecast'][0] # 今天的预报 + if isinstance(forecast_data, dict): + temp_max = forecast_data.get('temp_max', 'N/A') + temp_min = forecast_data.get('temp_min', 'N/A') + if temp_max != 'N/A' and temp_min != 'N/A': + temp_range = f" ({temp_min}°C~{temp_max}°C)" + + current_info = f""" +当前温度: {temp}°C{temp_range} +最高气温: {temp_max}°C +最低气温: {temp_min}°C +天气状况: {current_data.get('weather', 'N/A')} + """ + current_text = QTextEdit() + current_text.setPlainText(current_info.strip()) + current_text.setReadOnly(True) + current_layout.addWidget(current_text) + + layout.addLayout(current_layout) + + # 生活提示信息(替换原来的天气预报) + life_tips = weather_data.get('life_tips', []) + if life_tips: + tips_layout = QVBoxLayout() + tips_layout.addWidget(QLabel("生活提示:")) + + tips_text = QTextEdit() + tips_info = "" + for tip in life_tips: + tips_info += f"• {tip}\n" + + tips_text.setPlainText(tips_info.strip()) + tips_text.setReadOnly(True) + tips_layout.addWidget(tips_text) + layout.addLayout(tips_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.on_refresh_clicked() + dialog.close() + + def closeEvent(self, event): + """窗口关闭事件 - 只是隐藏而不是销毁""" + self.closed.emit() + self.hide() # 隐藏窗口而不是销毁 + event.ignore() + + def show_at_position(self, x, y): + """在指定位置显示窗口""" + self.move(x, y) + self.show() + + def update_position(self, x, y): + """更新窗口位置""" + self.move(x, y) \ No newline at end of file diff --git a/src/ui/word_style_ui.py b/src/ui/word_style_ui.py index 562b183..102b28c 100644 --- a/src/ui/word_style_ui.py +++ b/src/ui/word_style_ui.py @@ -698,8 +698,15 @@ class WordRibbon(QFrame): self.refresh_weather_btn.setStyleSheet("QPushButton { font-size: 11px; padding: 5px; }") self.refresh_weather_btn.setToolTip("刷新天气") + # 悬浮窗口按钮 + self.floating_weather_btn = QPushButton("🪟 悬浮") + self.floating_weather_btn.setFixedSize(60, 30) + self.floating_weather_btn.setStyleSheet("QPushButton { font-size: 11px; padding: 5px; }") + self.floating_weather_btn.setToolTip("切换天气悬浮窗口") + control_layout.addWidget(self.city_combo) control_layout.addWidget(self.refresh_weather_btn) + control_layout.addWidget(self.floating_weather_btn) # 添加右侧弹性空间,确保内容居中 control_layout.addStretch() @@ -852,6 +859,10 @@ class WordRibbon(QFrame): """刷新天气按钮点击处理""" pass + def on_floating_weather(self): + """悬浮窗口按钮点击处理""" + pass + def on_city_changed(self, city): """城市选择变化处理""" pass diff --git a/src/word_main_window.py b/src/word_main_window.py index 9a76eb6..eb7afbb 100644 --- a/src/word_main_window.py +++ b/src/word_main_window.py @@ -19,6 +19,7 @@ from ui.word_style_ui import WeatherAPI from file_parser import FileParser from input_handler.input_processor import InputProcessor from ui.calendar_widget import CalendarWidget +from ui.weather_floating_widget import WeatherFloatingWidget # 导入主题管理器 from ui.theme_manager import theme_manager @@ -108,6 +109,12 @@ class WordStyleMainWindow(QMainWindow): self.calendar_widget = CalendarWidget(self) self.calendar_widget.hide() # 默认隐藏 + # 初始化天气悬浮窗口 + self.weather_floating_widget = WeatherFloatingWidget(self) + self.weather_floating_widget.hide() # 默认隐藏 + self.weather_floating_widget.closed.connect(self.on_weather_floating_closed) + self.weather_floating_widget.refresh_requested.connect(self.refresh_weather) + # 设置窗口属性 self.setWindowTitle("文档1 - MagicWord") self.setGeometry(100, 100, 1200, 800) @@ -440,8 +447,14 @@ class WordStyleMainWindow(QMainWindow): print(f"获取到天气数据: {weather_data}") # 直接传递原始数据,update_weather_display会处理嵌套结构 self.update_weather_display(weather_data) + # 同步更新天气悬浮窗口 + if hasattr(self, 'weather_floating_widget') and self.weather_floating_widget.isVisible(): + self.weather_floating_widget.update_weather(weather_data) else: print(f"无法获取城市 {city} 的天气数据") + # 显示错误信息到天气悬浮窗口 + if hasattr(self, 'weather_floating_widget') and self.weather_floating_widget.isVisible(): + self.weather_floating_widget.update_weather({'error': '无法获取天气数据'}) def refresh_weather(self): """刷新天气""" @@ -692,6 +705,11 @@ class WordStyleMainWindow(QMainWindow): show_weather_action = QAction('显示详细天气', self) show_weather_action.triggered.connect(self.show_detailed_weather) weather_menu.addAction(show_weather_action) + + # 天气悬浮窗口 + toggle_floating_weather_action = QAction('天气悬浮窗口', self) + toggle_floating_weather_action.triggered.connect(self.toggle_floating_weather) + weather_menu.addAction(toggle_floating_weather_action) # 插入菜单 insert_menu = menubar.addMenu('插入(I)') @@ -929,6 +947,9 @@ class WordStyleMainWindow(QMainWindow): if hasattr(self.ribbon, 'refresh_weather_btn'): self.ribbon.refresh_weather_btn.clicked.connect(self.refresh_weather) + if hasattr(self.ribbon, 'floating_weather_btn'): + self.ribbon.floating_weather_btn.clicked.connect(self.toggle_floating_weather) + # 日历组件信号 if hasattr(self, 'calendar_widget'): self.calendar_widget.date_selected.connect(self.insert_date_to_editor) @@ -1623,9 +1644,15 @@ class WordStyleMainWindow(QMainWindow): print(f"refresh_weather - 原始数据包含life_tips: {weather_data.get('life_tips', [])}") print(f"refresh_weather - formatted_data包含life_tips: {formatted_data.get('life_tips', [])}") self.update_weather_display(formatted_data) + # 同步更新天气悬浮窗口 + if hasattr(self, 'weather_floating_widget') and self.weather_floating_widget.isVisible(): + self.weather_floating_widget.update_weather(formatted_data) self.status_bar.showMessage("天气数据已刷新", 2000) else: self.status_bar.showMessage("天气数据刷新失败,请检查API密钥", 3000) + # 显示错误信息到天气悬浮窗口 + if hasattr(self, 'weather_floating_widget') and self.weather_floating_widget.isVisible(): + self.weather_floating_widget.update_weather({'error': '天气数据刷新失败'}) except Exception as e: self.status_bar.showMessage(f"天气刷新失败: {str(e)}", 3000) @@ -1721,6 +1748,29 @@ class WordStyleMainWindow(QMainWindow): self.refresh_weather() dialog.close() + def toggle_floating_weather(self): + """切换天气悬浮窗口显示/隐藏""" + if hasattr(self, 'weather_floating_widget'): + if self.weather_floating_widget.isVisible(): + self.weather_floating_widget.hide() + self.status_bar.showMessage("天气悬浮窗口已隐藏", 2000) + else: + self.weather_floating_widget.show() + # 确保窗口在屏幕内 + self.weather_floating_widget.move(100, 100) + self.status_bar.showMessage("天气悬浮窗口已显示", 2000) + # 同步当前城市选择 + if hasattr(self, 'ribbon') and hasattr(self.ribbon, 'city_combo'): + current_city = self.ribbon.city_combo.currentText() + self.weather_floating_widget.set_current_city(current_city) + # 如果有天气数据,更新显示 + if hasattr(self, 'current_weather_data') and self.current_weather_data: + self.weather_floating_widget.update_weather(self.current_weather_data) + + def on_weather_floating_closed(self): + """天气悬浮窗口关闭时的处理""" + self.status_bar.showMessage("天气悬浮窗口已关闭", 2000) + def toggle_weather_tools(self, checked): """切换天气工具组显示""" if checked: