0.2.1 #39

Merged
pshjeamgr merged 3 commits from main into llllllllllllllCC 4 months ago

@ -13,6 +13,9 @@ from datetime import datetime
class WordRibbonTab(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.weather_group = None # 天气组件组
self.weather_visible = False # 天气组件显示状态
self.ribbon_layout = None # 功能区布局
self.setup_ui()
def setup_ui(self):
@ -24,6 +27,11 @@ class WordRibbonTab(QWidget):
class WordRibbon(QFrame):
def __init__(self, parent=None):
super().__init__(parent)
self.weather_visible = False # 天气组件显示状态
self.weather_group = None # 天气组件组
self.quote_visible = False # 每日一言组件显示状态
self.quote_group = None # 每日一言组件组
self.ribbon_layout = None # 功能区布局
self.setup_ui()
def setup_ui(self):
@ -45,35 +53,16 @@ class WordRibbon(QFrame):
}
""")
ribbon_layout = QHBoxLayout()
ribbon_layout.setContentsMargins(10, 5, 10, 5)
ribbon_layout.setSpacing(15)
self.ribbon_layout = QHBoxLayout() # 保存为实例变量
self.ribbon_layout.setContentsMargins(10, 5, 10, 5)
self.ribbon_layout.setSpacing(15)
# 开始标签的内容(最常用的功能)
self.setup_home_tab(ribbon_layout)
self.setup_home_tab(self.ribbon_layout)
# 添加天气工具组
weather_group = self.create_ribbon_group("天气")
weather_layout = QVBoxLayout()
# 天气工具组将在需要时动态添加
# 城市选择
self.city_combo = QComboBox()
self.city_combo.setFixedWidth(100)
self.city_combo.addItems(['自动定位', '北京', '上海', '广州', '深圳', '杭州', '南京', '武汉', '成都', '西安'])
self.city_combo.setCurrentText('自动定位')
self.city_combo.currentTextChanged.connect(self.on_city_changed)
# 刷新按钮
self.refresh_weather_btn = QPushButton("刷新天气")
self.refresh_weather_btn.clicked.connect(self.on_refresh_weather)
self.refresh_weather_btn.setFixedSize(80, 25)
weather_layout.addWidget(self.city_combo)
weather_layout.addWidget(self.refresh_weather_btn)
weather_group.setLayout(weather_layout)
ribbon_layout.addWidget(weather_group)
self.ribbon_area.setLayout(ribbon_layout)
self.ribbon_area.setLayout(self.ribbon_layout)
main_layout.addWidget(self.ribbon_area)
self.setLayout(main_layout)
@ -179,6 +168,105 @@ class WordRibbon(QFrame):
"""下划线按钮点击处理"""
pass
def create_weather_group(self):
"""创建天气组件组"""
if self.weather_group is not None:
return self.weather_group
weather_group = self.create_ribbon_group("天气")
weather_layout = QVBoxLayout()
# 城市选择 - 添加所有省会城市
self.city_combo = QComboBox()
self.city_combo.setFixedWidth(120) # 增加宽度以显示完整城市名
self.city_combo.addItems([
'自动定位',
'北京', '上海', '广州', '深圳', '杭州', '南京', '武汉', '成都', '西安', # 一线城市
'天津', '重庆', '苏州', '青岛', '大连', '宁波', '厦门', '无锡', '佛山', # 新一线城市
'石家庄', '太原', '呼和浩特', '沈阳', '长春', '哈尔滨', # 东北华北
'合肥', '福州', '南昌', '济南', '郑州', '长沙', '南宁', '海口', # 华东华中华南
'贵阳', '昆明', '拉萨', '兰州', '西宁', '银川', '乌鲁木齐' # 西南西北
])
self.city_combo.setCurrentText('自动定位')
self.city_combo.currentTextChanged.connect(self.on_city_changed)
# 刷新按钮
self.refresh_weather_btn = QPushButton("刷新天气")
self.refresh_weather_btn.clicked.connect(self.on_refresh_weather)
self.refresh_weather_btn.setFixedSize(80, 25)
weather_layout.addWidget(self.city_combo)
weather_layout.addWidget(self.refresh_weather_btn)
weather_group.setLayout(weather_layout)
self.weather_group = weather_group
return weather_group
def show_weather_group(self):
"""显示天气组件"""
if not self.weather_visible and self.weather_group is None:
weather_group = self.create_weather_group()
# 在编辑组之后添加天气组
if self.ribbon_layout:
# 找到编辑组的位置,在其后插入天气组
insert_index = self.ribbon_layout.count() - 1 # 在stretch之前插入
self.ribbon_layout.insertWidget(insert_index, weather_group)
self.weather_visible = True
def hide_weather_group(self):
"""隐藏天气组件"""
if self.weather_visible and self.weather_group is not None:
self.weather_group.setParent(None)
self.weather_group = None
self.weather_visible = False
def create_quote_group(self):
"""创建每日一言组件组"""
if self.quote_group is not None:
return self.quote_group
quote_group = self.create_ribbon_group("每日一言")
quote_layout = QVBoxLayout()
# 每日一言显示标签
self.quote_label = QLabel("每日一言: 暂无")
self.quote_label.setStyleSheet("QLabel { color: #666666; font-style: italic; font-size: 10px; }")
self.quote_label.setWordWrap(True)
self.quote_label.setFixedWidth(150)
# 刷新按钮
self.refresh_quote_btn = QPushButton("刷新箴言")
self.refresh_quote_btn.clicked.connect(self.on_refresh_quote)
self.refresh_quote_btn.setFixedSize(80, 25)
quote_layout.addWidget(self.quote_label)
quote_layout.addWidget(self.refresh_quote_btn)
quote_group.setLayout(quote_layout)
self.quote_group = quote_group
return quote_group
def show_quote_group(self):
"""显示每日一言组件"""
if not self.quote_visible and self.quote_group is None:
quote_group = self.create_quote_group()
# 在天气组之后添加每日一言组
if self.ribbon_layout:
# 找到合适的位置插入每日言组
insert_index = self.ribbon_layout.count() - 1 # 在stretch之前插入
# 如果天气组件存在,在其后插入;否则在编辑组后插入
if self.weather_group is not None and self.weather_visible:
insert_index = self.ribbon_layout.indexOf(self.weather_group) + 1
self.ribbon_layout.insertWidget(insert_index, quote_group)
self.quote_visible = True
def hide_quote_group(self):
"""隐藏每日一言组件"""
if self.quote_visible and self.quote_group is not None:
self.quote_group.setParent(None)
self.quote_group = None
self.quote_visible = False
def create_ribbon_group(self, title):
"""创建功能区组"""
group = QGroupBox(title)
@ -208,6 +296,15 @@ class WordRibbon(QFrame):
"""城市选择变化处理"""
pass
def on_refresh_quote(self):
"""刷新每日一言按钮点击处理"""
pass
def update_quote_display(self, quote_text):
"""更新每日一言显示"""
if hasattr(self, 'quote_label') and self.quote_label:
self.quote_label.setText(f"每日一言: {quote_text}")
def create_ribbon_button(self, text, shortcut, icon_name):
"""创建功能区按钮"""
btn = QToolButton()
@ -575,6 +672,24 @@ class WeatherAPI:
results[city] = weather_data
return results
def get_isp_info(self):
"""获取ISP信息"""
try:
url = "http://ip-api.com/json/"
response = requests.get(url, timeout=5)
response.raise_for_status()
data = response.json()
if data.get('status') == 'success':
isp = data.get('isp', '')
org = data.get('org', '')
as_info = data.get('as', '')
return f"{isp} {org} {as_info}".strip()
return None
except Exception as e:
print(f"获取ISP信息失败: {e}")
return None
def get_location_by_ip(self):
"""通过IP地址获取用户位置"""
try:
@ -675,12 +790,159 @@ class WeatherAPI:
city = self.get_location_by_ip()
if city:
print(f"通过IP定位成功: {city}")
# 检查是否是教育网或特殊网络环境
isp_info = self.get_isp_info()
if isp_info and ('教育网' in isp_info or 'CERNET' in isp_info or 'University' in isp_info):
print(f"检测到教育网环境: {isp_info}")
print("教育网IP定位可能不准确建议手动选择城市")
# 教育网环境下如果定位到北京可能是IP分配问题
if city.lower() in ['beijing', '北京', 'haidian', '海淀']:
print("提示:教育网环境下北京定位可能是网络出口导致的")
return {'city': city, 'note': '教育网环境,定位可能不准确', 'isp': isp_info}
# 智能处理 - 如果是区级单位,映射到市级城市
district_to_city_map = {
# 北京各区
'海淀': '北京',
'haidian': '北京',
'朝阳': '北京',
'chaoyang': '北京',
'东城': '北京',
'dongcheng': '北京',
'西城': '北京',
'xicheng': '北京',
'丰台': '北京',
'fengtai': '北京',
'石景山': '北京',
'shijingshan': '北京',
'通州': '北京',
'tongzhou': '北京',
'昌平': '北京',
'changping': '北京',
'大兴': '北京',
'daxing': '北京',
'怀柔': '北京',
'huairou': '北京',
'平谷': '北京',
'pinggu': '北京',
'门头沟': '北京',
'mentougou': '北京',
'密云': '北京',
'miyun': '北京',
'延庆': '北京',
'yanqing': '北京',
'房山': '北京',
'fangshan': '北京',
'顺义': '北京',
'shunyi': '北京',
# 天津各区
'和平': '天津',
'heping': '天津',
'河东': '天津',
'hedong': '天津',
'河西': '天津',
'hexi': '天津',
'南开': '天津',
'nankai': '天津',
'河北': '天津',
'hebei': '天津',
'红桥': '天津',
'hongqiao': '天津',
'滨海新区': '天津',
'binhaixinqu': '天津',
'东丽': '天津',
'dongli': '天津',
'西青': '天津',
'xiqing': '天津',
'津南': '天津',
'jinnan': '天津',
'北辰': '天津',
'beichen': '天津',
'武清': '天津',
'wuqing': '天津',
'宝坻': '天津',
'baodi': '天津',
'宁河': '天津',
'ninghe': '天津',
'静海': '天津',
'jinghai': '天津',
'蓟州': '天津',
'jizhou': '天津',
# 上海各区
'黄浦': '上海',
'huangpu': '上海',
'徐汇': '上海',
'xuhui': '上海',
'长宁': '上海',
'changning': '上海',
'静安': '上海',
'jingan': '上海',
'普陀': '上海',
'putuo': '上海',
'虹口': '上海',
'hongkou': '上海',
'杨浦': '上海',
'yangpu': '上海',
'闵行': '上海',
'minhang': '上海',
'宝山': '上海',
'baoshan': '上海',
'嘉定': '上海',
'jiading': '上海',
'浦东': '上海',
'pudong': '上海',
'金山': '上海',
'jinshan': '上海',
'松江': '上海',
'songjiang': '上海',
'青浦': '上海',
'qingpu': '上海',
'奉贤': '上海',
'fengxian': '上海',
'崇明': '上海',
'chongming': '上海',
# 广州各区
'天河': '广州',
'tianhe': '广州',
'越秀': '广州',
'yuexiu': '广州',
'海珠': '广州',
'haizhu': '广州',
'荔湾': '广州',
'liwan': '广州',
'白云': '广州',
'baiyun': '广州',
'黄埔': '广州',
'huangpu': '广州',
'番禺': '广州',
'panyu': '广州',
'花都': '广州',
'huadu': '广州',
'南沙': '广州',
'nansha': '广州',
'从化': '广州',
'conghua': '广州',
'增城': '广州',
'zengcheng': '广州'
}
# 检查是否是区级单位,如果是则映射到市级城市
city_lower = city.lower()
if city_lower in district_to_city_map:
mapped_city = district_to_city_map[city_lower]
print(f"智能映射: {city} -> {mapped_city}")
city = mapped_city
return {'city': city}
# 如果IP定位失败尝试其他方法
# 可以尝试使用浏览器的地理位置API但这需要前端支持
print("自动定位失败,使用默认城市")
print("自动定位失败,建议手动选择城市")
return None
except Exception as e:
@ -692,6 +954,138 @@ class WeatherAPI:
try:
# 处理英文城市名映射
original_city_name = city_name
# 智能城市映射 - 将区级单位映射到市级城市
district_to_city_map = {
# 北京各区
'海淀': '北京',
'朝阳': '北京',
'东城': '北京',
'西城': '北京',
'丰台': '北京',
'石景山': '北京',
'通州': '北京',
'昌平': '北京',
'大兴': '北京',
'怀柔': '北京',
'平谷': '北京',
'门头沟': '北京',
'密云': '北京',
'延庆': '北京',
'房山': '北京',
'顺义': '北京',
'haidian': '北京',
'chaoyang': '北京',
'dongcheng': '北京',
'xicheng': '北京',
'fengtai': '北京',
'shijingshan': '北京',
'tongzhou': '北京',
'changping': '北京',
'daxing': '北京',
'huairou': '北京',
'pinggu': '北京',
'mentougou': '北京',
'miyun': '北京',
'yanqing': '北京',
'fangshan': '北京',
'shunyi': '北京',
# 天津各区(统一映射到天津)
'和平': '天津',
'heping': '天津',
'河东': '天津',
'hedong': '天津',
'河西': '天津',
'hexi': '天津',
'南开': '天津',
'nankai': '天津',
'河北': '天津',
'红桥': '天津',
'hongqiao': '天津',
'滨海新区': '天津',
'binhaixinqu': '天津',
'东丽': '天津',
'dongli': '天津',
'西青': '天津',
'xiqing': '天津',
'津南': '天津',
'jinnan': '天津',
'北辰': '天津',
'beichen': '天津',
'武清': '天津',
'wuqing': '天津',
'宝坻': '天津',
'baodi': '天津',
'宁河': '天津',
'ninghe': '天津',
'静海': '天津',
'jinghai': '天津',
'蓟州': '天津',
'jizhou': '天津',
'黄浦': '上海',
'徐汇': '上海',
'长宁': '上海',
'静安': '上海',
'普陀': '上海',
'虹口': '上海',
'杨浦': '上海',
'闵行': '上海',
'宝山': '上海',
'嘉定': '上海',
'浦东': '上海',
'金山': '上海',
'松江': '上海',
'青浦': '上海',
'奉贤': '上海',
'崇明': '上海',
'huangpu': '上海',
'xuhui': '上海',
'changning': '上海',
'jingan': '上海',
'putuo': '上海',
'hongkou': '上海',
'yangpu': '上海',
'minhang': '上海',
'baoshan': '上海',
'jiading': '上海',
'pudong': '上海',
'jinshan': '上海',
'songjiang': '上海',
'qingpu': '上海',
'fengxian': '上海',
'chongming': '上海',
'天河': '广州',
'越秀': '广州',
'海珠': '广州',
'荔湾': '广州',
'白云': '广州',
'黄埔': '广州',
'番禺': '广州',
'花都': '广州',
'南沙': '广州',
'从化': '广州',
'增城': '广州',
'tianhe': '广州',
'yuexiu': '广州',
'haizhu': '广州',
'liwan': '广州',
'baiyun': '广州',
'huangpu': '广州',
'panyu': '广州',
'huadu': '广州',
'nansha': '广州',
'conghua': '广州',
'zengcheng': '广州'
}
# 检查是否是区级单位,如果是则映射到市级城市
city_lower = city_name.lower()
if city_lower in district_to_city_map:
mapped_city = district_to_city_map[city_lower]
print(f"智能映射: {city_name} -> {mapped_city}")
city_name = mapped_city
if city_name in self.city_id_map:
# 如果是英文城市名,先映射到中文
mapped_name = self.city_id_map.get(city_name)

@ -143,7 +143,20 @@ class WordStyleMainWindow(QMainWindow):
if current_city == '自动定位':
# 使用自动定位
print("使用自动定位")
weather_data = self.weather_api.get_weather_data()
location_info = self.weather_api.get_current_location()
if location_info:
if 'note' in location_info:
# 检测到特殊网络环境
print(f"网络环境提示: {location_info['note']}")
if '教育网' in location_info['note'] and location_info['city'].lower() in ['beijing', '北京', 'haidian', '海淀']:
print("建议:教育网环境下北京定位可能不准确,可手动选择天津")
# 可以选择提示用户手动选择,或者使用上次的定位
# 使用定位到的城市获取天气
actual_city = location_info.get('city', '北京')
weather_data = self.weather_api.get_weather_data(actual_city)
else:
# 定位失败,使用默认城市
weather_data = self.weather_api.get_weather_data()
else:
# 使用选中的城市
print(f"使用选中的城市: {current_city}")
@ -327,6 +340,22 @@ class WordStyleMainWindow(QMainWindow):
# 天气功能
weather_menu = view_menu.addMenu('天气信息')
# 显示天气工具组
self.show_weather_tools_action = QAction('显示天气工具', self)
self.show_weather_tools_action.setCheckable(True)
self.show_weather_tools_action.setChecked(False) # 默认不显示
self.show_weather_tools_action.triggered.connect(self.toggle_weather_tools)
weather_menu.addAction(self.show_weather_tools_action)
# 显示每日一言工具组
self.show_quote_tools_action = QAction('显示每日一言工具', self)
self.show_quote_tools_action.setCheckable(True)
self.show_quote_tools_action.setChecked(False) # 默认不显示
self.show_quote_tools_action.triggered.connect(self.toggle_quote_tools)
weather_menu.addAction(self.show_quote_tools_action)
weather_menu.addSeparator()
# 刷新天气
refresh_weather_action = QAction('刷新天气', self)
refresh_weather_action.setShortcut('F5')
@ -706,6 +735,69 @@ class WordStyleMainWindow(QMainWindow):
self.refresh_weather()
dialog.close()
def toggle_weather_tools(self, checked):
"""切换天气工具组显示"""
if checked:
# 显示天气工具组
if hasattr(self, 'ribbon'):
self.ribbon.show_weather_group()
self.status_bar.showMessage("天气工具已显示", 2000)
else:
# 隐藏天气工具组
if hasattr(self, 'ribbon'):
self.ribbon.hide_weather_group()
self.status_bar.showMessage("天气工具已隐藏", 2000)
def toggle_quote_tools(self, checked):
"""切换每日一言工具组显示"""
if checked:
# 显示每日一言工具组
if hasattr(self, 'ribbon'):
self.ribbon.show_quote_group()
self.status_bar.showMessage("每日一言工具已显示", 2000)
# 如果当前没有显示内容,刷新一次
if hasattr(self.ribbon, 'quote_label') and self.ribbon.quote_label.text() == "每日一言: 暂无":
self.refresh_daily_quote()
else:
# 隐藏每日一言工具组
if hasattr(self, 'ribbon'):
self.ribbon.hide_quote_group()
self.status_bar.showMessage("每日一言工具已隐藏", 2000)
def refresh_daily_quote(self):
"""刷新每日一言 - 使用线程获取"""
# 创建并启动获取名言的线程
self.quote_thread = QuoteFetchThread()
self.quote_thread.quote_fetched.connect(self.on_quote_fetched)
self.quote_thread.start()
def on_quote_fetched(self, quote_data):
"""处理名言获取成功"""
if 'error' not in quote_data:
content = quote_data.get('content', '获取名言失败')
author = quote_data.get('author', '未知')
quote_text = f"{content}{author}"
# 更新Ribbon中的每日一言显示
if hasattr(self.ribbon, 'quote_label'):
self.ribbon.quote_label.setText(f"每日一言: {quote_text}")
# 更新状态栏
self.status_bar.showMessage(f"每日名言: {quote_text}", 10000)
else:
# 处理错误情况
error_msg = quote_data.get('error', '获取名言失败')
if hasattr(self.ribbon, 'quote_label'):
self.ribbon.quote_label.setText(f"每日一言: 获取失败")
self.status_bar.showMessage(f"每日名言获取失败: {error_msg}", 5000)
def on_quote_error(self, error_data):
"""处理名言获取错误"""
error_msg = error_data.get('error', '获取名言失败') if isinstance(error_data, dict) else str(error_data)
if hasattr(self.ribbon, 'quote_label'):
self.ribbon.quote_label.setText(f"每日一言: 获取失败")
self.status_bar.showMessage(f"每日名言获取失败: {error_msg}", 5000)
def update_quote_display(self, quote_data):
"""更新名言显示"""
if 'error' not in quote_data:

Loading…
Cancel
Save