chore: replace app icon uitubiao.ico -> app.ico (converted from app.png)

This commit is contained in:
duxin
2026-07-14 15:15:03 +08:00
parent d4de09caa2
commit 5b04a120e3
3 changed files with 226 additions and 1 deletions

BIN
data/icons-1/app.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -336,7 +336,7 @@ class WaterQualityGUI(QMainWindow):
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(my_appid) ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(my_appid)
super().__init__() super().__init__()
icon_path = get_resource_path("data/icons-1/uitubiao.ico") icon_path = get_resource_path("data/icons-1/app.ico")
self.setWindowIcon(QIcon(icon_path)) self.setWindowIcon(QIcon(icon_path))
# 第一步:创建各 Manager纯连线不执行业务 # 第一步:创建各 Manager纯连线不执行业务

225
water_quality_app.spec Normal file
View File

@ -0,0 +1,225 @@
# -*- coding: utf-8 -*-
# ==============================================================================
# 水质参数反演分析系统 - 终极纯净版 PyInstaller Spec 配置文件
# 彻底斩断 venv 交叉污染,强制 Conda 原生环境全量解析
# 用法: pyinstaller --clean water_quality_app.spec
# ==============================================================================
import os
import sys
import glob
import shutil
block_cipher = None
# ==============================================================================
# 0. 基础路径配置 (❌ 彻底移除了 VENV_SITE 变量,拒绝交叉环境污染!)
# ==============================================================================
PROJECT_ROOT = os.path.abspath(os.getcwd())
SRC_DIR = os.path.join(PROJECT_ROOT, "src")
BUILD_DIR = os.path.join(PROJECT_ROOT, "build")
DIST_DIR = os.path.join(PROJECT_ROOT, "dist")
# Conda WQ_GUI 环境 DLL 路径MSVC 运行时 + GIS 核心库原生纯净副本)
CONDA_ENV_DLLS = r"D:\111\changyongruanjian\anconda\envs\WQ_GUI"
CONDA_OSGEO_DLLS = os.path.join(CONDA_ENV_DLLS, "Lib", "site-packages", "osgeo")
# ==============================================================================
# 1. 静态资源与数据文件收集 (datas)
# ==============================================================================
def get_data_files():
datas = []
# 1-1. 根目录核心配置文件 (包含内置公式 CSV)
single_files = [
"waterindex.csv",
"requirements.txt",
"README.md",
".md",
]
for f in single_files:
if os.path.exists(os.path.join(PROJECT_ROOT, f)):
datas.append((os.path.join(PROJECT_ROOT, f), "."))
# 1-2. data/ 目录(全量递归映射,确保代码通过 get_resource_path 能读到任务栏图标)
data_dir = os.path.join(PROJECT_ROOT, "data")
if os.path.isdir(data_dir):
datas.append((data_dir, "data"))
# 1-3. src/gui/model/ 模型参数文件
model_dir = os.path.join(SRC_DIR, "gui", "model")
if os.path.isdir(model_dir):
datas.append((model_dir, "src/gui/model"))
# 1-4. src/auth/ 离线授权验证模块
auth_dir = os.path.join(SRC_DIR, "auth")
if os.path.isdir(auth_dir):
datas.append((auth_dir, "src/auth"))
# 1-5. 运行时环境变量与 DLL 挂载钩子
rthook_script = os.path.join(PROJECT_ROOT, "scripts", "rthook_add_dll_dirs.py")
if os.path.exists(rthook_script):
datas.append((rthook_script, "scripts"))
return datas
datas = get_data_files()
# ==============================================================================
# 2. 核心二进制文件搜集 (binaries) - 强制抓取纯净运行库防静默崩溃
# ==============================================================================
def get_binaries():
binaries = []
# 2-1. 精准提取 Conda 环境下与编译完全匹配的 MSVC 运行库
if os.path.isdir(CONDA_ENV_DLLS):
for dll_name in [
"msvcp140.dll",
"msvcp140_1.dll",
"msvcp140_2.dll",
"msvcp140_atomic_wait.dll",
"msvcp140_codecvt_ids.dll",
"vcruntime140.dll",
"vcruntime140_1.dll",
"vcruntime140_threads.dll",
"concrt140.dll",
"vcomp140.dll",
"vcamp140.dll",
"vccorlib140.dll",
]:
dll_path = os.path.join(CONDA_ENV_DLLS, dll_name)
if os.path.exists(dll_path):
binaries.append((dll_path, "."))
# 2-2. 搜集底层 GDAL/GEOS/PROJ 核心框架与二进制扩展
if os.path.isdir(CONDA_OSGEO_DLLS):
for dll_name in ["gdal.dll", "geos.dll", "geos_c.dll", "proj_9.dll"]:
dll_path = os.path.join(CONDA_OSGEO_DLLS, dll_name)
if os.path.exists(dll_path):
binaries.append((dll_path, "."))
# 映射 Python 3.12 对应的底层二进制接口 (C-Extension)
for pyd_name in [
"_gdal.cp312-win_amd64.pyd",
"_gdal_array.cp312-win_amd64.pyd",
"_gdalconst.cp312-win_amd64.pyd"
]:
pyd_path = os.path.join(CONDA_OSGEO_DLLS, pyd_name)
if os.path.exists(pyd_path):
binaries.append((pyd_path, "osgeo"))
return binaries
binaries = get_binaries()
# ==============================================================================
# 3. 隐式依赖与底层动态加载池 (hiddenimports)
# ==============================================================================
hidden_imports = [
"PyQt5.sip",
# GDAL 空间处理核心
"osgeo", "osgeo.gdal", "osgeo.gdalconst", "osgeo.gdalnumeric", "osgeo.ogr", "osgeo.osr",
# 解决 rasterio 与 fiona 二进制隐藏扩展的断层报错
"rasterio._base", "rasterio._env", "rasterio._io", "rasterio._warp",
"rasterio._features", "rasterio._path", "rasterio.crs", "rasterio.env",
"rasterio.features", "rasterio.warp", "rasterio.windows", "rasterio.sample", "rasterio.vrt",
"fiona._env", "fiona._geometry", "fiona.ogrext", "fiona.io", "fiona.env", "fiona.features",
# 几何计算与坐标转换
"shapely._geos", "shapely._geometry", "shapely.lib",
"pyproj", "pyproj._datadir", "pyproj._crs",
"geopandas", "geopandas._compat", "geopandas.io",
# 底层科学计算库支持
"scipy.special._orthogonal", "scipy.spatial", "scipy.linalg",
"sklearn.utils._index_deprecations", "sklearn.utils._testing", "sklearn._loss",
"sklearn.ensemble", "sklearn.preprocessing", "sklearn.model_selection",
# 报告与文档导出组件
"docx", "docx.oxml", "docx.table", "docx.text",
"lxml.etree", "lxml.objectify",
# 业务面板与自定义挂载
"src.gui.styles", "src.gui.components.custom_widgets",
]
# ==============================================================================
# 4. 运行时前置初始化钩子 (runtime_hooks)
# ==============================================================================
runtime_hooks = []
rthook_path = os.path.join(PROJECT_ROOT, "scripts", "rthook_add_dll_dirs.py")
if os.path.exists(rthook_path):
runtime_hooks.append(rthook_path)
# ==============================================================================
# 5. 精简排除列表 (excludes) - 严格保留标准库防级联瘫痪
# ==============================================================================
excludes = [
"tkinter",
"matplotlib.tests",
"PyQt5.QtTest",
"PyQt5.QtWebEngine",
"PyQt5.QtWebEngineWidgets",
"pytest",
]
# ==============================================================================
# 6. 核心构建流程 (Analysis -> PYZ -> EXE -> COLLECT)
# ==============================================================================
appname = "MegaWater"
a = Analysis(
["src/gui/water_quality_gui_v2.py"],
# ⚠️ 绝对关键:仅保留项目原生搜索路径,彻底切断与混合虚拟环境的联系
pathex=[PROJECT_ROOT, SRC_DIR],
binaries=binaries,
datas=datas,
hiddenimports=hidden_imports,
hookspath=["scripts"] if os.path.isdir(os.path.join(PROJECT_ROOT, "scripts")) else [],
hooksconfig={},
runtime_hooks=runtime_hooks,
excludes=excludes,
win_no_prefer_redirects=False,
cipher=block_cipher,
noarchive=False,
)
# 强制清洗可能由于第三方包引入导致的、存在版本冲突的残缺 MSVC 动态库
a.binaries = [
x for x in a.binaries
if not x[0].lower().startswith(('msvcp140', 'vcruntime140'))
]
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
# 生成物理启动核心
exe = EXE(
pyz,
a.scripts,
[],
exclude_binaries=True,
name=appname,
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False, # 禁用 UPX 暴力压缩,保护二进制 C++ 区段完整性
console=False, # ⚠️ 维持开启控制台,拒绝绝对静默崩溃
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon="data/icons-1/app.ico", # 锁定物理执行文件桌面正方形主图标
)
# 组装最终绿色分发目录 (_internal + EXE) - 引入全自动纯净 DLL 填坑机制
coll = COLLECT(
exe,
a.binaries,
a.zipfiles,
a.datas,
# 强制将原生编译的底层运行库塞入分发根目录,终结指针断层!
[
('msvcp140.dll', os.path.join(CONDA_ENV_DLLS, 'msvcp140.dll'), 'BINARY'),
('vcruntime140.dll', os.path.join(CONDA_ENV_DLLS, 'vcruntime140.dll'), 'BINARY')
],
strip=False,
upx=False,
upx_exclude=[],
name=appname,
)