refactor(packaging): PyInstaller资源路径统一适配get_resource_path
This commit is contained in:
@ -5,9 +5,20 @@ Step5_5 面板 - 水质指数计算
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Union
|
||||
|
||||
|
||||
def get_resource_path(relative_path: str) -> str:
|
||||
"""获取资源的绝对路径,适配 PyInstaller 打包环境。"""
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
return os.path.join(sys._MEIPASS, relative_path)
|
||||
return os.path.abspath(
|
||||
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), relative_path)
|
||||
)
|
||||
|
||||
|
||||
import pandas as pd
|
||||
from PyQt5.QtWidgets import (
|
||||
QWidget, QVBoxLayout, QGroupBox, QFormLayout, QGridLayout,
|
||||
@ -153,10 +164,8 @@ class Step5_5Panel(QWidget):
|
||||
self.setLayout(main_layout)
|
||||
|
||||
# 自动加载内置公式文件
|
||||
formula_csv_path = (
|
||||
Path(__file__).resolve().parent.parent / "model" / "waterindex.csv"
|
||||
)
|
||||
if formula_csv_path.is_file():
|
||||
formula_csv_path = get_resource_path("data/sub/waterindex.csv")
|
||||
if os.path.isfile(formula_csv_path):
|
||||
self.formula_csv_widget.set_path(str(formula_csv_path))
|
||||
self.refresh_formulas()
|
||||
|
||||
|
||||
@ -410,13 +410,27 @@ class Step9Panel(QWidget):
|
||||
if not existing_out or not existing_out.strip():
|
||||
self.output_dir.set_path(output_dir)
|
||||
|
||||
# 5. 自动继承步骤1的水域掩膜作为边界文件
|
||||
# 5. 自动探测原始矢量边界文件(.shp)作为专题图底图
|
||||
# 优先回溯 input-test/roi.shp,geopandas.read_file 仅支持矢量格式
|
||||
if self.work_dir:
|
||||
default_mask = Path(self.work_dir) / "1_water_mask" / "water_mask_from_shp.dat"
|
||||
if default_mask.exists():
|
||||
possible_shp = None
|
||||
candidates = [
|
||||
Path(self.work_dir).parent / "input-test" / "roi.shp",
|
||||
Path(self.work_dir) / "roi.shp",
|
||||
Path(self.work_dir).parent / "roi.shp",
|
||||
]
|
||||
for candidate in candidates:
|
||||
if candidate.exists() and candidate.suffix.lower() == ".shp":
|
||||
possible_shp = candidate
|
||||
break
|
||||
|
||||
existing_boundary = (self.boundary_file.get_path() or "").strip()
|
||||
if not existing_boundary:
|
||||
self.boundary_file.set_path(str(default_mask))
|
||||
if not existing_boundary and possible_shp:
|
||||
self.boundary_file.set_path(str(possible_shp))
|
||||
elif not existing_boundary:
|
||||
# 未找到 .shp 时清空并提示用户手动选择矢量文件
|
||||
self.boundary_file.set_path("")
|
||||
print("⚠️ 提示:专题图生成模块需传入标准矢量边界文件 (.shp),请手动选择。")
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f"【{self.__class__.__name__}】自动填充失败,跳过: {e}")
|
||||
|
||||
@ -32,6 +32,18 @@ from PyQt5.QtGui import QIcon, QFont, QTextCursor, QPalette, QColor, QPixmap
|
||||
import sys
|
||||
import traceback
|
||||
|
||||
|
||||
def get_resource_path(relative_path: str) -> str:
|
||||
"""获取资源的绝对路径,适配 PyInstaller 打包环境。
|
||||
打包后资源位于 sys._MEIPASS(解压临时目录),开发环境则基于 __file__ 向上三级。
|
||||
"""
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
return os.path.join(sys._MEIPASS, relative_path)
|
||||
return os.path.abspath(
|
||||
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), relative_path)
|
||||
)
|
||||
|
||||
|
||||
def global_exception_handler(exc_type, exc_value, exc_traceback):
|
||||
print("\n" + "="*50)
|
||||
print("【严重错误拦截 - PyQt 崩溃死因】")
|
||||
@ -1398,19 +1410,8 @@ class WaterQualityGUI(QMainWindow):
|
||||
}
|
||||
|
||||
def get_icon_path(self, icon_filename):
|
||||
"""
|
||||
获取图标文件的完整路径
|
||||
在开发环境中从../data/icons/获取,在打包后从data/icons/获取
|
||||
"""
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
# 打包后的环境
|
||||
icon_dir = os.path.join(sys._MEIPASS, 'data', 'icons')
|
||||
else:
|
||||
# 开发环境
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
icon_dir = os.path.join(current_dir, '..', '..', 'data', 'icons')
|
||||
|
||||
return os.path.join(icon_dir, icon_filename)
|
||||
"""获取图标文件的完整路径(统一使用 get_resource_path)。"""
|
||||
return get_resource_path(f"data/icons/{icon_filename}")
|
||||
|
||||
def _disable_wheel_for_all_spinboxes(self):
|
||||
"""
|
||||
@ -1554,12 +1555,8 @@ class WaterQualityGUI(QMainWindow):
|
||||
}
|
||||
""")
|
||||
|
||||
# 设置Logo图片路径 - 使用相对路径(打包兼容)
|
||||
from pathlib import Path
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
logo_path = os.path.join(sys._MEIPASS, 'data', 'icons', 'logo.png')
|
||||
else:
|
||||
logo_path = str(Path(__file__).parent.parent.parent / "data" / "icons" / "logo.png")
|
||||
# 设置Logo图片路径
|
||||
logo_path = get_resource_path("data/icons/logo.png")
|
||||
logo_pixmap = QPixmap(logo_path)
|
||||
|
||||
if not logo_pixmap.isNull():
|
||||
@ -1692,10 +1689,7 @@ class WaterQualityGUI(QMainWindow):
|
||||
banner_widget.setStyleSheet("margin: 0px; padding: 0px; border: none;")
|
||||
|
||||
# 纯净底图路径(无水印文字)
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
banner_path = os.path.join(sys._MEIPASS, 'data', 'icons', 'Mega Water 1.0.jpg')
|
||||
else:
|
||||
banner_path = str(Path(__file__).parent.parent.parent / "data" / "icons" / "Mega Water 1.0.jpg")
|
||||
banner_path = get_resource_path("data/icons/Mega Water 1.0.jpg")
|
||||
self.banner_pixmap = QPixmap(banner_path)
|
||||
|
||||
if not self.banner_pixmap.isNull():
|
||||
@ -1822,14 +1816,14 @@ class WaterQualityGUI(QMainWindow):
|
||||
self.step_list.addItem(stage_item)
|
||||
|
||||
# 添加该阶段的所有步骤
|
||||
HIDDEN_STEP_IDS = {"step6_5", "step6_75", "step8_5", "step8_75"}
|
||||
for step_id, step_display in steps:
|
||||
if step_id in HIDDEN_STEP_IDS:
|
||||
continue
|
||||
|
||||
item = QListWidgetItem(f" └─ {step_display}")
|
||||
item.setData(Qt.UserRole, step_id)
|
||||
|
||||
# 隐藏4个冗余回归步骤(树节点)
|
||||
if step_id in ("step6_5", "step6_75", "step8_5", "step8_75"):
|
||||
item.setHidden(True)
|
||||
|
||||
self.step_name_map[step_display] = step_id
|
||||
|
||||
# 设置步骤项的样式
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import base64
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
@ -19,6 +20,15 @@ from docx.shared import Inches, Pt, Cm
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
from docx.enum.section import WD_SECTION
|
||||
from docx.oxml.ns import qn
|
||||
|
||||
|
||||
def get_resource_path(relative_path: str) -> str:
|
||||
"""获取资源的绝对路径,适配 PyInstaller 打包环境。"""
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
return os.path.join(sys._MEIPASS, relative_path)
|
||||
return os.path.abspath(
|
||||
os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), relative_path)
|
||||
)
|
||||
from docx.oxml import OxmlElement
|
||||
from docx.shared import RGBColor
|
||||
import pandas as pd
|
||||
@ -848,8 +858,8 @@ class WaterQualityReportGenerator:
|
||||
section.different_first_page_header_footer = True
|
||||
|
||||
# 1. 左上角图片(增大) - 使用相对路径
|
||||
cover_top_img_path = Path(__file__).parent.parent.parent / "data" / "icons" / "word" / "lica.png"
|
||||
if cover_top_img_path.exists():
|
||||
cover_top_img_path = get_resource_path("data/icons/word/lica.png")
|
||||
if os.path.isfile(cover_top_img_path):
|
||||
try:
|
||||
p = doc.add_paragraph()
|
||||
p.alignment = WD_ALIGN_PARAGRAPH.LEFT
|
||||
@ -897,8 +907,8 @@ class WaterQualityReportGenerator:
|
||||
|
||||
|
||||
# 4. 底部图片(增大) - 使用相对路径
|
||||
cover_bottom_img_path = Path(__file__).parent.parent.parent / "data" / "icons" / "word" / "fenmian.png"
|
||||
if cover_bottom_img_path.exists():
|
||||
cover_bottom_img_path = get_resource_path("data/icons/word/fenmian.png")
|
||||
if os.path.isfile(cover_bottom_img_path):
|
||||
try:
|
||||
p = doc.add_paragraph()
|
||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
@ -960,8 +970,8 @@ class WaterQualityReportGenerator:
|
||||
|
||||
|
||||
# 第一张图片 - 使用相对路径
|
||||
img1_path = Path(__file__).parent.parent.parent / "data" / "icons" / "word" / "屏幕截图 2026-03-31 144131.png"
|
||||
if img1_path.exists():
|
||||
img1_path = get_resource_path("data/icons/word/屏幕截图 2026-03-31 144131.png")
|
||||
if os.path.isfile(img1_path):
|
||||
p = doc.add_paragraph()
|
||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
p.add_run().add_picture(str(img1_path), width=Inches(6.0))
|
||||
@ -999,8 +1009,8 @@ class WaterQualityReportGenerator:
|
||||
self._style_heading(h, level=1)
|
||||
|
||||
# 插入图片 - 使用相对路径
|
||||
processing_img_path = Path(__file__).parent.parent.parent / "data" / "icons" / "word" / "liucheng.png"
|
||||
if processing_img_path.exists():
|
||||
processing_img_path = get_resource_path("data/icons/word/liucheng.png")
|
||||
if os.path.isfile(processing_img_path):
|
||||
p = doc.add_paragraph()
|
||||
p.alignment = WD_ALIGN_PARAGRAPH.CENTER
|
||||
p.add_run().add_picture(str(processing_img_path), width=Inches(6.5))
|
||||
@ -1356,8 +1366,8 @@ class WaterQualityReportGenerator:
|
||||
header_para = header.add_paragraph()
|
||||
|
||||
# 1. 最左侧图片 - 使用相对路径
|
||||
header_img_path = Path(__file__).parent.parent.parent / "data" / "icons" / "word" / "lica.png"
|
||||
if header_img_path.exists():
|
||||
header_img_path = get_resource_path("data/icons/word/lica.png")
|
||||
if os.path.isfile(header_img_path):
|
||||
try:
|
||||
run_img = header_para.add_run()
|
||||
run_img.add_picture(str(header_img_path), width=Inches(1.6))
|
||||
|
||||
Reference in New Issue
Block a user