This commit is contained in:
陈横 2025-10-11 09:27:51 +08:00
commit 0728bd7290
141 changed files with 25783 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

10
.idea/AugmentWebviewStateStore.xml generated Normal file

File diff suppressed because one or more lines are too long

14
.idea/MetaCore.iml generated Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.13 (MetaCore-startup)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

View File

@ -0,0 +1,12 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyStubPackagesAdvertiser" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<list>
<option value="PyQt5-stubs==5.15.6.0" />
</list>
</option>
</inspection_tool>
</profile>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (MetaCore-startup)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/MetaCore.iml" filepath="$PROJECT_DIR$/.idea/MetaCore.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,224 @@
# 跨平台路径处理优化报告
## 优化概述
本次优化主要针对 MetaCore 项目中的跨平台兼容性和路径处理问题,使用现代 Python 标准库 `pathlib` 替代传统的 `os.path`,并创建了专门的工具类来处理跨平台差异。
## 主要问题
### 1. 路径处理问题
- **混合使用路径分隔符**:代码中存在大量 `replace('\\', '/')` 操作,这是不规范且不可靠的做法
- **硬编码路径**存在平台特定的硬编码路径如Linux下的 `/home/tiger/下载/pycharm-2025.2.0.1/bin/pycharm.sh`
- **不一致的路径API**:混合使用 `os.path.join` 和字符串拼接
### 2. 跨平台兼容性问题
- **平台检测重复**:多处重复的平台类型检测代码
- **可执行文件查找**:没有统一的可执行文件查找机制
- **路径规范化不统一**:不同地方使用不同的路径规范化方法
## 优化方案
### 1. 创建工具类
#### PathUtils 类
```python
class PathUtils:
"""跨平台路径处理工具类"""
@staticmethod
def normalize_path(path_str: str) -> Path:
"""规范化路径为Path对象"""
@staticmethod
def ensure_path_exists(path: Path, is_file: bool = False) -> bool:
"""确保路径存在"""
@staticmethod
def safe_path_join(*parts) -> Path:
"""安全地连接路径部分"""
@staticmethod
def is_valid_path(path_str: str) -> bool:
"""检查路径字符串是否有效"""
```
#### PlatformUtils 类
```python
class PlatformUtils:
"""跨平台工具类"""
@staticmethod
def get_system_type() -> str:
"""获取系统类型"""
@staticmethod
def get_executable_extension() -> str:
"""获取可执行文件扩展名"""
@staticmethod
def get_python_executable(venv_path: Path) -> Path:
"""获取虚拟环境中的Python可执行文件路径"""
@staticmethod
def get_pycharm_paths() -> List[Path]:
"""获取各平台PyCharm可能的安装路径"""
@staticmethod
def find_executable(paths: List[Path]) -> Optional[Path]:
"""在指定路径列表中查找可执行文件"""
```
### 2. 优化的文件
#### MetaCore/data/project_manager.py
- **完全重构**:使用 `pathlib.Path` 替代所有 `os.path` 操作
- **统一路径处理**:所有路径操作都通过 `PathUtils` 进行
- **移除硬编码路径**:使用动态路径查找替代硬编码路径
- **改进的PyCharm集成**:使用统一的可执行文件查找机制
#### MetaCore/ui/project_card.py
- **优化 show_in_explorer 方法**:使用 `pathlib` 处理路径
- **改进错误处理**:更好的异常处理和用户提示
- **跨平台文件管理器支持**:统一的文件管理器打开逻辑
### 3. 主要改进
#### 路径处理改进
- ✅ 使用 `pathlib.Path` 替代 `os.path`
- ✅ 统一的路径规范化方法
- ✅ 自动处理不同操作系统的路径格式
- ✅ 移除手动的路径分隔符替换
#### 跨平台兼容性改进
- ✅ 统一的平台检测机制
- ✅ 动态的可执行文件查找
- ✅ 平台特定的配置统一管理
- ✅ 改进的错误处理和回退机制
#### 代码质量改进
- ✅ 减少代码重复
- ✅ 更好的类型提示
- ✅ 统一的异常处理
- ✅ 改进的文档和注释
## 具体优化案例
### 1. 路径连接优化
**优化前:**
```python
project_dir = os.path.join(path, title).replace('\\', '/')
full_path = os.path.normpath(os.path.join(project_dir, filename))
```
**优化后:**
```python
path_obj = PathUtils.normalize_path(path)
project_dir = path_obj / title
full_path = project_dir / filename
```
### 2. PyCharm路径查找优化
**优化前:**
```python
if system == "linux":
return [
"pycharm",
"pycharm.sh",
"/opt/pycharm*/bin/pycharm.sh",
"/usr/local/bin/pycharm",
"/usr/bin/pycharm",
"/home/tiger/下载/pycharm-2025.2.0.1/bin/pycharm.sh", # 硬编码路径
os.path.expanduser("~/.local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-*/bin/pycharm.sh")
]
```
**优化后:**
```python
else: # Linux
return [
Path("pycharm"),
Path("pycharm.sh"),
*Path("/opt").glob("pycharm*/bin/pycharm.sh"),
Path("/usr/local/bin/pycharm"),
Path("/usr/bin/pycharm"),
*home.glob(".local/share/JetBrains/Toolbox/apps/PyCharm-P/ch-*/bin/pycharm.sh")
]
```
### 3. 虚拟环境Python可执行文件查找优化
**优化前:**
```python
if os.name == 'nt': # Windows
python_executable = Path(venv_path) / 'Scripts' / 'python.exe'
else: # Unix-like systems
python_executable = Path(venv_path) / 'bin' / 'python'
```
**优化后:**
```python
python_executable = PlatformUtils.get_python_executable(venv_path_obj)
```
## 测试建议
### 1. 跨平台测试
- Windows 10/11
- macOS (Intel & Apple Silicon)
- Ubuntu/Debian Linux
- CentOS/RHEL Linux
### 2. 路径测试
- 包含中文字符的路径
- 包含空格的路径
- 超长路径
- 网络路径 (Windows UNC)
- 符号链接
### 3. 功能测试
- 项目创建和导入
- 文件管理器打开
- PyCharm集成
- 虚拟环境处理
## 后续优化建议
### 1. 配置文件优化
- 使用 `pathlib` 优化配置文件路径处理
- 统一配置文件格式和位置
### 2. 资源文件处理
- 优化图标和资源文件的路径处理
- 支持相对路径和绝对路径
### 3. 日志系统
- 添加路径相关的详细日志
- 改进错误报告机制
### 4. 单元测试
- 为路径处理工具类添加单元测试
- 添加跨平台兼容性测试
## 性能影响
### 正面影响
- ✅ **更少的路径转换操作**:减少字符串替换操作
- ✅ **更好的缓存利用**Path对象的内置缓存机制
- ✅ **减少重复代码**:统一的工具函数
### 注意事项
- ⚠️ **Path对象创建开销**:虽然很小,但比字符串操作略重
- ⚠️ **兼容性**确保所有Path对象在需要时正确转换为字符串
## 总结
本次优化显著改善了 MetaCore 项目的跨平台兼容性和代码质量:
1. **统一性**所有路径操作现在使用统一的API
2. **可靠性**减少了平台特定的bug和问题
3. **可维护性**:代码更清晰,更容易维护和扩展
4. **现代化**使用现代Python最佳实践
这些改进为项目的长期维护和跨平台部署奠定了坚实的基础。

80
Doc/README.md Normal file
View File

@ -0,0 +1,80 @@
# MetaCore 项目文档中心
欢迎来到MetaCore项目文档中心这里包含了项目的所有说明文档按类别整理便于查阅。
## 📚 文档分类
### 🚀 快速开始
- **[快速开始.md](快速开始.md)** - 新用户必读,快速上手指南
- **[安装PyQt5指南.md](安装PyQt5指南.md)** - PyQt5安装详细步骤
### 📖 详细说明
- **[README_PyQt5.md](README_PyQt5.md)** - PyQt5版本完整功能说明
- **[项目总览.md](项目总览.md)** - 整个项目的全面概述
- **[功能对比说明.md](功能对比说明.md)** - Web版本与PyQt5版本对比
### 🔧 环境配置
- **[虚拟环境完整指南.md](虚拟环境完整指南.md)** - 虚拟环境完整指南
## 🎯 推荐阅读顺序
### 新用户
1. [快速开始.md](快速开始.md) - 了解如何快速启动
2. [安装PyQt5指南.md](安装PyQt5指南.md) - 解决安装问题
3. [README_PyQt5.md](README_PyQt5.md) - 了解完整功能
### 开发者
1. [项目总览.md](项目总览.md) - 了解项目整体架构
2. [功能对比说明.md](功能对比说明.md) - 理解两个版本的差异
3. [虚拟环境完整指南.md](虚拟环境完整指南.md) - 配置开发环境
### 系统管理员
1. [虚拟环境完整指南.md](虚拟环境完整指南.md) - 环境部署
2. [安装PyQt5指南.md](安装PyQt5指南.md) - 依赖安装
3. [项目总览.md](项目总览.md) - 了解项目状态
## 🔍 快速查找
### 按问题类型查找
#### 安装问题
- PyQt5安装失败 → [安装PyQt5指南.md](安装PyQt5指南.md)
- 虚拟环境配置 → [虚拟环境完整指南.md](虚拟环境完整指南.md)
#### 使用问题
- 如何启动应用 → [快速开始.md](快速开始.md)
- 功能说明 → [README_PyQt5.md](README_PyQt5.md)
- 版本选择 → [功能对比说明.md](功能对比说明.md)
#### 开发问题
- 项目架构 → [项目总览.md](项目总览.md)
- 功能对比 → [功能对比说明.md](功能对比说明.md)
## 📱 文档更新
### 最新更新
- **2024年** - 完成PyQt5版本开发
- **最近** - 整理文档到Doc目录
### 维护说明
- 所有文档统一存放在Doc目录
- 按功能和用途分类
- 定期更新和维护
## 🎯 使用建议
### 查阅文档
1. **从README.md开始** - 本文档提供了完整的导航
2. **按需查阅** - 根据具体问题选择相应文档
3. **顺序阅读** - 新用户建议按推荐顺序阅读
### 贡献文档
1. **保持结构** - 新文档应放在Doc目录
2. **更新索引** - 添加新文档时更新本README
3. **统一格式** - 遵循现有文档的格式规范
---
💡 **提示:** 如果您是第一次使用MetaCore建议从 [快速开始.md](快速开始.md) 开始阅读!
🎉 **欢迎使用MetaCore项目管理平台**

210
Doc/README_PyQt5.md Normal file
View File

@ -0,0 +1,210 @@
# MetaCore - PyQt5版本
这是基于PyQt5重写的MetaCore项目管理平台完全复制了原始Web版本的界面和功能。
## 功能特性
### 🎯 主要功能
- ✅ **项目管理**:创建、导入、删除、重命名项目
- ✅ **项目卡片**:三段式布局(标题+菜单、图片+类型标签、时间)
- ✅ **收藏功能**:项目收藏/取消收藏
- ✅ **搜索过滤**:按名称搜索、按类型过滤
- ✅ **视图模式**:网格视图和列表视图
- ✅ **右键菜单**:完整的项目操作菜单
### 🎨 界面特性
- ✅ **深色主题**:现代化的深色界面设计
- ✅ **响应式布局**:自适应窗口大小
- ✅ **侧边栏导航**:可展开/收起的导航菜单
- ✅ **模态对话框**:创建项目和导入项目对话框
- ✅ **拖拽支持**:文件拖拽导入功能
## 安装和运行
### 1. 环境要求
- Python 3.7+
- PyQt5 5.15.0+
### 2. 安装依赖
```bash
pip install -r requirements.txt
```
### 3. 运行应用
```bash
python main.py
```
## 项目结构
```
MetaCore/
├── main.py # 主程序入口
├── requirements.txt # 依赖包列表
├── README_PyQt5.md # 说明文档
├── data/ # 数据模块
│ ├── __init__.py
│ ├── project_manager.py # 项目数据管理器
│ └── projects.json # 项目数据文件(自动生成)
└── ui/ # 界面模块
├── __init__.py
├── main_window.py # 主窗口
├── sidebar.py # 侧边栏组件
├── project_area.py # 项目显示区域
├── project_card.py # 项目卡片组件
├── create_project_dialog.py # 创建项目对话框
├── import_project_dialog.py # 导入项目对话框
└── styles.py # 样式表定义
```
## 主要组件说明
### 1. 主窗口 (MainWindow)
- 整体布局管理
- 菜单栏和状态栏
- 组件间信号连接
- 窗口事件处理
### 2. 侧边栏 (Sidebar)
- Logo区域
- 快速操作按钮
- 可展开的导航菜单
- 用户信息显示
### 3. 项目区域 (ProjectArea)
- 工具栏和搜索区域
- 网格/列表视图切换
- 项目卡片容器
- 空状态显示
### 4. 项目卡片 (ProjectCard)
- 三段式布局设计
- 悬停效果
- 右键菜单
- 收藏状态显示
### 5. 创建项目对话框 (CreateProjectDialog)
- 2:1布局比例
- 模板选择网格
- 项目信息表单
- 文件夹选择功能
### 6. 导入项目对话框 (ImportProjectDialog)
- 文件拖拽上传
- 导入选项配置
- 文件列表显示
- 进度反馈
## 数据管理
### 项目数据结构
```python
{
"id": 1,
"title": "项目名称",
"date": "2024-06-08 15:56:35",
"type": "industrial",
"image": "🏭",
"favorite": true,
"path": "/path/to/project"
}
```
### 支持的项目类型
- `industrial` - 工业项目 🏭
- `smart` - 智能项目 💧
- `vr` - VR项目 🥽
- `game` - 游戏项目 🎮
- `design` - 设计项目 🎨
- `empty` - 空白项目 📁
## 样式系统
### 主题色彩
- **主色调**:深灰色 (#1a1a1a, #2a2a2a)
- **边框色**:中灰色 (#3a3a3a, #4a4a4a)
- **强调色**:紫色 (#8b5cf6, #7c3aed)
- **文字色**:白色/灰色 (#ffffff, #cccccc, #888888)
### 组件样式
- 所有组件都有对应的ObjectName用于样式选择器
- 支持悬停状态和选中状态
- 统一的圆角和间距设计
- 平滑的过渡动画效果
## 信号和槽机制
### 主要信号
- `projects_changed` - 项目列表变化
- `project_added` - 项目添加
- `project_removed` - 项目删除
- `project_updated` - 项目更新
- `filter_changed` - 过滤条件变化
- `search_changed` - 搜索内容变化
### 事件处理
- 鼠标点击事件
- 键盘快捷键
- 拖拽事件
- 窗口事件
## 扩展功能
### 可以添加的功能
1. **项目模板系统**:真实的项目模板创建和应用
2. **文件管理**:项目内文件的管理和预览
3. **版本控制**Git集成和版本管理
4. **协作功能**:多用户协作和权限管理
5. **插件系统**:支持第三方插件扩展
6. **云同步**:项目数据云端同步
7. **导出功能**:项目打包和分享
### 性能优化
1. **虚拟滚动**:大量项目时的性能优化
2. **缓存机制**:图片和数据缓存
3. **异步加载**:大文件异步处理
4. **内存管理**:及时释放不用的资源
## 开发说明
### 添加新组件
1. 在`ui/`目录下创建新的组件文件
2. 继承适当的PyQt5基类
3. 实现`init_ui()`方法
4. 添加必要的信号定义
5. 在样式表中添加对应样式
### 修改样式
1. 在`ui/styles.py`中修改样式定义
2. 使用ObjectName作为选择器
3. 支持状态选择器(:hover, :checked等
4. 遵循现有的颜色和间距规范
### 数据持久化
- 项目数据自动保存到`data/projects.json`
- 应用关闭时自动保存
- 启动时自动加载历史数据
- 支持数据备份和恢复
## 与Web版本对比
### 相同功能
- ✅ 完全相同的界面布局
- ✅ 相同的项目管理功能
- ✅ 相同的视觉设计风格
- ✅ 相同的用户交互逻辑
### PyQt5版本优势
- ✅ 原生桌面应用体验
- ✅ 更好的性能表现
- ✅ 系统集成度更高
- ✅ 离线使用支持
- ✅ 文件系统直接访问
### 技术差异
- **Web版本**HTML + CSS + JavaScript
- **PyQt5版本**Python + PyQt5 + 自定义样式表
- **数据存储**JSON文件 vs 浏览器存储
- **文件操作**系统API vs Web API限制
这个PyQt5版本完全复制了Web版本的功能和外观同时提供了更好的桌面应用体验。

208
Doc/功能对比说明.md Normal file
View File

@ -0,0 +1,208 @@
# MetaCore Web版本 vs PyQt5版本功能对比
## 🎯 完整功能映射
### 1. 整体布局结构
| Web版本 | PyQt5版本 | 说明 |
|---------|-----------|------|
| `<div class="sidebar">` | `Sidebar(QWidget)` | 左侧导航栏 |
| `<div class="main-content">` | `ProjectArea(QWidget)` | 主内容区域 |
| CSS Grid布局 | QGridLayout | 项目卡片网格布局 |
| CSS Flexbox | QHBoxLayout/QVBoxLayout | 弹性布局 |
### 2. 侧边栏功能
| Web版本功能 | PyQt5实现 | 对应文件 |
|-------------|-----------|----------|
| Logo区域 | `create_logo_section()` | `ui/sidebar.py` |
| 创建项目按钮 | `QPushButton(" 创建新项目")` | `ui/sidebar.py` |
| 导入项目按钮 | `QPushButton("📤 导入项目")` | `ui/sidebar.py` |
| 导航菜单 | `create_navigation_menu()` | `ui/sidebar.py` |
| 可展开分组 | `create_nav_section()` | `ui/sidebar.py` |
| 用户信息 | `create_user_info()` | `ui/sidebar.py` |
### 3. 项目卡片功能
| Web版本 | PyQt5版本 | 实现细节 |
|---------|-----------|----------|
| 三段式布局 | `create_grid_layout()` | 头部+图片+底部 |
| 项目标题 | `QLabel(project.title)` | 支持文字省略 |
| 三点菜单 | `QPushButton("⋮")` | 右键菜单触发 |
| 项目图标 | `QLabel(project.image)` | Emoji图标显示 |
| 类型标签 | `QLabel(type_label)` | 紫色背景标签 |
| 收藏星星 | `QLabel("⭐")` | 条件显示 |
| 项目时间 | `QLabel(project.date)` | 底部居中显示 |
| 悬停效果 | `enterEvent/leaveEvent` | 边框高亮效果 |
### 4. 右键菜单功能
| Web版本菜单项 | PyQt5实现 | 功能说明 |
|---------------|-----------|----------|
| 📁 打开项目 | `open_action` | 项目打开功能 |
| ✏️ 重命名 | `rename_action` | 项目重命名 |
| 📋 复制项目 | `duplicate_action` | 项目复制 |
| 📤 导出项目 | `export_action` | 项目导出 |
| ⭐ 收藏/取消收藏 | `favorite_action` | 收藏状态切换 |
| 🗑️ 删除项目 | `delete_action` | 项目删除确认 |
### 5. 创建项目对话框
| Web版本元素 | PyQt5组件 | 布局比例 |
|-------------|-----------|----------|
| 模板选择区域 | `create_template_section()` | 2/3宽度 |
| 项目信息区域 | `create_project_info_section()` | 1/3宽度 |
| 模板网格 | `QGridLayout(2列)` | 2列模板布局 |
| 项目名称输入 | `QLineEdit` | 表单输入 |
| 项目描述输入 | `QTextEdit` | 多行文本 |
| 位置选择 | `QFileDialog.getExistingDirectory()` | 系统文件夹选择 |
| 浏览按钮 | `QPushButton("📁")` | 文件夹图标 |
### 6. 搜索和过滤功能
| Web版本 | PyQt5版本 | 实现方式 |
|---------|-----------|----------|
| 搜索框 | `QLineEdit` | 实时搜索 |
| 视图切换 | `QPushButton` (网格/列表) | 可选择按钮组 |
| 类型过滤 | `QComboBox` | 下拉选择 |
| 排序选项 | `QComboBox` | 排序方式选择 |
## 🎨 样式系统对比
### CSS vs PyQt5样式表
| Web版本CSS | PyQt5样式表 | 效果 |
|------------|-------------|------|
| `.project-card` | `#projectCard` | 项目卡片样式 |
| `.project-card:hover` | `#projectCard[hover="true"]` | 悬停效果 |
| `background: #2a2a2a` | `background-color: #2a2a2a` | 背景色 |
| `border-radius: 12px` | `border-radius: 12px` | 圆角 |
| `transition: all 0.2s` | 通过事件处理实现 | 过渡动画 |
### 颜色主题完全一致
| 颜色用途 | 颜色值 | Web版本 | PyQt5版本 |
|----------|--------|---------|-----------|
| 主背景 | #1a1a1a | ✅ | ✅ |
| 卡片背景 | #2a2a2a | ✅ | ✅ |
| 边框色 | #3a3a3a | ✅ | ✅ |
| 强调色 | #8b5cf6 | ✅ | ✅ |
| 文字色 | #ffffff | ✅ | ✅ |
## 🔧 技术实现对比
### 1. 数据管理
| 方面 | Web版本 | PyQt5版本 |
|------|---------|-----------|
| 数据存储 | JavaScript数组 | Python列表 + JSON文件 |
| 数据持久化 | localStorage | 文件系统 |
| 数据结构 | JavaScript对象 | Python类 |
| 状态管理 | 直接操作DOM | 信号槽机制 |
### 2. 事件处理
| 事件类型 | Web版本 | PyQt5版本 |
|----------|---------|-----------|
| 点击事件 | `addEventListener('click')` | `clicked.connect()` |
| 悬停事件 | CSS `:hover` | `enterEvent/leaveEvent` |
| 键盘事件 | `keydown/keyup` | `keyPressEvent` |
| 拖拽事件 | HTML5 Drag API | `dragEnterEvent/dropEvent` |
### 3. 布局系统
| 布局方式 | Web版本 | PyQt5版本 |
|----------|---------|-----------|
| 弹性布局 | CSS Flexbox | QHBoxLayout/QVBoxLayout |
| 网格布局 | CSS Grid | QGridLayout |
| 绝对定位 | CSS position | setGeometry() |
| 响应式 | CSS媒体查询 | 布局管理器自适应 |
## 🚀 功能增强
### PyQt5版本独有优势
1. **系统集成**
- 原生文件对话框
- 系统通知支持
- 任务栏集成
- 系统托盘支持
2. **性能优化**
- 原生渲染性能
- 内存管理更好
- 大量数据处理能力
- 多线程支持
3. **桌面特性**
- 快捷键支持
- 窗口管理
- 多显示器支持
- 离线使用
### 可扩展功能
1. **文件系统集成**
```python
# 直接操作文件系统
import os, shutil
def copy_project_files(src, dst):
shutil.copytree(src, dst)
```
2. **数据库支持**
```python
# 可以集成SQLite等数据库
import sqlite3
def save_to_database(project):
# 数据库操作
pass
```
3. **插件系统**
```python
# 动态加载插件
import importlib
def load_plugin(plugin_name):
return importlib.import_module(f'plugins.{plugin_name}')
```
## 📱 使用体验对比
### 启动和运行
| 方面 | Web版本 | PyQt5版本 |
|------|---------|-----------|
| 启动方式 | 浏览器打开HTML | 运行Python脚本 |
| 依赖环境 | 现代浏览器 | Python + PyQt5 |
| 安装过程 | 无需安装 | pip install PyQt5 |
| 更新方式 | 刷新页面 | 重新运行程序 |
### 用户交互
| 交互方式 | Web版本 | PyQt5版本 |
|----------|---------|-----------|
| 响应速度 | 依赖浏览器 | 原生应用速度 |
| 动画效果 | CSS动画 | Qt动画系统 |
| 拖拽操作 | HTML5 API | Qt拖拽系统 |
| 右键菜单 | 自定义实现 | 原生菜单 |
## 🎯 总结
PyQt5版本完全复制了Web版本的所有功能和视觉效果同时提供了更好的桌面应用体验
### ✅ 完全实现的功能
- 所有UI组件和布局
- 所有交互功能
- 完整的样式主题
- 数据管理和持久化
- 搜索和过滤功能
- 项目CRUD操作
### 🚀 额外优势
- 原生桌面应用性能
- 系统级文件操作
- 更好的用户体验
- 扩展性更强
这个PyQt5版本不仅是Web版本的完美移植更是一个功能更强大的桌面应用程序。

190
Doc/安装PyQt5指南.md Normal file
View File

@ -0,0 +1,190 @@
# PyQt5安装指南
## 🔧 Windows系统安装PyQt5
### 方法1使用pip安装推荐
#### 1. 检查Python是否已安装
```cmd
python --version
```
如果显示版本号说明Python已安装。如果提示命令不存在需要先安装Python。
#### 2. 安装Python如果未安装
1. 访问 https://www.python.org/downloads/
2. 下载最新版本的Python
3. 安装时勾选"Add Python to PATH"
#### 3. 安装PyQt5
```cmd
pip install PyQt5
```
#### 4. 验证安装
```cmd
python -c "import PyQt5; print('PyQt5安装成功')"
```
### 方法2使用conda安装
#### 1. 安装Anaconda或Miniconda
- 下载地址https://www.anaconda.com/products/distribution
#### 2. 安装PyQt5
```cmd
conda install pyqt
```
### 方法3离线安装
#### 1. 下载PyQt5安装包
访问 https://pypi.org/project/PyQt5/#files 下载对应的.whl文件
#### 2. 离线安装
```cmd
pip install PyQt5-5.15.7-cp39-cp39-win_amd64.whl
```
## 🚀 运行MetaCore应用
### 1. 确认PyQt5已安装
```cmd
python -c "from PyQt5.QtWidgets import QApplication; print('PyQt5可用')"
```
### 2. 运行应用
```cmd
cd MetaCore目录
python main.py
```
### 3. 如果遇到错误
#### 错误1ModuleNotFoundError: No module named 'PyQt5'
**解决方案:**
```cmd
pip install PyQt5
```
#### 错误2ImportError: DLL load failed
**解决方案:**
```cmd
pip uninstall PyQt5
pip install PyQt5
```
#### 错误3Python命令不存在
**解决方案:**
1. 重新安装Python并勾选"Add to PATH"
2. 或者使用完整路径:
```cmd
C:\Python39\python.exe main.py
```
## 📋 系统要求
### 最低要求
- Windows 7 SP1 或更高版本
- Python 3.6 或更高版本
- 2GB RAM
- 100MB 可用磁盘空间
### 推荐配置
- Windows 10 或更高版本
- Python 3.8 或更高版本
- 4GB RAM
- SSD硬盘
## 🔍 故障排除
### 1. 检查Python版本
```cmd
python --version
```
确保版本为3.6或更高。
### 2. 检查pip版本
```cmd
pip --version
```
如果pip不可用可以重新安装Python。
### 3. 更新pip
```cmd
python -m pip install --upgrade pip
```
### 4. 清理缓存
```cmd
pip cache purge
```
### 5. 使用国内镜像源(如果下载慢)
```cmd
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5
```
## 🎯 验证安装成功
### 运行测试脚本
创建一个测试文件 `test_pyqt5.py`
```python
import sys
from PyQt5.QtWidgets import QApplication, QLabel, QWidget
def test_pyqt5():
app = QApplication(sys.argv)
window = QWidget()
window.setWindowTitle('PyQt5测试')
window.setGeometry(100, 100, 300, 200)
label = QLabel('PyQt5安装成功', window)
label.move(100, 80)
window.show()
print("PyQt5测试窗口已显示关闭窗口退出测试")
sys.exit(app.exec_())
if __name__ == '__main__':
test_pyqt5()
```
运行测试:
```cmd
python test_pyqt5.py
```
如果出现一个窗口显示"PyQt5安装成功",说明安装正确。
## 📞 获取帮助
如果仍然遇到问题:
1. **检查Python环境**
```cmd
where python
python -m site
```
2. **重新安装Python**
- 卸载现有Python
- 重新下载安装,确保勾选"Add to PATH"
3. **使用虚拟环境**
```cmd
python -m venv metacore_env
metacore_env\Scripts\activate
pip install PyQt5
```
4. **联系技术支持**
- 提供错误信息截图
- 说明操作系统版本
- 提供Python版本信息
---
安装完成后就可以运行MetaCore PyQt5版本了🎉

209
Doc/快速开始.md Normal file
View File

@ -0,0 +1,209 @@
# MetaCore PyQt5版本 - 快速开始指南
## 🚀 一键启动
### 方法1直接运行
```bash
# 1. 安装依赖
pip install PyQt5
# 2. 运行应用
python main.py
```
### 方法2使用启动脚本
```bash
python run_app.py
```
## 📋 系统要求
- **Python版本**3.7 或更高
- **操作系统**Windows 10/11, macOS 10.14+, Linux
- **内存要求**:最少 512MB RAM
- **磁盘空间**:约 100MB
## 🔧 安装步骤
### Windows用户
```cmd
# 1. 检查Python版本
python --version
# 2. 安装PyQt5
pip install PyQt5
# 3. 运行应用
python main.py
```
### macOS用户
```bash
# 1. 确保有Python3
python3 --version
# 2. 安装PyQt5
pip3 install PyQt5
# 3. 运行应用
python3 main.py
```
### Linux用户
```bash
# Ubuntu/Debian
sudo apt-get install python3-pyqt5
# 或使用pip
pip3 install PyQt5
# 运行应用
python3 main.py
```
## 🎯 首次使用
### 1. 启动应用
运行后会看到MetaCore主界面
- 左侧:导航侧边栏
- 右侧:项目展示区域
- 底部:状态栏
### 2. 创建第一个项目
1. 点击侧边栏的" 创建新项目"按钮
2. 选择项目模板工业、VR、智能等
3. 填写项目名称和描述
4. 选择项目保存位置
5. 点击"创建项目"
### 3. 管理项目
- **查看项目**:点击项目卡片
- **右键菜单**:右键点击项目卡片或点击"⋮"按钮
- **搜索项目**:使用顶部搜索框
- **切换视图**:点击网格/列表视图按钮
## 📁 文件结构说明
```
MetaCore/
├── main.py # 🚀 主程序入口
├── run_app.py # 🎯 启动脚本
├── requirements.txt # 📦 依赖列表
├── data/ # 💾 数据目录
│ ├── project_manager.py # 项目管理器
│ └── projects.json # 项目数据(自动生成)
└── ui/ # 🎨 界面组件
├── main_window.py # 主窗口
├── sidebar.py # 侧边栏
├── project_area.py # 项目区域
├── project_card.py # 项目卡片
├── create_project_dialog.py # 创建项目对话框
├── import_project_dialog.py # 导入项目对话框
└── styles.py # 样式表
```
## 🎨 界面预览
### 主界面布局
```
┌─────────────────────────────────────────────────────────┐
│ MetaCore - 项目管理平台 🔔 👤 ➕创建 │
├─────────────┬───────────────────────────────────────────┤
│ 🧊 MetaCore │ 全部项目 ⊞ ☰ 🔽 🔍 │
│ ├───────────────────────────────────────────┤
创建新项目│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ 📤 导入项目 │ │ 🏭 │ │ 💧 │ │ 🏗️ │ │ 📊 │ │
│ │ │智慧工厂│ │智慧水务│ │数字工厂│ │智慧监控│ │
│ 📁 项目概览 │ │ ⭐⋮ │ │ ⋮ │ │ ⋮ │ │ ⭐⋮ │ │
│ ⭐ 收藏项目 │ └─────┘ └─────┘ └─────┘ └─────┘ │
│ 🕒 最近项目 │ │
│ 🏭 工业项目 │ │
│ 💧 智能项目 │ │
│ │ │
│ 👤 Admin ▼ │ │
└─────────────┴───────────────────────────────────────────┤
│ 项目总数: 5 当前用户: Admin │
└─────────────────────────────────────────────────────────┘
```
### 创建项目对话框
```
┌─────────────────────────────────────────────────────────┐
│ 创建新的项目 ✕ │
├─────────────────────────────────────────────────────────┤
│ 选择项目模板 │ 项目信息 │
│ │ │
│ ┌─────┐ ┌─────┐ │ 选择一个项目模板来快速 │
│ │ 📁 │ │ 🏭 │ │ 开始,或者创建一个空白 │
│ │空白项目│ │工业项目│ │ 项目来从头开始。 │
│ └─────┘ └─────┘ │ │
│ ┌─────┐ ┌─────┐ │ 项目名称 │
│ │ 🥽 │ │ 💧 │ │ ┌─────────────────┐ │
│ │VR项目│ │智能项目│ │ │ │ │
│ └─────┘ └─────┘ │ └─────────────────┘ │
│ ┌─────┐ ┌─────┐ │ │
│ │ 🎮 │ │ 🎨 │ │ 项目描述 │
│ │游戏项目│ │设计项目│ │ ┌─────────────────┐ │
│ └─────┘ └─────┘ │ │ │ │
│ │ └─────────────────┘ │
│ │ │
│ │ 项目位置 │
│ │ ┌───────────────┐ 📁 │
│ │ │ │ │
│ │ └───────────────┘ │
├─────────────────────────────────────────────────────────┤
│ 取消 创建项目 │
└─────────────────────────────────────────────────────────┘
```
## ⚡ 快捷键
| 功能 | 快捷键 | 说明 |
|------|--------|------|
| 新建项目 | Ctrl+N | 打开创建项目对话框 |
| 导入项目 | Ctrl+I | 打开导入项目对话框 |
| 搜索项目 | Ctrl+F | 聚焦搜索框 |
| 退出应用 | Ctrl+Q | 关闭应用程序 |
## 🔧 常见问题
### Q: 提示"No module named 'PyQt5'"
**A:** 需要安装PyQt5依赖包
```bash
pip install PyQt5
```
### Q: 在macOS上运行出错
**A:** 可能需要使用python3命令
```bash
python3 main.py
```
### Q: 项目数据保存在哪里?
**A:** 项目数据保存在`data/projects.json`文件中,应用关闭时自动保存。
### Q: 如何备份项目数据?
**A:** 复制`data/projects.json`文件即可备份所有项目信息。
### Q: 可以修改界面主题吗?
**A:** 可以在`ui/styles.py`文件中修改颜色和样式定义。
## 🎯 下一步
1. **探索功能**:尝试创建不同类型的项目
2. **自定义设置**:根据需要调整界面和功能
3. **数据管理**:定期备份项目数据
4. **功能扩展**:根据需要添加新功能
## 📞 技术支持
如果遇到问题,可以:
1. 查看`README_PyQt5.md`详细文档
2. 检查`功能对比说明.md`了解功能对应关系
3. 查看源代码中的注释和文档字符串
---
🎉 **恭喜!** 您已经成功运行了MetaCore PyQt5版本
这个桌面应用完全复制了Web版本的所有功能同时提供了更好的性能和用户体验。开始创建您的第一个项目吧

View File

@ -0,0 +1,261 @@
# MetaCore虚拟环境完整指南
## 🎯 概述
为MetaCore PyQt5版本创建独立的Python虚拟环境确保项目依赖不会与系统其他Python项目冲突。
## 📁 已创建的文件
### 自动化脚本
- `setup_and_run.bat` - Windows一键启动脚本
- `setup_and_run.sh` - macOS/Linux一键启动脚本
- `test_environment.py` - 环境测试脚本
### 配置文件
- `requirements.txt` - 项目依赖列表
- `虚拟环境设置指南.md` - 详细设置说明
- `虚拟环境快速参考.md` - 快速参考卡
## 🚀 快速开始
### 方法1一键启动推荐
#### Windows用户
```cmd
# 双击运行或命令行执行
setup_and_run.bat
```
#### macOS/Linux用户
```bash
# 首次运行需要给权限
chmod +x setup_and_run.sh
# 运行脚本
./setup_and_run.sh
```
### 方法2手动设置
#### 1. 创建虚拟环境
```cmd
# Windows
python -m venv metacore_env
# macOS/Linux
python3 -m venv metacore_env
```
#### 2. 激活虚拟环境
```cmd
# Windows
metacore_env\Scripts\activate
# macOS/Linux
source metacore_env/bin/activate
```
#### 3. 安装依赖
```cmd
pip install -r requirements.txt
```
#### 4. 运行应用
```cmd
python main.py
```
#### 5. 退出虚拟环境
```cmd
deactivate
```
## 🔧 环境测试
运行环境测试脚本检查配置:
```cmd
python test_environment.py
```
测试内容包括:
- ✅ Python版本检查
- ✅ PyQt5安装验证
- ✅ 项目文件完整性
- ✅ 模块导入测试
- ✅ 虚拟环境状态
## 📋 依赖包说明
### 必需依赖
- **PyQt5 >= 5.15.0** - GUI框架
### 可选依赖
- **Pillow >= 8.0.0** - 图像处理(如需要更好的图标支持)
- **psutil >= 5.8.0** - 系统信息(如需要系统集成功能)
## 🎯 使用场景
### 开发环境
```cmd
# 激活环境
metacore_env\Scripts\activate
# 开发调试
python main.py
# 安装新依赖
pip install package_name
# 更新依赖列表
pip freeze > requirements.txt
# 退出环境
deactivate
```
### 生产环境
```cmd
# 创建干净环境
python -m venv production_env
# 激活环境
production_env\Scripts\activate
# 安装指定依赖
pip install -r requirements.txt
# 运行应用
python main.py
```
## 🔍 故障排除
### 常见问题及解决方案
#### 1. Python命令不存在
**症状:** `'python' 不是内部或外部命令`
**解决:**
- 重新安装Python并勾选"Add to PATH"
- 或使用完整路径:`C:\Python39\python.exe`
#### 2. venv模块不存在
**症状:** `No module named venv`
**解决:**
```cmd
pip install virtualenv
virtualenv metacore_env
```
#### 3. PyQt5安装失败
**症状:** 网络错误或编译错误
**解决:**
```cmd
# 使用国内镜像
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5
# 或使用conda
conda install pyqt
```
#### 4. 权限错误
**症状:** `Permission denied`
**解决:**
- Windows以管理员身份运行
- macOS/Linux检查目录权限 `chmod 755 /path/to/MetaCore`
#### 5. 虚拟环境激活失败
**症状:** 激活脚本不存在
**解决:**
```cmd
# 删除并重新创建
rm -rf metacore_env
python -m venv metacore_env
```
## 📊 环境管理最佳实践
### 1. 项目隔离
- 每个项目使用独立的虚拟环境
- 避免在系统Python中安装项目依赖
### 2. 依赖管理
- 使用requirements.txt记录依赖
- 定期更新依赖包版本
- 区分开发依赖和生产依赖
### 3. 版本控制
- 将虚拟环境目录添加到.gitignore
- 只提交requirements.txt文件
- 在不同环境中重新创建虚拟环境
### 4. 文档维护
- 记录环境创建步骤
- 说明特殊依赖的安装方法
- 提供故障排除指南
## 🎨 目录结构
完整的项目目录结构:
```
MetaCore/
├── metacore_env/ # 虚拟环境(不提交到版本控制)
│ ├── Scripts/ # Windows
│ ├── bin/ # macOS/Linux
│ ├── lib/
│ └── pyvenv.cfg
├── data/ # 数据模块
├── ui/ # 界面模块
├── main.py # 主程序
├── requirements.txt # 依赖列表
├── setup_and_run.bat # Windows启动脚本
├── setup_and_run.sh # macOS/Linux启动脚本
├── test_environment.py # 环境测试脚本
├── 虚拟环境设置指南.md # 详细指南
├── 虚拟环境快速参考.md # 快速参考
└── 虚拟环境完整指南.md # 本文档
```
## 🚀 部署建议
### 开发部署
1. 克隆项目代码
2. 创建虚拟环境
3. 安装依赖包
4. 运行测试脚本
5. 启动应用
### 生产部署
1. 使用干净的Python环境
2. 创建专用虚拟环境
3. 安装精确版本的依赖
4. 配置系统服务
5. 设置日志和监控
## 📞 获取帮助
### 自助诊断
1. 运行 `python test_environment.py` 检查环境
2. 查看 `虚拟环境快速参考.md` 获取常用命令
3. 参考 `虚拟环境设置指南.md` 获取详细说明
### 常用检查命令
```cmd
# 检查Python版本
python --version
# 检查虚拟环境状态
echo $VIRTUAL_ENV # Linux/macOS
echo %VIRTUAL_ENV% # Windows
# 检查已安装包
pip list
# 检查PyQt5
python -c "import PyQt5; print('PyQt5可用')"
```
---
🎉 **虚拟环境配置完成!**
现在您可以在独立的环境中安全地运行MetaCore PyQt5版本不用担心依赖冲突问题。选择最适合您的启动方式开始使用吧

234
Doc/项目总览.md Normal file
View File

@ -0,0 +1,234 @@
# MetaCore 项目总览
## 🎯 项目简介
MetaCore是一个现代化的项目管理平台现在提供两个版本
- **Web版本**基于HTML/CSS/JavaScript的浏览器应用
- **PyQt5版本**基于Python PyQt5的桌面应用
两个版本功能完全一致,界面设计完全相同,为用户提供了不同平台的选择。
## 📁 完整项目结构
```
MetaCore/
├── 📄 Web版本文件
│ ├── index.html # 主页面
│ ├── script.js # JavaScript逻辑
│ ├── styles.css # 样式表
│ └── test-cards.html # 测试页面
├── 🐍 PyQt5版本文件
│ ├── main.py # 主程序入口
│ ├── run_app.py # 启动脚本
│ ├── requirements.txt # 依赖包
│ ├── data/ # 数据模块
│ │ ├── __init__.py
│ │ ├── project_manager.py # 项目管理器
│ │ └── projects.json # 数据文件(自动生成)
│ └── ui/ # 界面模块
│ ├── __init__.py
│ ├── main_window.py # 主窗口
│ ├── sidebar.py # 侧边栏
│ ├── project_area.py # 项目区域
│ ├── project_card.py # 项目卡片
│ ├── create_project_dialog.py # 创建对话框
│ ├── import_project_dialog.py # 导入对话框
│ └── styles.py # 样式定义
└── 📚 文档文件
├── README_PyQt5.md # PyQt5版本说明
├── 快速开始.md # 快速开始指南
├── 安装PyQt5指南.md # 安装指南
├── 功能对比说明.md # 版本对比
├── PyQt5版本完成总结.md # 完成总结
├── 创建项目1-3布局说明.md # 布局优化说明
├── 创建项目布局优化说明.md # 布局说明
├── 项目卡片更新说明.md # 卡片更新说明
├── 功能演示.md # 功能演示
└── 项目总览.md # 本文档
```
## 🚀 快速开始
### Web版本
```bash
# 直接在浏览器中打开
open index.html
```
### PyQt5版本
```bash
# 1. 安装依赖
pip install PyQt5
# 2. 运行应用
python main.py
```
## ✨ 核心功能
### 🎨 界面特性
- ✅ **现代化设计**:深色主题,简洁美观
- ✅ **响应式布局**:自适应不同屏幕尺寸
- ✅ **三段式卡片**:标题+图片+时间的经典布局
- ✅ **2:1对话框**:创建项目的黄金比例布局
- ✅ **悬停效果**:丰富的交互反馈
### 📊 项目管理
- ✅ **项目创建**:多种模板选择
- ✅ **项目导入**:支持文件拖拽
- ✅ **项目编辑**:重命名、描述修改
- ✅ **项目删除**:安全删除确认
- ✅ **收藏功能**:快速标记重要项目
### 🔍 搜索过滤
- ✅ **实时搜索**:按项目名称搜索
- ✅ **类型过滤**:按项目类型筛选
- ✅ **收藏过滤**:查看收藏的项目
- ✅ **时间排序**:按创建时间排序
### 👁️ 视图模式
- ✅ **网格视图**:卡片式展示
- ✅ **列表视图**:紧凑式展示
- ✅ **视图切换**:一键切换显示模式
## 🎯 版本对比
| 特性 | Web版本 | PyQt5版本 |
|------|---------|-----------|
| 运行环境 | 浏览器 | 桌面应用 |
| 安装要求 | 无 | Python + PyQt5 |
| 性能表现 | 依赖浏览器 | 原生性能 |
| 文件操作 | 受限 | 完全访问 |
| 离线使用 | 支持 | 完全支持 |
| 系统集成 | 有限 | 完全集成 |
| 更新方式 | 刷新页面 | 重启应用 |
## 🛠️ 技术栈
### Web版本
- **前端**HTML5 + CSS3 + JavaScript ES6
- **样式**CSS Grid + Flexbox
- **图标**Font Awesome + Emoji
- **存储**localStorage
### PyQt5版本
- **框架**Python 3.7+ + PyQt5
- **架构**MVC模式 + 信号槽机制
- **界面**Qt样式表 + 自定义组件
- **存储**JSON文件
## 📈 开发历程
### 第一阶段Web版本开发
1. ✅ 基础界面搭建
2. ✅ 项目卡片设计
3. ✅ 侧边栏导航
4. ✅ 创建项目功能
5. ✅ 搜索过滤功能
### 第二阶段:界面优化
1. ✅ 三段式卡片布局
2. ✅ 1/3布局对话框
3. ✅ 悬停效果优化
4. ✅ 响应式设计
5. ✅ 文件选择集成
### 第三阶段PyQt5移植
1. ✅ 架构设计
2. ✅ 组件开发
3. ✅ 样式移植
4. ✅ 功能实现
5. ✅ 测试优化
## 🎨 设计亮点
### 1. 三段式项目卡片
```
┌─────────────────┐
│ 标题 ⋮ │ ← 头部:项目名称 + 菜单
├─────────────────┤
│ 🏭 │ ← 中部:项目图标 + 类型
│ 工业项目 │
├─────────────────┤
│ 2024-06-08 15:56│ ← 底部:创建时间
└─────────────────┘
```
### 2. 2:1创建对话框
```
┌─────────────────────────────────────┐
│ 创建新的项目 ✕ │
├─────────────────────────────────────┤
│ 模板选择 (2/3) │ 项目信息 (1/3) │
│ ┌─────┐ ┌─────┐ │ 项目名称 │
│ │ 📁 │ │ 🏭 │ │ ┌─────────────┐ │
│ │空白 │ │工业 │ │ │ │ │
│ └─────┘ └─────┘ │ └─────────────┘ │
│ ┌─────┐ ┌─────┐ │ 项目描述 │
│ │ 🥽 │ │ 💧 │ │ ┌─────────────┐ │
│ │VR │ │智能 │ │ │ │ │
│ └─────┘ └─────┘ │ └─────────────┘ │
└─────────────────────────────────────┘
```
### 3. 深色主题配色
- **主背景**#1a1a1a深黑
- **卡片背景**#2a2a2a深灰
- **边框色**#3a3a3a中灰
- **强调色**#8b5cf6紫色
- **文字色**#ffffff白色
## 🔮 未来规划
### 短期目标
- [ ] 添加项目模板管理
- [ ] 实现真实的文件操作
- [ ] 添加项目统计功能
- [ ] 支持主题切换
### 中期目标
- [ ] 集成版本控制系统
- [ ] 添加协作功能
- [ ] 实现云同步
- [ ] 开发移动端版本
### 长期目标
- [ ] 构建插件生态
- [ ] 企业级功能
- [ ] AI辅助功能
- [ ] 跨平台统一
## 📞 技术支持
### 文档资源
- 📖 **详细说明**README_PyQt5.md
- 🚀 **快速开始**:快速开始.md
- 🔧 **安装指南**安装PyQt5指南.md
- 📊 **功能对比**:功能对比说明.md
### 常见问题
1. **PyQt5安装问题**参考安装PyQt5指南.md
2. **功能使用问题**:参考快速开始.md
3. **版本选择问题**:参考功能对比说明.md
## 🏆 项目成就
### ✅ 完成的里程碑
1. **完整功能实现**100%复制Web版本功能
2. **视觉效果还原**:像素级还原界面设计
3. **性能优化**:提供更好的桌面体验
4. **文档完善**:提供完整的使用文档
### 🎯 技术价值
- 展示了Web到桌面的完整转换过程
- 提供了PyQt5开发的最佳实践
- 建立了可复用的组件架构
- 创建了完整的文档体系
---
🎉 **MetaCore项目现在提供了Web和桌面两种完整的解决方案**
无论您喜欢在浏览器中使用还是作为桌面应用运行,都能获得完全相同的功能和体验。选择最适合您的版本,开始管理您的项目吧!

39
MetaCore.spec Normal file
View File

@ -0,0 +1,39 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['MetaCore\\main.py'],
pathex=['.'],
binaries=[],
datas=[('MetaCore/Resources', 'MetaCore/Resources'), ('data', 'data')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='MetaCore',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=False,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['MetaCore\\Resources\\Icons\\app_icon.png'],
)

5
MetaCore/.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

12
MetaCore/.idea/MetaCore.iml generated Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

8
MetaCore/.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/MetaCore.iml" filepath="$PROJECT_DIR$/.idea/MetaCore.iml" />
</modules>
</component>
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

210
MetaCore/README.md Normal file
View File

@ -0,0 +1,210 @@
# MetaCore - PyQt5版本
这是基于PyQt5重写的MetaCore项目管理平台完全复制了原始Web版本的界面和功能。
## 功能特性
### 🎯 主要功能
- ✅ **项目管理**:创建、导入、删除、重命名项目
- ✅ **项目卡片**:三段式布局(标题+菜单、图片+类型标签、时间)
- ✅ **收藏功能**:项目收藏/取消收藏
- ✅ **搜索过滤**:按名称搜索、按类型过滤
- ✅ **视图模式**:网格视图和列表视图
- ✅ **右键菜单**:完整的项目操作菜单
### 🎨 界面特性
- ✅ **深色主题**:现代化的深色界面设计
- ✅ **响应式布局**:自适应窗口大小
- ✅ **侧边栏导航**:可展开/收起的导航菜单
- ✅ **模态对话框**:创建项目和导入项目对话框
- ✅ **拖拽支持**:文件拖拽导入功能
## 安装和运行
### 1. 环境要求
- Python 3.7+
- PyQt5 5.15.0+
### 2. 安装依赖
```bash
pip install -r requirements.txt
```
### 3. 运行应用
```bash
python main.py
```
## 项目结构
```
MetaCore/
├── main.py # 主程序入口
├── requirements.txt # 依赖包列表
├── README_PyQt5.md # 说明文档
├── data/ # 数据模块
│ ├── __init__.py
│ ├── project_manager.py # 项目数据管理器
│ └── projects.json # 项目数据文件(自动生成)
└── ui/ # 界面模块
├── __init__.py
├── main_window.py # 主窗口
├── sidebar.py # 侧边栏组件
├── project_area.py # 项目显示区域
├── project_card.py # 项目卡片组件
├── create_project_dialog.py # 创建项目对话框
├── import_project_dialog.py # 导入项目对话框
└── styles.py # 样式表定义
```
## 主要组件说明
### 1. 主窗口 (MainWindow)
- 整体布局管理
- 菜单栏和状态栏
- 组件间信号连接
- 窗口事件处理
### 2. 侧边栏 (Sidebar)
- Logo区域
- 快速操作按钮
- 可展开的导航菜单
- 用户信息显示
### 3. 项目区域 (ProjectArea)
- 工具栏和搜索区域
- 网格/列表视图切换
- 项目卡片容器
- 空状态显示
### 4. 项目卡片 (ProjectCard)
- 三段式布局设计
- 悬停效果
- 右键菜单
- 收藏状态显示
### 5. 创建项目对话框 (CreateProjectDialog)
- 2:1布局比例
- 模板选择网格
- 项目信息表单
- 文件夹选择功能
### 6. 导入项目对话框 (ImportProjectDialog)
- 文件拖拽上传
- 导入选项配置
- 文件列表显示
- 进度反馈
## 数据管理
### 项目数据结构
```python
{
"id": 1,
"title": "项目名称",
"date": "2024-06-08 15:56:35",
"type": "industrial",
"image": "🏭",
"favorite": true,
"path": "/path/to/project"
}
```
### 支持的项目类型
- `industrial` - 工业项目 🏭
- `smart` - 智能项目 💧
- `vr` - VR项目 🥽
- `game` - 游戏项目 🎮
- `design` - 设计项目 🎨
- `empty` - 空白项目 📁
## 样式系统
### 主题色彩
- **主色调**:深灰色 (#1a1a1a, #2a2a2a)
- **边框色**:中灰色 (#3a3a3a, #4a4a4a)
- **强调色**:紫色 (#8b5cf6, #7c3aed)
- **文字色**:白色/灰色 (#ffffff, #cccccc, #888888)
### 组件样式
- 所有组件都有对应的ObjectName用于样式选择器
- 支持悬停状态和选中状态
- 统一的圆角和间距设计
- 平滑的过渡动画效果
## 信号和槽机制
### 主要信号
- `projects_changed` - 项目列表变化
- `project_added` - 项目添加
- `project_removed` - 项目删除
- `project_updated` - 项目更新
- `filter_changed` - 过滤条件变化
- `search_changed` - 搜索内容变化
### 事件处理
- 鼠标点击事件
- 键盘快捷键
- 拖拽事件
- 窗口事件
## 扩展功能
### 可以添加的功能
1. **项目模板系统**:真实的项目模板创建和应用
2. **文件管理**:项目内文件的管理和预览
3. **版本控制**Git集成和版本管理
4. **协作功能**:多用户协作和权限管理
5. **插件系统**:支持第三方插件扩展
6. **云同步**:项目数据云端同步
7. **导出功能**:项目打包和分享
### 性能优化
1. **虚拟滚动**:大量项目时的性能优化
2. **缓存机制**:图片和数据缓存
3. **异步加载**:大文件异步处理
4. **内存管理**:及时释放不用的资源
## 开发说明
### 添加新组件
1. 在`ui/`目录下创建新的组件文件
2. 继承适当的PyQt5基类
3. 实现`init_ui()`方法
4. 添加必要的信号定义
5. 在样式表中添加对应样式
### 修改样式
1. 在`ui/styles.py`中修改样式定义
2. 使用ObjectName作为选择器
3. 支持状态选择器(:hover, :checked等
4. 遵循现有的颜色和间距规范
### 数据持久化
- 项目数据自动保存到`data/projects.json`
- 应用关闭时自动保存
- 启动时自动加载历史数据
- 支持数据备份和恢复
## 与Web版本对比
### 相同功能
- ✅ 完全相同的界面布局
- ✅ 相同的项目管理功能
- ✅ 相同的视觉设计风格
- ✅ 相同的用户交互逻辑
### PyQt5版本优势
- ✅ 原生桌面应用体验
- ✅ 更好的性能表现
- ✅ 系统集成度更高
- ✅ 离线使用支持
- ✅ 文件系统直接访问
### 技术差异
- **Web版本**HTML + CSS + JavaScript
- **PyQt5版本**Python + PyQt5 + 自定义样式表
- **数据存储**JSON文件 vs 浏览器存储
- **文件操作**系统API vs Web API限制
这个PyQt5版本完全复制了Web版本的功能和外观同时提供了更好的桌面应用体验。

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1 @@
# 数据模块

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,13 @@
[
{
"id": 1,
"title": "XNWX",
"date": "2025-09-28 10:48:15",
"type": "imported",
"image": "C:\\Users\\29381\\Desktop\\XNWX\\XNWX.png",
"path": "C:\\Users\\29381\\Desktop",
"project_dir": "C:\\Users\\29381\\Desktop\\XNWX",
"description": "从文件夹 XNWX 导入",
"status": "normal"
}
]

67
MetaCore/main.py Normal file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MetaCore - 项目管理平台 (PyQt5版本)
"""
import sys
import json
import os
from datetime import datetime
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
# 导入自定义组件
from MetaCore.ui.main_window import MainWindow
from MetaCore.ui.styles import StyleSheet
from MetaCore.data.project_manager import ProjectManager
class MetaCoreApp(QApplication):
"""MetaCore应用程序主类"""
def __init__(self, argv):
super().__init__(argv)
# 设置应用程序信息
self.setApplicationName("MetaCore")
self.setApplicationVersion("1.0.0")
self.setOrganizationName("MetaCore Team")
# 设置应用程序图标(如果图标文件存在)
icon_path = "resources/icons/app_icon.png"
if os.path.exists(icon_path):
self.setWindowIcon(QIcon(icon_path))
# 初始化数据管理器
self.project_manager = ProjectManager()
# 创建主窗口
self.main_window = MainWindow(self.project_manager)
# 应用样式表
self.setStyleSheet(StyleSheet.get_main_style())
# 显示主窗口
self.main_window.show()
def closeEvent(self, event):
"""应用程序关闭事件"""
# 保存项目数据
self.project_manager.save_projects()
event.accept()
def main():
"""主函数"""
app = MetaCoreApp(sys.argv)
# 设置高DPI支持
app.setAttribute(Qt.AA_EnableHighDpiScaling, True)
app.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
# 运行应用程序
sys.exit(app.exec_())
if __name__ == "__main__":
main()

24
MetaCore/requirements.txt Normal file
View File

@ -0,0 +1,24 @@
# MetaCore PyQt5版本依赖包
# ================================
# 必需依赖 - 核心GUI框架
PyQt5>=5.15.0
# 必需依赖 - 打包工具(用于构建可执行文件)
PyInstaller>=5.0.0
# 推荐依赖 - 图像处理(更好的图标和图片支持)
Pillow>=8.0.0
# 可选依赖 - 系统信息(系统集成功能)
psutil>=5.8.0
# 开发依赖 - 类型检查(开发时使用)
# typing-extensions>=4.0.0 # Python 3.7兼容性
# 注意以下是Python标准库无需安装
# - sys, os, json, datetime (系统和文件操作)
# - pathlib (路径处理)
# - subprocess (进程管理)
# - platform (平台信息)
# - typing (类型提示)

View File

@ -0,0 +1,47 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
示例脚本 - 演示如何编写脚本
"""
from core.script_system import ScriptBase
class ExampleScript(ScriptBase):
"""示例脚本类"""
def __init__(self):
super().__init__()
self.counter = 0
self.rotation_speed = 30.0 # 度/秒
def start(self):
"""脚本开始时调用"""
self.log("示例脚本开始运行!")
self.log(f"挂载到对象: {self.gameObject.getName()}")
def update(self, dt):
"""每帧更新"""
self.counter += 1
# 每60帧输出一次信息
if self.counter % 60 == 0:
self.log(f"运行了 {self.counter}")
# 让对象旋转
if self.transform:
current_h = self.transform.getH()
new_h = current_h + self.rotation_speed * dt
self.transform.setH(new_h)
def on_destroy(self):
"""脚本销毁时调用"""
self.log("示例脚本被销毁")
def on_enable(self):
"""脚本启用时调用"""
self.log("示例脚本被启用")
def on_disable(self):
"""脚本禁用时调用"""
self.log("示例脚本被禁用")

225
MetaCore/test_open.py Normal file
View File

@ -0,0 +1,225 @@
import subprocess
import os
import sys
from pathlib import Path
def run_cmd_command(command, cwd=None, shell=True, timeout=30):
"""
执行CMD命令的通用方法
Args:
command (str or list): 要执行的命令
cwd (str, optional): 工作目录
shell (bool): 是否使用shell执行命令
timeout (int): 超时时间
Returns:
tuple: (return_code, stdout, stderr)
"""
try:
# 执行命令
result = subprocess.run(
command,
cwd=cwd,
shell=shell,
capture_output=True,
text=True,
timeout=timeout,
encoding='utf-8'
)
return result.returncode, result.stdout, result.stderr
except subprocess.TimeoutExpired:
return -1, "", "命令执行超时"
except Exception as e:
return -2, "", f"执行命令时出错: {str(e)}"
def run_cmd_with_venv(venv_path, command, cwd=None, timeout=30):
"""
在指定虚拟环境中执行CMD命令
Args:
venv_path (str): 虚拟环境路径
command (str): 要执行的命令
cwd (str, optional): 工作目录
timeout (int): 超时时间
Returns:
tuple: (return_code, stdout, stderr)
"""
try:
# 激活虚拟环境并执行命令
if os.name == 'nt': # Windows
activate_script = Path(venv_path) / 'Scripts' / 'activate.bat'
full_command = f'"{activate_script}" && {command}'
else: # Unix-like systems
activate_script = Path(venv_path) / 'bin' / 'activate'
full_command = f'source "{activate_script}" && {command}'
return run_cmd_command(full_command, cwd=cwd, timeout=timeout)
except Exception as e:
return -2, "", f"在虚拟环境中执行命令时出错: {str(e)}"
def run_python_in_venv(venv_path, script_path, args=None, cwd=None, timeout=30):
"""
在指定虚拟环境中运行Python脚本
Args:
venv_path (str): 虚拟环境路径
script_path (str): Python脚本路径
args (list, optional): 脚本参数
cwd (str, optional): 工作目录
timeout (int): 超时时间
Returns:
tuple: (return_code, stdout, stderr)
"""
try:
# 获取虚拟环境中的Python解释器
if os.name == 'nt': # Windows
python_executable = Path(venv_path) / 'Scripts' / 'python.exe'
else: # Unix-like systems
python_executable = Path(venv_path) / 'bin' / 'python'
# 构建命令
cmd = [str(python_executable), str(script_path)]
if args:
cmd.extend(args)
# 设置环境变量
env = os.environ.copy()
env['VIRTUAL_ENV'] = str(venv_path)
if os.name == 'nt': # Windows
env['PATH'] = str(Path(venv_path) / 'Scripts') + os.pathsep + env['PATH']
else: # Unix-like
env['PATH'] = str(Path(venv_path) / 'bin') + os.pathsep + env['PATH']
# 执行命令
result = subprocess.run(
cmd,
cwd=cwd,
capture_output=True,
text=True,
timeout=timeout,
encoding='utf-8',
env=env
)
return result.returncode, result.stdout, result.stderr
except subprocess.TimeoutExpired:
return -1, "", "命令执行超时"
except Exception as e:
return -2, "", f"在虚拟环境中运行Python脚本时出错: {str(e)}"
def execute_commands_sequentially(commands, cwd=None, timeout=30):
"""
顺序执行多个命令
Args:
commands (list): 命令列表
cwd (str, optional): 工作目录
timeout (int): 超时时间
Returns:
list: 每个命令的执行结果列表
"""
results = []
for i, command in enumerate(commands):
print(f"执行命令 {i + 1}/{len(commands)}: {command}")
return_code, stdout, stderr = run_cmd_command(command, cwd=cwd, timeout=timeout)
results.append({
'command': command,
'return_code': return_code,
'stdout': stdout,
'stderr': stderr
})
# 如果命令执行失败,停止执行后续命令
if return_code != 0:
print(f"命令执行失败,停止执行后续命令: {command}")
break
return results
def run_text():
# 示例1: 执行简单命令
print("=== 示例1: 执行简单命令 ===")
return_code, stdout, stderr = run_cmd_command("dir" if os.name == 'nt' else "ls -la")
print(f"返回码: {return_code}")
print(f"输出: {stdout}")
if stderr:
print(f"错误: {stderr}")
# 示例2: 在虚拟环境中执行命令
print("\n=== 示例2: 在虚拟环境中执行命令 ===")
# return_code, stdout, stderr = run_cmd_with_venv(
# r"C:\path\to\your\venv",
# "pip list"
# )
# print(f"返回码: {return_code}")
# print(f"输出: {stdout}")
# 示例3: 在虚拟环境中运行Python脚本
print("\n=== 示例3: 在虚拟环境中运行Python脚本 ===")
# return_code, stdout, stderr = run_python_in_venv(
# r"C:\path\to\your\venv",
# r"C:\path\to\your\script.py",
# args=["arg1", "arg2"]
# )
# print(f"返回码: {return_code}")
# print(f"输出: {stdout}")
# 示例4: 顺序执行多个命令
print("\n=== 示例4: 顺序执行多个命令 ===")
commands = [
"echo Hello",
"echo World",
"python --version"
]
results = execute_commands_sequentially(commands)
for result in results:
print(f"命令: {result['command']}")
print(f"返回码: {result['return_code']}")
print(f"输出: {result['stdout']}")
if result['stderr']:
print(f"错误: {result['stderr']}")
print("-" * 40)
# 使用示例
if __name__ == "__main__":
venv_path = r"d:\PythonProject\CH_EG\EG\.venv"
script_path = r"d:\PythonProject\CH_EG\EG\Start_Run.py"
print(f"虚拟环境路径: {venv_path}")
print(f"脚本路径: {script_path}")
# 检查路径是否存在
if not os.path.exists(venv_path):
print(f"错误: 虚拟环境路径不存在: {venv_path}")
sys.exit(1)
if not os.path.exists(script_path):
print(f"错误: 脚本文件不存在: {script_path}")
sys.exit(1)
# 在虚拟环境中运行Python脚本
return_code, stdout, stderr = run_python_in_venv(venv_path, script_path)
print(f"返回码: {return_code}")
print(f"标准输出: {stdout}")
print(f"错误输出: {stderr}")
if return_code == 0:
print("脚本执行成功!")
else:
print("脚本执行失败!")

1
MetaCore/ui/__init__.py Normal file
View File

@ -0,0 +1 @@
# UI模块

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,460 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
创建项目对话框
"""
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from MetaCore.data.project_manager import ProjectManager
class CreateProjectDialog(QDialog):
"""创建项目对话框"""
def __init__(self, project_manager: ProjectManager, project_settings_page=None, parent=None):
super().__init__(parent)
self.project_manager = project_manager
self.project_settings_page = project_settings_page
self.selected_template = "empty"
self.selected_path = ""
self.init_ui()
self.connect_signals()
# 设置对话框属性
self.setWindowTitle("创建新的项目")
self.setModal(True)
self.setMinimumSize(1000, 725)
self.resize(1000, 725) # 设置默认尺寸
# 设置默认项目位置
self.set_default_location_from_settings()
# 居中显示
self.center_dialog()
def init_ui(self):
"""初始化UI"""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 标题栏 - 使用默认系统标题栏
# self.create_title_bar(layout)
# 主要内容区域
self.create_main_content(layout)
# 底部按钮
self.create_button_area(layout)
def create_main_content(self, layout):
"""创建主要内容"""
content_widget = QWidget()
content_layout = QHBoxLayout(content_widget)
content_layout.setContentsMargins(0, 0, 0, 0)
content_layout.setSpacing(0)
# 左侧模板选择区域 (2/3)
self.create_template_section(content_layout)
# 右侧项目信息区域 (1/3)
self.create_project_info_section(content_layout)
layout.addWidget(content_widget)
def create_template_section(self, layout):
"""创建模板选择区域"""
template_widget = QWidget()
template_widget.setObjectName("templateSection")
template_layout = QVBoxLayout(template_widget)
template_layout.setContentsMargins(30, 30, 20, 30)
# 标题
title_label = QLabel("选择项目模板")
title_label.setObjectName("sectionTitle")
template_layout.addWidget(title_label)
# 模板网格
self.create_template_grid(template_layout)
# 设置固定比例 (2/3)
template_widget.setMinimumWidth(600)
layout.addWidget(template_widget, 2)
def create_template_grid(self, layout):
"""创建模板网格"""
# 滚动区域
scroll_area = QScrollArea()
scroll_area.setObjectName("templateScrollArea")
scroll_area.setWidgetResizable(True)
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# 模板容器
templates_widget = QWidget()
templates_widget.setObjectName("templatesContainer")
templates_layout = QGridLayout(templates_widget)
templates_layout.setSpacing(20) # 增加间距,适配固定尺寸按钮
templates_layout.setContentsMargins(10, 10, 10, 10) # 添加容器边距
templates_layout.setAlignment(Qt.AlignTop | Qt.AlignLeft) # 左上对齐
# 模板数据 - 当前只有空白项目模板,后续可以添加更多模板
templates = [
("empty", "📄", "空白项目模板"),
# 后续可以添加的模板示例:
# ("web", "🌐", "Web应用模板"),
# ("mobile", "📱", "移动应用模板"),
# ("desktop", "🖥️", "桌面应用模板"),
# ("api", "🔌", "API服务模板"),
# ("data", "📊", "数据分析模板"),
# ("game", "🎮", "游戏开发模板"),
]
# 创建模板项
self.template_buttons = []
for i, (template_id, icon, name) in enumerate(templates):
row = i // 3 # 每行最多3个模板为后续扩展做准备
col = i % 3
template_btn = self.create_template_item(template_id, icon, name)
templates_layout.addWidget(template_btn, row, col)
self.template_buttons.append(template_btn)
# 添加弹性空间,确保模板按钮不会被拉伸
templates_layout.setRowStretch(templates_layout.rowCount(), 1)
templates_layout.setColumnStretch(templates_layout.columnCount(), 1)
scroll_area.setWidget(templates_widget)
layout.addWidget(scroll_area)
def create_template_item(self, template_id, icon, name):
"""创建模板项"""
template_btn = QPushButton()
template_btn.setObjectName("templateItem")
template_btn.setCheckable(True)
# 设置固定尺寸,确保所有模板按钮大小一致,便于后续添加多个模板
template_btn.setFixedSize(180, 140)
# 设置默认选中
if template_id == "empty":
template_btn.setChecked(True)
# 布局
btn_layout = QVBoxLayout(template_btn)
btn_layout.setAlignment(Qt.AlignCenter)
btn_layout.setSpacing(12)
btn_layout.setContentsMargins(20, 24, 20, 24)
# 图标
icon_label = QLabel(icon)
icon_label.setObjectName("templateIcon")
icon_label.setAlignment(Qt.AlignCenter)
btn_layout.addWidget(icon_label)
# 名称
name_label = QLabel(name)
name_label.setObjectName("templateName")
name_label.setAlignment(Qt.AlignCenter)
name_label.setWordWrap(True)
btn_layout.addWidget(name_label)
# 点击事件
def on_clicked():
# 取消其他按钮的选中状态
for btn in self.template_buttons:
if btn != template_btn:
btn.setChecked(False)
template_btn.setChecked(True)
self.selected_template = template_id
self.update_template_description(template_id)
template_btn.clicked.connect(on_clicked)
return template_btn
def create_project_info_section(self, layout):
"""创建项目信息区域"""
info_widget = QWidget()
info_widget.setObjectName("projectInfoSection")
info_layout = QVBoxLayout(info_widget)
info_layout.setContentsMargins(20, 30, 30, 30)
# 标题
title_label = QLabel("项目信息")
title_label.setObjectName("sectionTitle")
info_layout.addWidget(title_label)
# 模板描述
self.description_label = QLabel("创建一个空白项目,您可以从头开始构建您的应用程序。包含基础的项目结构和配置文件,适用于任何类型的项目开发。")
self.description_label.setObjectName("templateDescription")
self.description_label.setWordWrap(True)
info_layout.addWidget(self.description_label)
# 表单
self.create_project_form(info_layout)
info_layout.addStretch()
# 设置固定比例 (1/3),增加最大宽度以容纳更长的错误信息
info_widget.setMaximumWidth(350) # 从300增加到350
layout.addWidget(info_widget, 1)
def create_project_form(self, layout):
"""创建项目表单"""
form_layout = QVBoxLayout()
form_layout.setSpacing(18)
# 项目名称
name_group = QVBoxLayout()
name_group.setSpacing(4) # 减小间距,让错误提示更紧贴
name_label = QLabel("项目名称")
name_label.setObjectName("formLabel")
name_group.addWidget(name_label)
self.name_input = QLineEdit()
self.name_input.setObjectName("formInput")
self.name_input.setPlaceholderText("输入项目名称")
name_group.addWidget(self.name_input)
# 错误提示标签 - 紧贴在输入框下方的小红字
self.name_error_label = QLabel("")
self.name_error_label.setObjectName("errorLabel")
self.name_error_label.setWordWrap(False) # 不换行,保持一行显示
self.name_error_label.setFixedHeight(18) # 固定高度,一行小字
self.name_error_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.name_error_label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
self.name_error_label.hide() # 初始隐藏
name_group.addWidget(self.name_error_label)
form_layout.addLayout(name_group)
# 项目描述
desc_group = QVBoxLayout()
desc_label = QLabel("项目描述")
desc_label.setObjectName("formLabel")
desc_group.addWidget(desc_label)
self.desc_input = QTextEdit()
self.desc_input.setObjectName("formTextArea")
self.desc_input.setPlaceholderText("输入项目描述(可选)")
self.desc_input.setMaximumHeight(70)
desc_group.addWidget(self.desc_input)
form_layout.addLayout(desc_group)
# 项目位置
location_group = QVBoxLayout()
location_label = QLabel("项目位置")
location_label.setObjectName("formLabel")
location_group.addWidget(location_label)
location_layout = QHBoxLayout()
self.location_input = QLineEdit()
self.location_input.setObjectName("formInput")
self.location_input.setPlaceholderText("点击浏览选择位置")
self.location_input.setReadOnly(True)
location_layout.addWidget(self.location_input)
browse_btn = QPushButton("📁")
browse_btn.setObjectName("browseBtn")
browse_btn.setFixedSize(32, 32) # 减小尺寸40x32 -> 32x32
browse_btn.setToolTip("选择项目保存位置")
browse_btn.clicked.connect(self.browse_location)
location_layout.addWidget(browse_btn)
location_group.addLayout(location_layout)
form_layout.addLayout(location_group)
layout.addLayout(form_layout)
def create_button_area(self, layout):
"""创建按钮区域"""
button_widget = QWidget()
button_widget.setObjectName("buttonArea")
button_layout = QHBoxLayout(button_widget)
button_layout.setContentsMargins(30, 20, 30, 30)
button_layout.setSpacing(10) # 设置按钮间距
button_layout.addStretch()
# 取消按钮
cancel_btn = QPushButton("取消")
cancel_btn.setObjectName("secondaryBtn")
cancel_btn.clicked.connect(self.reject)
button_layout.addWidget(cancel_btn)
# 创建按钮
self.create_btn = QPushButton("创建项目")
self.create_btn.setObjectName("primaryBtn")
self.create_btn.clicked.connect(self.create_project)
button_layout.addWidget(self.create_btn)
layout.addWidget(button_widget)
def update_template_description(self, template_id):
"""更新模板描述"""
descriptions = {
"empty": "创建一个空白项目,您可以从头开始构建您的应用程序。包含基础的项目结构和配置文件,适用于任何类型的项目开发。",
}
description = descriptions.get(template_id, "项目模板描述")
self.description_label.setText(description)
def browse_location(self):
"""浏览项目位置"""
# 使用项目设置中的默认位置作为起始目录
if self.project_settings_page:
start_dir = self.project_settings_page.get_default_project_location()
else:
start_dir = os.path.expanduser("~/Documents")
folder = QFileDialog.getExistingDirectory(self, "选择项目保存位置", start_dir)
if folder:
self.selected_path = folder
self.location_input.setText(folder)
# 触发验证
self.validate_input()
def create_project(self):
"""创建项目"""
# 验证输入
name = self.name_input.text().strip()
if not name:
QMessageBox.warning(self, "输入错误", "请输入项目名称")
return
if not self.selected_path:
QMessageBox.warning(self, "输入错误", "请选择项目保存位置")
return
# 使用项目管理器的验证方法进行全面检查
is_valid, error_message = self.project_manager.validate_project_creation(name, self.selected_path)
if not is_valid:
QMessageBox.warning(self, "创建失败", error_message)
return
# 创建项目
description = self.desc_input.toPlainText().strip()
try:
project = self.project_manager.add_project(
name, description, self.selected_template, self.selected_path
)
# 显示详细的成功信息
success_msg = f"""项目创建成功!
项目名称: {name}
项目目录: {project.project_dir}
项目文件结构已创建完成包含
models/ - 模型文件夹
textures/ - 贴图文件夹
scenes/ - 场景文件夹
project.json - 项目配置文件
您可以开始在此基础上开发您的应用程序"""
QMessageBox.information(self, "创建成功", success_msg)
self.accept()
except Exception as e:
QMessageBox.critical(self, "创建失败", f"项目创建失败:{str(e)}")
def get_template_name(self, template_id):
"""获取模板名称"""
template_names = {
"empty": "空白项目模板",
}
return template_names.get(template_id, "空白项目模板")
def connect_signals(self):
"""连接信号"""
# 连接项目名称输入框的文本变化信号
self.name_input.textChanged.connect(self.validate_input)
# 连接路径选择的变化
self.location_input.textChanged.connect(self.validate_input)
def validate_input(self):
"""实时验证输入"""
name = self.name_input.text().strip()
path = self.selected_path
# 重置样式属性
self.name_input.setProperty("error", False)
self.name_input.setProperty("valid", False)
self.create_btn.setEnabled(True)
# 如果名称为空,清空错误提示(用户可能还在输入)
if not name:
self.name_error_label.hide()
self.name_input.style().polish(self.name_input)
return
# 如果路径未选择,不进行完整验证
if not path:
self.name_error_label.hide()
self.name_input.style().polish(self.name_input)
return
# 进行验证
is_valid, error_message = self.project_manager.validate_project_creation(name, path)
if not is_valid:
# 设置错误状态
self.name_input.setProperty("error", True)
self.name_input.setProperty("valid", False)
# 禁用创建按钮
self.create_btn.setEnabled(False)
# 显示错误信息 - 一行小红字
self.name_error_label.setText(error_message)
self.name_error_label.show()
else:
# 设置成功状态
self.name_input.setProperty("error", False)
self.name_input.setProperty("valid", True)
# 隐藏错误信息
self.name_error_label.hide()
# 刷新样式
self.name_input.style().polish(self.name_input)
def set_default_location(self, location: str):
"""设置默认项目位置"""
if location and os.path.exists(location):
self.selected_path = location
self.location_input.setText(location)
# 触发验证
self.validate_input()
def set_default_location_from_settings(self):
"""从项目设置中设置默认项目位置"""
if self.project_settings_page:
default_location = self.project_settings_page.get_default_project_location()
if default_location:
self.set_default_location(default_location)
def center_dialog(self):
"""对话框居中"""
if self.parent():
parent_rect = self.parent().geometry()
x = parent_rect.x() + (parent_rect.width() - self.width()) // 2
y = parent_rect.y() + (parent_rect.height() - self.height()) // 2
self.move(x, y)
else:
# 如果没有父窗口,则在屏幕中央显示
screen = QApplication.desktop().screenGeometry()
x = (screen.width() - self.width()) // 2
y = (screen.height() - self.height()) // 2
self.move(x, y)

238
MetaCore/ui/file_watcher.py Normal file
View File

@ -0,0 +1,238 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件系统监控器
实时监测目录和文件的变化
"""
import os
from PyQt5.QtCore import QObject, QFileSystemWatcher, pyqtSignal, QTimer
from PyQt5.QtWidgets import QMessageBox
class FileWatcher(QObject):
"""文件系统监控器"""
# 信号定义
directory_changed = pyqtSignal(str) # 目录变化信号
file_changed = pyqtSignal(str) # 文件变化信号
project_added = pyqtSignal(str) # 项目添加信号
project_removed = pyqtSignal(str) # 项目删除信号
def __init__(self, parent=None):
super().__init__(parent)
# 创建文件系统监控器
self.watcher = QFileSystemWatcher()
# 连接信号
self.watcher.directoryChanged.connect(self.on_directory_changed)
self.watcher.fileChanged.connect(self.on_file_changed)
# 监控的路径列表
self.watched_directories = set()
self.watched_files = set()
# 目录内容缓存(用于检测具体变化)
self.directory_contents = {}
# 延迟处理定时器(避免频繁触发)
self.change_timer = QTimer()
self.change_timer.setSingleShot(True)
self.change_timer.timeout.connect(self.process_pending_changes)
self.pending_changes = set()
def add_directory(self, directory_path):
"""
添加目录监控
Args:
directory_path (str): 要监控的目录路径
"""
if not os.path.exists(directory_path):
print(f"警告: 目录不存在 - {directory_path}")
return False
if not os.path.isdir(directory_path):
print(f"警告: 路径不是目录 - {directory_path}")
return False
# 规范化路径
directory_path = os.path.abspath(directory_path)
if directory_path not in self.watched_directories:
# 添加到监控列表
self.watcher.addPath(directory_path)
self.watched_directories.add(directory_path)
# 缓存目录内容
self.cache_directory_contents(directory_path)
print(f"开始监控目录: {directory_path}")
return True
else:
print(f"目录已在监控中: {directory_path}")
return False
def remove_directory(self, directory_path):
"""
移除目录监控
Args:
directory_path (str): 要移除监控的目录路径
"""
directory_path = os.path.abspath(directory_path)
if directory_path in self.watched_directories:
self.watcher.removePath(directory_path)
self.watched_directories.remove(directory_path)
# 清除缓存
if directory_path in self.directory_contents:
del self.directory_contents[directory_path]
print(f"停止监控目录: {directory_path}")
return True
else:
print(f"目录未在监控中: {directory_path}")
return False
def add_file(self, file_path):
"""
添加文件监控
Args:
file_path (str): 要监控的文件路径
"""
if not os.path.exists(file_path):
print(f"警告: 文件不存在 - {file_path}")
return False
if not os.path.isfile(file_path):
print(f"警告: 路径不是文件 - {file_path}")
return False
file_path = os.path.abspath(file_path)
if file_path not in self.watched_files:
self.watcher.addPath(file_path)
self.watched_files.add(file_path)
print(f"开始监控文件: {file_path}")
return True
else:
print(f"文件已在监控中: {file_path}")
return False
def remove_file(self, file_path):
"""
移除文件监控
Args:
file_path (str): 要移除监控的文件路径
"""
file_path = os.path.abspath(file_path)
if file_path in self.watched_files:
self.watcher.removePath(file_path)
self.watched_files.remove(file_path)
print(f"停止监控文件: {file_path}")
return True
else:
print(f"文件未在监控中: {file_path}")
return False
def cache_directory_contents(self, directory_path):
"""缓存目录内容"""
try:
contents = set(os.listdir(directory_path))
self.directory_contents[directory_path] = contents
except OSError as e:
print(f"无法读取目录内容: {directory_path} - {e}")
def on_directory_changed(self, directory_path):
"""目录变化处理"""
print(f"检测到目录变化: {directory_path}")
# 添加到待处理变化列表
self.pending_changes.add(directory_path)
# 启动延迟处理定时器
self.change_timer.start(500) # 500ms延迟
def on_file_changed(self, file_path):
"""文件变化处理"""
print(f"检测到文件变化: {file_path}")
# 立即发出文件变化信号
self.file_changed.emit(file_path)
def process_pending_changes(self):
"""处理待处理的目录变化"""
for directory_path in self.pending_changes:
self.analyze_directory_changes(directory_path)
self.pending_changes.clear()
def analyze_directory_changes(self, directory_path):
"""分析目录具体变化"""
if not os.path.exists(directory_path):
print(f"目录已被删除: {directory_path}")
self.directory_changed.emit(directory_path)
return
try:
# 获取当前目录内容
current_contents = set(os.listdir(directory_path))
# 获取之前缓存的内容
previous_contents = self.directory_contents.get(directory_path, set())
# 检测新增的项目
added_items = current_contents - previous_contents
for item in added_items:
item_path = os.path.join(directory_path, item)
if os.path.isdir(item_path):
print(f"检测到新增目录: {item_path}")
self.project_added.emit(item_path)
else:
print(f"检测到新增文件: {item_path}")
# 检测删除的项目
removed_items = previous_contents - current_contents
for item in removed_items:
item_path = os.path.join(directory_path, item)
print(f"检测到删除项目: {item_path}")
self.project_removed.emit(item_path)
# 更新缓存
self.directory_contents[directory_path] = current_contents
# 发出目录变化信号
if added_items or removed_items:
self.directory_changed.emit(directory_path)
except OSError as e:
print(f"分析目录变化失败: {directory_path} - {e}")
def get_watched_directories(self):
"""获取所有监控的目录"""
return list(self.watched_directories)
def get_watched_files(self):
"""获取所有监控的文件"""
return list(self.watched_files)
def clear_all_watches(self):
"""清除所有监控"""
# 移除所有路径
for path in list(self.watched_directories):
self.remove_directory(path)
for path in list(self.watched_files):
self.remove_file(path)
print("已清除所有文件监控")
def is_watching(self, path):
"""检查是否正在监控指定路径"""
path = os.path.abspath(path)
return path in self.watched_directories or path in self.watched_files

197
MetaCore/ui/icon_manager.py Normal file
View File

@ -0,0 +1,197 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
图标管理器
统一管理应用程序中使用的所有图标
"""
import os
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import QSize
class IconManager:
"""图标管理器"""
# 图标目录路径
ICONS_DIR = "Resources/Icons"
# 图标文件映射
ICON_FILES = {
# 应用程序图标
'app': 'app_icon.png',
'logo': 'logo.png',
# 操作图标
'create': 'create.png',
'import': 'import.png',
'folder': 'folder.png',
'delete': 'delete.png',
'Refresh': 'Refresh.png',
# 视图图标
'grid_view': 'grid_view.png',
'list_view': 'list_view.png',
# 导航图标
'overview': 'overview.png',
'management': 'management.png',
'resource_category': 'category.png',
'resource_management': 'resource.png',
'project_settings': 'settings.png',
'system_settings': 'system.png',
# 树箭头
'down': 'down.png',
'right': 'right.png',
}
# 图标缓存
_icon_cache = {}
@classmethod
def get_icon(cls, icon_name: str, size: QSize = None) -> QIcon:
"""
获取图标
Args:
icon_name (str): 图标名称
size (QSize, optional): 图标尺寸
Returns:
QIcon: 图标对象如果文件不存在则返回空图标
"""
# 检查缓存
cache_key = f"{icon_name}_{size.width() if size else 'default'}_{size.height() if size else 'default'}"
if cache_key in cls._icon_cache:
return cls._icon_cache[cache_key]
# 获取图标文件路径
icon_path = cls.get_icon_path(icon_name)
if not icon_path or not os.path.exists(icon_path):
# 如果图标文件不存在,返回空图标
icon = QIcon()
else:
# 创建图标
if size:
pixmap = QPixmap(icon_path).scaled(size, aspectRatioMode=1, transformMode=1)
icon = QIcon(pixmap)
else:
icon = QIcon(icon_path)
# 缓存图标
cls._icon_cache[cache_key] = icon
return icon
@classmethod
def get_icon_path(cls, icon_name: str) -> str:
"""
获取图标文件路径
Args:
icon_name (str): 图标名称
Returns:
str: 图标文件的完整路径如果不存在则返回空字符串
"""
if icon_name not in cls.ICON_FILES:
return ""
icon_file = cls.ICON_FILES[icon_name]
icon_path = os.path.join(cls.ICONS_DIR, icon_file)
return icon_path
@classmethod
def get_pixmap(cls, icon_name: str, size: QSize = None) -> QPixmap:
"""
获取图标的 QPixmap 对象
Args:
icon_name (str): 图标名称
size (QSize, optional): 图标尺寸
Returns:
QPixmap: 图标的 QPixmap 对象
"""
icon_path = cls.get_icon_path(icon_name)
if not icon_path or not os.path.exists(icon_path):
return QPixmap()
pixmap = QPixmap(icon_path)
if size:
pixmap = pixmap.scaled(size, aspectRatioMode=1, transformMode=1)
return pixmap
@classmethod
def icon_exists(cls, icon_name: str) -> bool:
"""
检查图标是否存在
Args:
icon_name (str): 图标名称
Returns:
bool: 图标文件是否存在
"""
icon_path = cls.get_icon_path(icon_name)
return icon_path and os.path.exists(icon_path)
@classmethod
def get_project_type_icon(cls, project_type: str) -> QIcon:
"""
根据项目类型获取对应图标
Args:
project_type (str): 项目类型
Returns:
QIcon: 项目类型对应的图标
"""
icon_name = f"project_{project_type}"
if icon_name in cls.ICON_FILES:
return cls.get_icon(icon_name)
else:
# 如果没有对应的项目类型图标,返回默认项目图标
return cls.get_icon('project_empty')
@classmethod
def clear_cache(cls):
"""清空图标缓存"""
cls._icon_cache.clear()
@classmethod
def ensure_icons_directory(cls):
"""确保图标目录存在"""
if not os.path.exists(cls.ICONS_DIR):
os.makedirs(cls.ICONS_DIR, exist_ok=True)
@classmethod
def get_available_icons(cls) -> list:
"""
获取所有可用的图标列表
Returns:
list: 可用图标名称列表
"""
available_icons = []
for icon_name in cls.ICON_FILES:
if cls.icon_exists(icon_name):
available_icons.append(icon_name)
return available_icons
@classmethod
def get_missing_icons(cls) -> list:
"""
获取缺失的图标列表
Returns:
list: 缺失图标名称列表
"""
missing_icons = []
for icon_name in cls.ICON_FILES:
if not cls.icon_exists(icon_name):
missing_icons.append(icon_name)
return missing_icons

View File

@ -0,0 +1,468 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
导入项目对话框
"""
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from MetaCore.data.project_manager import ProjectManager
class ImportProjectDialog(QDialog):
"""导入项目对话框"""
def __init__(self, project_manager: ProjectManager, project_settings_page=None, parent=None):
super().__init__(parent)
self.project_manager = project_manager
self.project_settings_page = project_settings_page
self.selected_files = []
self.init_ui()
self.connect_signals()
# 设置对话框属性
self.setWindowTitle("导入文件夹")
self.setModal(True)
self.setMinimumSize(1000, 725)
self.resize(1000, 725) # 设置默认尺寸
# 居中显示
self.center_dialog()
def init_ui(self):
"""初始化UI"""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 标题栏
# self.create_title_bar(layout)
# 主要内容区域
self.create_main_content(layout)
# 底部按钮
self.create_button_area(layout)
def create_title_bar(self, layout):
"""创建标题栏"""
title_widget = QWidget()
title_widget.setObjectName("dialogTitle")
title_layout = QHBoxLayout(title_widget)
title_layout.setContentsMargins(30, 20, 30, 20)
# 标题
title_label = QLabel("导入项目文件")
title_label.setObjectName("titleLabel")
title_layout.addWidget(title_label)
title_layout.addStretch()
# 关闭按钮
close_btn = QPushButton("")
close_btn.setObjectName("closeBtn")
close_btn.setFixedSize(32, 32)
close_btn.clicked.connect(self.reject)
title_layout.addWidget(close_btn)
layout.addWidget(title_widget)
def create_main_content(self, layout):
"""创建主要内容"""
content_widget = QWidget()
content_layout = QVBoxLayout(content_widget)
content_layout.setContentsMargins(30, 30, 30, 30)
content_layout.setSpacing(20)
# 导入区域
self.create_import_area(content_layout)
# 导入选项
self.create_import_options(content_layout)
layout.addWidget(content_widget)
def create_import_area(self, layout):
"""创建导入区域"""
import_group = QGroupBox("选择文件夹")
import_group.setObjectName("importGroup")
import_layout = QVBoxLayout(import_group)
import_layout.setSpacing(15)
# 拖拽上传区域
self.upload_area = UploadArea()
self.upload_area.files_dropped.connect(self.on_files_dropped)
self.upload_area.select_files_requested.connect(self.select_files)
import_layout.addWidget(self.upload_area)
# 或者选择文件
file_layout = QHBoxLayout()
file_layout.addWidget(QLabel("或者"))
select_btn = QPushButton("点击选择文件夹")
select_btn.setObjectName("selectBtn")
select_btn.clicked.connect(self.select_files)
file_layout.addWidget(select_btn)
file_layout.addStretch()
import_layout.addLayout(file_layout)
# 文件列表
self.file_list = QListWidget()
self.file_list.setObjectName("fileList")
self.file_list.setMaximumHeight(150)
import_layout.addWidget(self.file_list)
layout.addWidget(import_group)
def create_import_options(self, layout):
"""创建导入选项"""
options_widget = QWidget()
options_widget.setObjectName("optionsGroup")
options_layout = QHBoxLayout(options_widget)
# 导入选项
self.extract_checkbox = QCheckBox("导入后打开项目")
self.extract_checkbox.setChecked(True)
options_layout.addWidget(self.extract_checkbox)
options_layout.addStretch()
self.overwrite_checkbox = QCheckBox("还原动态数据源")
options_layout.addWidget(self.overwrite_checkbox)
layout.addWidget(options_widget)
# def create_import_options(self, layout):
# """创建导入选项"""
# options_group = QGroupBox("导入选项")
# options_group.setObjectName("optionsGroup")
# options_layout = QVBoxLayout(options_group)
# options_layout.setSpacing(10)
#
# # 项目名称
# name_layout = QHBoxLayout()
# name_layout.addWidget(QLabel("项目名称:"))
#
# self.name_input = QLineEdit()
# self.name_input.setObjectName("nameInput")
# self.name_input.setPlaceholderText("自动从文件名提取")
# name_layout.addWidget(self.name_input)
#
# options_layout.addLayout(name_layout)
#
# # 导入位置
# location_layout = QHBoxLayout()
# location_layout.addWidget(QLabel("导入位置:"))
#
# self.location_input = QLineEdit()
# self.location_input.setObjectName("locationInput")
# self.location_input.setPlaceholderText("选择导入位置")
# self.location_input.setReadOnly(True)
# location_layout.addWidget(self.location_input)
#
# browse_btn = QPushButton("浏览")
# browse_btn.setObjectName("browseBtn")
# browse_btn.clicked.connect(self.browse_location)
# location_layout.addWidget(browse_btn)
#
# options_layout.addLayout(location_layout)
#
# # 导入选项
# self.extract_checkbox = QCheckBox("解压缩文件")
# self.extract_checkbox.setChecked(True)
# options_layout.addWidget(self.extract_checkbox)
#
# self.overwrite_checkbox = QCheckBox("覆盖已存在的文件")
# options_layout.addWidget(self.overwrite_checkbox)
#
# layout.addWidget(options_group)
def create_button_area(self, layout):
"""创建按钮区域"""
button_widget = QWidget()
button_widget.setObjectName("buttonArea")
button_layout = QHBoxLayout(button_widget)
button_layout.setContentsMargins(30, 20, 30, 30)
button_layout.setSpacing(10) # 与创建项目对话框保持一致
button_layout.addStretch()
# 取消按钮
self.cancel_btn = QPushButton("取消")
self.cancel_btn.setObjectName("secondaryBtn")
self.cancel_btn.clicked.connect(self.reject)
button_layout.addWidget(self.cancel_btn)
# 导入按钮
self.import_btn = QPushButton("导入项目")
self.import_btn.setObjectName("primaryBtn")
self.import_btn.setEnabled(False)
self.import_btn.clicked.connect(self.import_project)
button_layout.addWidget(self.import_btn)
layout.addWidget(button_widget)
def select_files(self):
"""选择文件夹"""
# 使用项目设置中的默认位置作为起始目录
if self.project_settings_page:
start_dir = self.project_settings_page.get_default_project_location()
else:
start_dir = os.path.expanduser("~/Documents")
folder = QFileDialog.getExistingDirectory(
self, "选择文件夹",
start_dir
)
if folder:
self.selected_files = [folder]
self.update_file_list()
self.update_project_name()
def browse_location(self):
"""浏览导入位置"""
# 当前UI简化版本不需要此功能
pass
def on_files_dropped(self, files):
"""文件夹拖拽事件"""
# 只接受文件夹
folders = [f for f in files if os.path.isdir(f)]
if folders:
self.selected_files = folders
self.update_file_list()
self.update_project_name()
else:
QMessageBox.warning(self, "提示", "请拖拽文件夹,不支持单个文件")
def update_file_list(self):
"""更新文件夹列表"""
self.file_list.clear()
for folder_path in self.selected_files:
folder_name = os.path.basename(folder_path)
# 计算文件夹大小和文件数量
try:
total_size = 0
file_count = 0
for root, dirs, files in os.walk(folder_path):
for file in files:
file_path = os.path.join(root, file)
if os.path.exists(file_path):
total_size += os.path.getsize(file_path)
file_count += 1
size_str = self.format_file_size(total_size)
item_text = f"📁 {folder_name} ({file_count} 个文件, {size_str})"
except Exception:
item_text = f"📁 {folder_name} (无法计算大小)"
self.file_list.addItem(item_text)
# 按钮状态由 update_project_name 方法中的验证逻辑控制
def update_project_name(self):
"""更新项目名称并验证"""
if not self.selected_files:
self.import_btn.setEnabled(False)
return
# 从第一个文件夹名自动提取项目名称
folder_path = self.selected_files[0]
folder_name = os.path.basename(folder_path)
# 进行验证
is_valid, error_message = self.project_manager.validate_project_import(folder_name, folder_path)
if is_valid:
# 验证通过,启用导入按钮
self.import_btn.setEnabled(True)
self.import_btn.setToolTip("")
else:
# 验证失败,禁用导入按钮并显示错误信息
self.import_btn.setEnabled(False)
self.import_btn.setToolTip(f"无法导入: {error_message}")
def format_file_size(self, size):
"""格式化文件大小"""
for unit in ['B', 'KB', 'MB', 'GB']:
if size < 1024.0:
return f"{size:.1f} {unit}"
size /= 1024.0
return f"{size:.1f} TB"
def import_project(self):
"""导入项目"""
# 防止重复点击
if not self.import_btn.isEnabled():
return
# 立即禁用按钮,防止重复点击
self.import_btn.setEnabled(False)
try:
# 验证输入
if not self.selected_files:
QMessageBox.warning(self, "输入错误", "请选择要导入的文件夹")
return
# 从第一个文件夹名自动提取项目名称
folder_path = self.selected_files[0]
folder_name = os.path.basename(folder_path)
name = folder_name
# 使用项目管理器的验证方法进行全面检查
is_valid, error_message = self.project_manager.validate_project_import(name, folder_path)
if not is_valid:
QMessageBox.warning(self, "导入失败", error_message)
return
# 导入项目 - 直接使用现有文件夹作为项目目录
project = self.project_manager.import_project(
name, # 项目名称
f"从文件夹 {folder_name} 导入", # 项目描述
"imported", # 项目类型
folder_path # 直接使用原文件夹路径作为项目目录
)
# 处理导入选项
if self.overwrite_checkbox.isChecked():
self.restore_dynamic_data_sources(project)
QMessageBox.information(self, "导入成功", f"项目 \"{name}\" 导入成功!\n文件夹位置: {folder_path}")
# 如果勾选了导入后打开项目,则打开项目
if self.extract_checkbox.isChecked():
self.open_imported_project(project)
self.accept()
except Exception as e:
QMessageBox.critical(self, "导入失败", f"项目导入失败:{str(e)}")
finally:
# 确保在任何情况下都重新启用按钮(如果对话框没有关闭)
if self.isVisible():
self.import_btn.setEnabled(True)
def open_imported_project(self, project):
"""打开导入的项目"""
try:
# 使用项目管理器的验证方法检查项目是否可以打开
is_valid, error_message = self.project_manager.validate_project_open(project.project_dir)
if not is_valid:
QMessageBox.warning(self, "无法打开项目", f"项目无法打开: {error_message}")
return
# 验证通过,显示成功信息
QMessageBox.information(self, "打开项目", f"正在打开项目: {project.title}")
# TODO: 在这里添加实际的项目打开逻辑
except Exception as e:
QMessageBox.critical(self, "错误", f"打开项目时发生错误:\n{str(e)}")
def restore_dynamic_data_sources(self, project):
"""还原动态数据源"""
try:
# TODO: 在这里添加还原动态数据源的逻辑
print(f"还原项目 {project.title} 的动态数据源")
except Exception as e:
QMessageBox.warning(self, "警告", f"还原动态数据源时发生错误:\n{str(e)}")
def connect_signals(self):
"""连接信号"""
# 连接按钮信号
self.cancel_btn.clicked.connect(self.reject)
self.import_btn.clicked.connect(self.import_project)
# 连接文件选择按钮信号
# self.select_files_btn.clicked.connect(self.select_files)
# self.select_folder_btn.clicked.connect(self.select_folder)
def center_dialog(self):
"""对话框居中"""
if self.parent():
parent_rect = self.parent().geometry()
x = parent_rect.x() + (parent_rect.width() - self.width()) // 2
y = parent_rect.y() + (parent_rect.height() - self.height()) // 2
self.move(x, y)
class UploadArea(QWidget):
"""文件上传区域"""
files_dropped = pyqtSignal(list)
select_files_requested = pyqtSignal()
def __init__(self):
super().__init__()
self.setAcceptDrops(True)
self.init_ui()
def init_ui(self):
"""初始化UI"""
self.setObjectName("uploadArea")
self.setMinimumHeight(150)
layout = QVBoxLayout(self)
layout.setAlignment(Qt.AlignCenter)
layout.setSpacing(10)
# 上传图标
icon_label = QLabel("📁")
icon_label.setStyleSheet("font-size: 32px; color: #666666;")
icon_label.setAlignment(Qt.AlignCenter)
layout.addWidget(icon_label)
# 提示文字
text_label = QLabel("拖拽文件夹到这里,或者")
text_label.setStyleSheet("color: #888888; font-size: 14px;")
text_label.setAlignment(Qt.AlignCenter)
layout.addWidget(text_label)
# 选择按钮
select_btn = QPushButton("点击选择")
select_btn.setObjectName("uploadBtn")
select_btn.clicked.connect(self.select_files_requested.emit)
layout.addWidget(select_btn)
# 支持格式提示
format_label = QLabel("支持任意文件夹")
format_label.setStyleSheet("color: #666666; font-size: 12px;")
format_label.setAlignment(Qt.AlignCenter)
layout.addWidget(format_label)
def dragEnterEvent(self, event):
"""拖拽进入事件"""
if event.mimeData().hasUrls():
event.acceptProposedAction()
self.setProperty("dragOver", True)
self.style().unpolish(self)
self.style().polish(self)
def dragLeaveEvent(self, event):
"""拖拽离开事件"""
self.setProperty("dragOver", False)
self.style().unpolish(self)
self.style().polish(self)
def dropEvent(self, event):
"""拖拽放下事件"""
files = []
for url in event.mimeData().urls():
if url.isLocalFile():
files.append(url.toLocalFile())
if files:
self.files_dropped.emit(files)
self.setProperty("dragOver", False)
self.style().unpolish(self)
self.style().polish(self)

303
MetaCore/ui/main_window.py Normal file
View File

@ -0,0 +1,303 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
主窗口类
"""
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from MetaCore.ui.sidebar import Sidebar
from MetaCore.ui.project_area import ProjectArea
from MetaCore.ui.create_project_dialog import CreateProjectDialog
from MetaCore.ui.import_project_dialog import ImportProjectDialog
from MetaCore.ui.project_settings_page import ProjectSettingsPage
from MetaCore.data.project_manager import ProjectManager
from MetaCore.ui.icon_manager import IconManager
class MainWindow(QMainWindow):
"""主窗口类"""
def __init__(self, project_manager: ProjectManager):
super().__init__()
self.project_manager = project_manager
self.current_filter = "overview"
self.current_search = ""
self.init_ui()
self.connect_signals()
# 设置窗口属性
self.setWindowTitle("MetaCore - 项目管理平台")
self.setWindowIcon(IconManager.get_icon('app'))
self.setMinimumSize(1000, 700)
self.resize(1400, 900)
# 响应式布局标志
self.is_compact_mode = False
# 居中显示
self.center_window()
def init_ui(self):
"""初始化UI"""
# 创建中央部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 创建主布局
main_layout = QHBoxLayout(central_widget)
# 设置部件内容周围的边距大小分别为左、上、右和下。
# 边距由布局系统使用,并且子类可能使用边距来指定绘制区域(例如,不包括框架)。
# 更改页边距会触发一个 resizeEvent() 事件。
main_layout.setContentsMargins(0, 0, 0, 0)
main_layout.setSpacing(0)
# 创建侧边栏
self.sidebar = Sidebar(self.project_manager)
main_layout.addWidget(self.sidebar)
# 创建项目区域
self.project_area = ProjectArea(self.project_manager)
# 创建项目设置页面
self.project_settings_page = ProjectSettingsPage()
# 创建堆叠窗口部件来管理不同页面
self.stacked_widget = QStackedWidget()
self.stacked_widget.addWidget(self.project_area) # 索引 0: 项目区域
self.stacked_widget.addWidget(self.project_settings_page) # 索引 1: 项目设置页面
main_layout.addWidget(self.stacked_widget)
# 设置布局比例
main_layout.setStretch(0, 0) # 侧边栏固定宽度
main_layout.setStretch(1, 1) # 堆叠窗口部件自适应
# 创建状态栏
# self.create_status_bar()
# 创建菜单栏
# self.create_menu_bar()
def create_status_bar(self):
"""创建状态栏"""
self.status_bar = self.statusBar()
# 项目数量标签
self.project_count_label = QLabel()
self.status_bar.addWidget(self.project_count_label)
# 分隔符
self.status_bar.addPermanentWidget(QLabel("|"))
# 当前用户标签
user_label = QLabel("当前用户: Admin")
self.status_bar.addPermanentWidget(user_label)
# 更新项目数量
self.update_project_count()
def create_menu_bar(self):
"""创建菜单栏"""
menubar = self.menuBar()
# 文件菜单
file_menu = menubar.addMenu('文件(&F)')
# 新建项目
new_action = QAction('新建项目(&N)', self)
new_action.setShortcut('Ctrl+N')
new_action.setStatusTip('创建新项目')
new_action.triggered.connect(self.show_create_project_dialog)
file_menu.addAction(new_action)
# 导入项目
import_action = QAction('导入项目(&I)', self)
import_action.setShortcut('Ctrl+I')
import_action.setStatusTip('导入现有项目')
import_action.triggered.connect(self.show_import_project_dialog)
file_menu.addAction(import_action)
file_menu.addSeparator()
# 退出
exit_action = QAction('退出(&X)', self)
exit_action.setShortcut('Ctrl+Q')
exit_action.setStatusTip('退出应用程序')
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
# 编辑菜单
edit_menu = menubar.addMenu('编辑(&E)')
# 搜索
search_action = QAction('搜索项目(&S)', self)
search_action.setShortcut('Ctrl+F')
search_action.setStatusTip('搜索项目')
search_action.triggered.connect(self.focus_search)
edit_menu.addAction(search_action)
# 视图菜单
view_menu = menubar.addMenu('视图(&V)')
# 网格视图
grid_action = QAction('网格视图(&G)', self)
grid_action.setCheckable(True)
grid_action.setChecked(True)
grid_action.triggered.connect(lambda: self.project_area.set_view_mode('grid'))
view_menu.addAction(grid_action)
# 列表视图
list_action = QAction('列表视图(&L)', self)
list_action.setCheckable(True)
list_action.triggered.connect(lambda: self.project_area.set_view_mode('list'))
view_menu.addAction(list_action)
# 创建视图模式组
view_group = QActionGroup(self)
view_group.addAction(grid_action)
view_group.addAction(list_action)
# 帮助菜单
help_menu = menubar.addMenu('帮助(&H)')
# 关于
about_action = QAction('关于(&A)', self)
about_action.triggered.connect(self.show_about)
help_menu.addAction(about_action)
def connect_signals(self):
"""连接信号"""
# 侧边栏信号
self.sidebar.filter_changed.connect(self.on_filter_changed)
self.sidebar.navigation_changed.connect(self.on_navigation_changed) # 新增导航变化信号
self.sidebar.create_project_requested.connect(self.show_create_project_dialog)
self.sidebar.import_project_requested.connect(self.show_import_project_dialog)
# 项目区域信号
self.project_area.search_changed.connect(self.on_search_changed)
self.project_area.create_project_requested.connect(self.show_create_project_dialog)
self.project_area.import_project_requested.connect(self.show_import_project_dialog)
# 项目设置页面信号
self.project_settings_page.settings_changed.connect(self.on_project_settings_changed)
# 项目管理器信号
self.project_manager.projects_changed.connect(self.update_project_count)
self.project_manager.projects_changed.connect(self.refresh_projects)
def center_window(self):
"""窗口居中"""
screen = QApplication.desktop().screenGeometry()
size = self.geometry()
self.move(
(screen.width() - size.width()) // 2,
(screen.height() - size.height()) // 2
)
def resizeEvent(self, event):
"""窗口大小变化事件"""
super().resizeEvent(event)
# 检查是否需要切换到紧凑模式
width = event.size().width()
should_be_compact = width < 1200
if should_be_compact != self.is_compact_mode:
self.is_compact_mode = should_be_compact
self.update_layout_mode()
def update_layout_mode(self):
"""更新布局模式"""
if self.is_compact_mode:
# 紧凑模式:缩小侧边栏
self.sidebar.setFixedWidth(240)
else:
# 正常模式:标准侧边栏宽度
self.sidebar.setFixedWidth(280)
def on_filter_changed(self, filter_type: str):
"""过滤器改变"""
self.current_filter = filter_type
self.refresh_projects()
def on_navigation_changed(self, section: str, item_name: str, filter_type: str):
"""导航变化处理"""
# 根据filter_type决定显示哪个页面
if filter_type == "project_settings":
# 切换到项目设置页面
self.stacked_widget.setCurrentIndex(1)
else:
# 切换到项目区域
self.stacked_widget.setCurrentIndex(0)
# 更新项目区域的面包屑导航和标题
self.project_area.update_navigation(section, item_name)
def on_search_changed(self, search_text: str):
"""搜索改变"""
self.current_search = search_text
self.refresh_projects()
def on_project_settings_changed(self):
"""项目设置变化处理"""
# 设置已更改,可以在这里处理相关逻辑
# 例如:更新创建项目对话框的默认位置
print("项目设置已更新")
def refresh_projects(self):
"""刷新项目显示"""
if self.current_search:
projects = self.project_manager.search_projects(self.current_search)
else:
projects = self.project_manager.get_projects_by_type(self.current_filter)
self.project_area.update_projects(projects)
def update_project_count(self):
"""更新项目数量"""
count = len(self.project_manager.get_all_projects())
# 如果状态栏存在,更新项目数量显示
if hasattr(self, 'project_count_label'):
self.project_count_label.setText(f"项目总数: {count}")
# 可以在这里添加其他更新逻辑,比如更新窗口标题
self.setWindowTitle(f"MetaCore - 项目管理平台 ({count} 个项目)")
def show_create_project_dialog(self):
"""显示创建项目对话框"""
dialog = CreateProjectDialog(self.project_manager, self.project_settings_page, self)
if dialog.exec_() == QDialog.Accepted:
self.refresh_projects()
def show_import_project_dialog(self):
"""显示导入项目对话框"""
dialog = ImportProjectDialog(self.project_manager, self.project_settings_page, self)
if dialog.exec_() == QDialog.Accepted:
self.refresh_projects()
def focus_search(self):
"""聚焦搜索框"""
self.project_area.focus_search()
def show_about(self):
"""显示关于对话框"""
QMessageBox.about(self, "关于 MetaCore",
"MetaCore 项目管理平台\n\n"
"版本: 1.0.0\n"
"基于 PyQt5 开发\n\n"
"© 2024 MetaCore Team")
def closeEvent(self, event):
"""关闭事件"""
reply = QMessageBox.question(self, '确认退出',
'确定要退出 MetaCore 吗?',
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
# 保存数据
self.project_manager.save_projects()
event.accept()
else:
event.ignore()

441
MetaCore/ui/project_area.py Normal file
View File

@ -0,0 +1,441 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
项目区域组件
"""
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from typing import List
from MetaCore.data.project_manager import ProjectManager, Project
from MetaCore.ui.icon_manager import IconManager
from MetaCore.ui.project_card import ProjectCard
class ProjectArea(QWidget):
"""项目区域组件"""
# 信号定义
search_changed = pyqtSignal(str)
create_project_requested = pyqtSignal()
import_project_requested = pyqtSignal()
def __init__(self, project_manager: ProjectManager):
super().__init__()
self.project_manager = project_manager
self.view_mode = "grid" # grid 或 list
self.projects = []
self.init_ui()
self.connect_signals()
# 初始加载项目
self.update_projects(self.project_manager.get_all_projects())
def init_ui(self):
"""初始化UI"""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 顶部工具栏
self.create_toolbar(layout)
# 搜索和过滤区域
self.create_search_filter_area(layout)
# 项目显示区域
self.create_project_display_area(layout)
def create_toolbar(self, layout):
"""创建顶部工具栏"""
toolbar_widget = QWidget()
toolbar_widget.setObjectName("toolbar")
toolbar_layout = QHBoxLayout(toolbar_widget)
toolbar_layout.setContentsMargins(30, 20, 30, 10)
# 面包屑导航容器
breadcrumb_container = QWidget()
breadcrumb_container.setObjectName("breadcrumbContainer")
breadcrumb_layout = QHBoxLayout(breadcrumb_container)
breadcrumb_layout.setContentsMargins(0, 0, 0, 0)
breadcrumb_layout.setSpacing(0)
self.home_label = QLabel("我的项目")
self.home_label.setObjectName("breadcrumbItem")
breadcrumb_layout.addWidget(self.home_label)
self.separator_label = QLabel("/")
self.separator_label.setObjectName("breadcrumbSeparator")
breadcrumb_layout.addWidget(self.separator_label)
self.current_label = QLabel("项目概述")
self.current_label.setObjectName("breadcrumbCurrent")
breadcrumb_layout.addWidget(self.current_label)
breadcrumb_layout.addStretch()
toolbar_layout.addWidget(breadcrumb_container)
# 右侧操作按钮
actions_layout = QHBoxLayout()
# 导入项目按钮
self.import_project_btn = QPushButton("导入项目")
if IconManager.icon_exists('import'):
self.import_project_btn.setIcon(IconManager.get_icon('import'))
else:
self.import_project_btn = QPushButton("↑ 导入项目")
self.import_project_btn.setObjectName("importBtn")
self.import_project_btn.clicked.connect(self.import_project_requested.emit)
actions_layout.addWidget(self.import_project_btn)
# 创建项目按钮
self.create_project_btn = QPushButton("创建")
if IconManager.icon_exists('create'):
self.create_project_btn.setIcon(IconManager.get_icon('create'))
else:
self.create_project_btn = QPushButton("+ 创建")
self.create_project_btn.setObjectName("primaryBtn")
self.create_project_btn.clicked.connect(self.create_project_requested.emit)
actions_layout.addWidget(self.create_project_btn)
toolbar_layout.addLayout(actions_layout)
layout.addWidget(toolbar_widget)
def create_search_filter_area(self, layout):
"""创建搜索和过滤区域"""
# 内容头部 - 调整高度更紧凑
content_header = QWidget()
content_header.setObjectName("contentHeader")
header_layout = QHBoxLayout(content_header)
header_layout.setContentsMargins(30, 12, 30, 12) # 减少上下边距20->12
# 标题
self.title_label = QLabel("项目概述")
self.title_label.setObjectName("contentTitle")
header_layout.addWidget(self.title_label)
header_layout.addStretch()
# 搜索输入框
self.search_input = QLineEdit()
self.search_input.setObjectName("searchInput")
self.search_input.setPlaceholderText("搜索项目...")
self.search_input.textChanged.connect(self.search_changed.emit)
self.search_input.setMaximumWidth(250) # 限制最大宽度
header_layout.addWidget(self.search_input)
# 视图控制按钮
view_controls = QHBoxLayout()
# 网格视图按钮
self.grid_view_btn = QPushButton()
if IconManager.icon_exists('grid_view'):
self.grid_view_btn.setIcon(IconManager.get_icon('grid_view', QSize(16, 16)))
self.grid_view_btn.setIconSize(QSize(16, 16))
else:
self.grid_view_btn.setText("")
self.grid_view_btn.setObjectName("viewBtn")
self.grid_view_btn.setCheckable(True)
self.grid_view_btn.setChecked(True)
self.grid_view_btn.setToolTip("网格视图")
self.grid_view_btn.clicked.connect(lambda: self.set_view_mode("grid"))
view_controls.addWidget(self.grid_view_btn)
# 列表视图按钮
self.list_view_btn = QPushButton()
if IconManager.icon_exists('list_view'):
self.list_view_btn.setIcon(IconManager.get_icon('list_view', QSize(16, 16)))
self.list_view_btn.setIconSize(QSize(16, 16))
else:
self.list_view_btn.setText("")
self.list_view_btn.setObjectName("viewBtn")
self.list_view_btn.setCheckable(True)
self.list_view_btn.setToolTip("列表视图")
self.list_view_btn.clicked.connect(lambda: self.set_view_mode("list"))
view_controls.addWidget(self.list_view_btn)
# # 过滤按钮
# filter_btn = QPushButton("▼")
# filter_btn.setObjectName("viewBtn")
# filter_btn.setToolTip("过滤选项")
# view_controls.addWidget(filter_btn)
header_layout.addLayout(view_controls)
layout.addWidget(content_header)
def create_project_display_area(self, layout):
"""创建项目显示区域"""
# 滚动区域
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# 项目容器
self.projects_container = QWidget()
self.projects_container.setObjectName("projectsContainer")
# 网格布局
self.projects_layout = QGridLayout(self.projects_container)
self.projects_layout.setContentsMargins(30, 20, 30, 30)
self.projects_layout.setSpacing(20)
self.projects_layout.setAlignment(Qt.AlignTop) # 设置顶部对齐
# 响应式列数
self.grid_columns = 4 # 默认列数
self.update_grid_columns()
self.scroll_area.setWidget(self.projects_container)
layout.addWidget(self.scroll_area)
def connect_signals(self):
"""连接信号"""
# 项目管理器信号
self.project_manager.project_added.connect(self.on_project_added)
self.project_manager.project_removed.connect(self.on_project_removed)
self.project_manager.project_updated.connect(self.on_project_updated)
def update_projects(self, projects: List[Project]):
"""更新项目显示"""
self.projects = projects
self.refresh_project_display()
def update_navigation(self, section: str, item_name: str):
"""更新导航显示"""
# 更新面包屑导航
self.home_label.setText(section)
self.current_label.setText(item_name)
# 更新主标题
# 根据不同的导航项设置不同的标题
title_mapping = {
"项目概述": "项目概述",
"项目管理": "项目管理",
"资源分类": "资源分类管理",
"资源管理": "资源管理",
"系统设置": "系统设置",
}
display_title = title_mapping.get(item_name, item_name)
self.title_label.setText(display_title)
def refresh_project_display(self):
"""刷新项目显示"""
# 清除现有项目卡片
for i in reversed(range(self.projects_layout.count())):
child = self.projects_layout.itemAt(i).widget()
if child:
child.setParent(None)
if not self.projects:
# 显示空状态
self.show_empty_state()
else:
# 添加项目卡片
if self.view_mode == "grid":
self.show_grid_view()
else:
self.show_list_view()
# 强制更新布局和几何信息
self._update_layout_geometry()
def show_grid_view(self):
"""显示网格视图"""
# 使用响应式列数
columns = self.grid_columns
for i, project in enumerate(self.projects):
row = i // columns
col = i % columns
project_card = ProjectCard(project, self.project_manager)
self.projects_layout.addWidget(project_card, row, col, Qt.AlignTop) # 顶部对齐
def show_list_view(self):
"""显示列表视图"""
for i, project in enumerate(self.projects):
project_card = ProjectCard(project, self.project_manager, view_mode="list")
self.projects_layout.addWidget(project_card, i, 0, Qt.AlignTop) # 顶部对齐
def show_empty_state(self):
"""显示空状态"""
empty_widget = QWidget()
empty_layout = QVBoxLayout(empty_widget)
empty_layout.setAlignment(Qt.AlignCenter)
# 空状态图标
empty_icon = QLabel("📁")
empty_icon.setStyleSheet("font-size: 48px; color: #666666;")
empty_icon.setAlignment(Qt.AlignCenter)
empty_layout.addWidget(empty_icon)
# 空状态文字
empty_text = QLabel("没有找到匹配的项目")
empty_text.setStyleSheet("font-size: 16px; color: #888888; margin-top: 10px;")
empty_text.setAlignment(Qt.AlignCenter)
empty_layout.addWidget(empty_text)
self.projects_layout.addWidget(empty_widget, 0, 0, 1, 4)
def set_view_mode(self, mode: str):
"""设置视图模式"""
self.view_mode = mode
# 更新按钮状态
self.grid_view_btn.setChecked(mode == "grid")
self.list_view_btn.setChecked(mode == "list")
# 刷新显示
self.refresh_project_display()
def focus_search(self):
"""聚焦搜索框"""
self.search_input.setFocus()
def on_project_added(self, project: Project):
"""项目添加事件"""
# 如果当前显示的是项目概述或项目管理,则添加新项目
if hasattr(self, 'current_filter') and self.current_filter in ["overview", "management"]:
self.projects.insert(0, project)
self.refresh_project_display()
def on_project_removed(self, project_id: int):
"""项目删除事件"""
self.projects = [p for p in self.projects if p.id != project_id]
self.refresh_project_display()
def on_project_updated(self, project: Project):
"""项目更新事件"""
for i, p in enumerate(self.projects):
if p.id == project.id:
self.projects[i] = project
break
self.refresh_project_display()
def update_grid_columns(self):
"""更新网格列数 - 针对固定大小卡片优化"""
# 获取可用宽度,尝试多种方式确保准确性
width = 0
if hasattr(self, 'scroll_area') and self.scroll_area.width() > 0:
# 优先使用滚动区域的宽度
width = self.scroll_area.viewport().width()
elif hasattr(self, 'projects_container') and self.projects_container.width() > 0:
# 备选:使用项目容器的宽度
width = self.projects_container.width()
elif hasattr(self, 'scroll_area'):
# 最后备选:使用滚动区域的宽度
width = self.scroll_area.width()
# 确保宽度有效
if width <= 0:
# 如果仍然无效,使用默认列数
if not hasattr(self, 'grid_columns'):
self.grid_columns = 1
return False
# 固定卡片大小的计算280px宽度20px间距
available_width = width - 60 # 减去左右边距
# 确保可用宽度为正数
if available_width <= 0:
available_width = width - 20 # 使用更小的边距
# 固定卡片宽度和间距
card_width = 280 # 固定卡片宽度
spacing = 20 # 卡片间距
# 计算能容纳的列数
if available_width < card_width:
columns = 1
else:
# 计算能容纳的列数:(可用宽度 + 间距) / (卡片宽度 + 间距)
columns = (available_width + spacing) // (card_width + spacing)
columns = max(1, columns)
# 限制最大列数,避免过多列
columns = min(columns, 6)
# 检查列数是否发生变化
old_columns = getattr(self, 'grid_columns', 4)
if old_columns != columns:
self.grid_columns = columns
return True # 返回True表示列数发生了变化
else:
self.grid_columns = columns
return False
def resizeEvent(self, event):
"""窗口大小变化事件"""
super().resizeEvent(event)
# 立即处理缩小情况,延迟处理放大情况
if hasattr(self, '_last_width'):
current_width = event.size().width()
is_shrinking = current_width < self._last_width
if is_shrinking:
# 缩小时立即处理,确保响应性
self._handle_resize()
self._last_width = current_width
return
# 延迟处理,避免频繁调用(主要用于放大情况)
if hasattr(self, '_resize_timer'):
self._resize_timer.stop()
self._resize_timer = QTimer()
self._resize_timer.setSingleShot(True)
self._resize_timer.timeout.connect(self._handle_resize)
self._resize_timer.start(50) # 减少延迟100ms->50ms
# 记录当前宽度
self._last_width = event.size().width()
def _handle_resize(self):
"""处理窗口大小变化"""
if hasattr(self, 'projects') and self.view_mode == "grid":
# 强制更新滚动区域几何信息
if hasattr(self, 'scroll_area'):
self.scroll_area.updateGeometry()
QApplication.processEvents()
# 更新列数
columns_changed = self.update_grid_columns()
if columns_changed:
# 列数变化,完全重新布局
self.refresh_project_display()
else:
# 列数没变,但仍需要更新布局以适应新的宽度
self._update_layout_geometry()
# 强制重新计算卡片大小
self._update_card_sizes()
def _update_layout_geometry(self):
"""更新布局几何信息"""
if hasattr(self, 'projects_container'):
# 强制更新布局
self.projects_container.updateGeometry()
self.projects_layout.update()
# 确保滚动区域正确更新
if hasattr(self, 'scroll_area'):
self.scroll_area.updateGeometry()
# 强制重新计算滚动区域大小
QApplication.processEvents()
self.scroll_area.ensureVisible(0, 0)
def _update_card_sizes(self):
"""更新项目卡片大小 - 固定大小卡片无需动态调整"""
# 由于卡片现在是固定大小(280x240),不再需要动态调整
# 这个方法保留为空,以保持接口兼容性
pass

974
MetaCore/ui/project_card.py Normal file
View File

@ -0,0 +1,974 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
项目卡片组件
"""
import os
import sys
import subprocess
import platform
from pathlib import Path
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from MetaCore.data.project_manager import ProjectManager, Project
from MetaCore.ui.icon_manager import IconManager
from MetaCore.ui.project_settings_page import ProjectSettingsPage
class ImageDisplayWidget(QWidget):
"""
一个专门用于显示带圆角图片的控件
它会自动将图片按比例缩放以覆盖整个区域并进行圆角裁剪
"""
def __init__(self, parent=None):
super().__init__(parent)
self.pixmap = QPixmap()
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
def setPixmap(self, pixmap):
self.pixmap = pixmap
self.update() # 触发重绘
# 这是在 ImageDisplayWidget 类内部的方法
def paintEvent(self, event):
if self.pixmap.isNull():
return
# 导入 QSize 以便创建新的尺寸对象
from PyQt5.QtCore import QSize
import math
target_rect = self.rect()
radius = 12.0
# “过缩放”逻辑保持不变,我们仍然需要一张比控件大的图片
overscale_factor = 1.05
original_size = target_rect.size()
larger_width = math.ceil(original_size.width() * overscale_factor)
larger_height = math.ceil(original_size.height() * overscale_factor)
larger_target_size = QSize(larger_width, larger_height)
scaled_pixmap = self.pixmap.scaled(larger_target_size, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
# --- 核心修正点在这里 ---
# 1. 计算绘制的起始坐标(x, y),以使 scaled_pixmap 的中心与控件中心对齐
# 由于 scaled_pixmap 比控件大,所以 x 和 y 通常是负数,这是正确的
draw_x = (target_rect.width() - scaled_pixmap.width()) / 2
draw_y = (target_rect.height() - scaled_pixmap.height()) / 2
# 2. 使用QPainter进行绘制
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# 3. 创建并设置圆角裁剪路径 (逻辑不变)
path = QPainterPath()
path.addRoundedRect(QRectF(target_rect), radius, radius)
painter.setClipPath(path)
# 4. 使用最简单的 drawPixmap 版本,直接在计算好的坐标点绘制
# 这个版本不会进行任何额外的缩放,完美解决了偏移问题
painter.drawPixmap(int(draw_x), int(draw_y), scaled_pixmap)
# -----------------------
class ProjectCard(QWidget):
"""项目卡片组件"""
def __init__(self, project: Project, project_manager: ProjectManager, view_mode: str = "grid"):
super().__init__()
self.project = project
self.project_manager = project_manager
self.view_mode = view_mode
self.project_settings_page = ProjectSettingsPage()
# 设置卡片对象名称和属性
self.setObjectName("projectCard")
self.setProperty("status", project.status)
self.setAttribute(Qt.WA_StyledBackground) # 关键:启用样式背景继承
# 设置尺寸和策略
if view_mode == "grid":
self.setFixedSize(280, 240)
else:
self.setFixedHeight(80)
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
self.init_ui()
self.connect_signals()
# 确保样式正确应用
self.update_style()
def update_style(self):
"""强制刷新样式"""
self.style().unpolish(self)
self.style().polish(self)
self.update()
def init_ui(self):
"""初始化UI"""
if self.view_mode == "grid":
self.create_grid_layout()
else:
self.create_list_layout()
def create_grid_layout(self):
"""创建网格布局"""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# 项目头部
self.create_project_header(layout)
# 项目图片
self.create_project_image(layout)
# 项目底部
self.create_project_footer(layout)
def create_list_layout(self):
"""创建列表布局"""
layout = QHBoxLayout(self)
layout.setContentsMargins(16, 12, 16, 12)
layout.setSpacing(16)
# 项目图标 - 使用优化的图标显示
self.create_list_project_icon(layout)
# 项目信息
info_layout = QVBoxLayout()
info_layout.setSpacing(4)
# 项目名称
title_layout = QHBoxLayout()
title_label = QLabel(self.project.title)
title_label.setObjectName("projectTitle")
title_layout.addWidget(title_label)
title_layout.addStretch()
info_layout.addLayout(title_layout)
# 项目日期
date_label = QLabel(self.project.date)
date_label.setObjectName("projectDate")
info_layout.addWidget(date_label)
layout.addLayout(info_layout)
layout.addStretch()
# 菜单按钮
self.create_menu_button(layout)
def create_project_header(self, layout):
"""创建项目头部"""
header_widget = QWidget()
header_widget.setObjectName("projectHeader")
header_layout = QHBoxLayout(header_widget)
header_layout.setContentsMargins(16, 16, 16, 8)
header_layout.setSpacing(8)
# 项目标题
title_label = QLabel(self.project.title)
title_label.setObjectName("projectTitle")
title_label.setWordWrap(True)
header_layout.addWidget(title_label, 1) # 添加拉伸因子
# 右侧操作区
actions_layout = QHBoxLayout()
actions_layout.setSpacing(4)
# 根据项目状态显示不同的按钮
if self.project.status == 'pending_delete':
self.menu_btn = QPushButton("")
self.menu_btn.setObjectName("deleteBtn")
self.menu_btn.setFixedSize(24, 24)
self.menu_btn.clicked.connect(self.confirm_delete_project)
self.menu_btn.setToolTip("确认删除项目")
else:
self.menu_btn = QPushButton("")
self.menu_btn.setObjectName("menuBtn")
self.menu_btn.setFixedSize(24, 24)
self.menu_btn.clicked.connect(self.show_context_menu)
self.menu_btn.setToolTip("项目操作菜单")
actions_layout.addWidget(self.menu_btn)
header_layout.addLayout(actions_layout)
layout.addWidget(header_widget)
def create_project_image(self, layout):
"""创建项目图片区域 - 最终版"""
import os
from PyQt5.QtWidgets import QStackedLayout # 导入 QStackedLayout
# image_container 是最外层的容器
image_container = QWidget()
image_container.setObjectName("projectImageContainer")
image_container.setContentsMargins(16, 0, 16, 0)
# image_widget 现在是堆叠布局的容器,它拥有灰色背景和圆角
image_widget = QWidget()
image_widget.setObjectName("projectImage")
# --- 使用 QStackedLayout 来切换两种状态 ---
stacked_layout = QStackedLayout(image_widget)
stacked_layout.setContentsMargins(0, 0, 0, 0)
# 状态一:显示图片 (使用我们自定义的控件)
image_display = ImageDisplayWidget()
# 注意:这里不需要给 image_display 设置 objectName 或样式,因为它只是一个“画布”
# 状态二:显示默认图标 (使用一个标准的 QLabel)
default_icon_label = QLabel("📁")
default_icon_label.setObjectName("projectIcon") # QSS 会应用到这里
default_icon_label.setAlignment(Qt.AlignCenter)
# 将两个状态控件添加到堆叠布局中
stacked_layout.addWidget(image_display) # 索引 0
stacked_layout.addWidget(default_icon_label) # 索引 1
# --- 根据条件切换显示 ---
if hasattr(self.project, 'image') and os.path.exists(self.project.image) and os.path.isfile(self.project.image):
# 如果图片存在...
pixmap = QPixmap(self.project.image)
image_display.setPixmap(pixmap)
stacked_layout.setCurrentIndex(0) # 显示图片控件
else:
# 如果图片不存在...
stacked_layout.setCurrentIndex(1) # 显示默认图标控件
# --- 最终布局 ---
# 我们只需要一个简单的 QVBoxLayout 来容纳 image_widget
container_layout = QVBoxLayout(image_container)
container_layout.setContentsMargins(0, 0, 0, 0)
container_layout.addWidget(image_widget)
layout.addWidget(image_container, 1)
def create_project_footer(self, layout):
"""创建项目底部"""
footer_widget = QWidget()
footer_widget.setObjectName("projectFooter")
footer_layout = QVBoxLayout(footer_widget)
footer_layout.setContentsMargins(16, 0, 16, 16) # 减少顶部边距
# 项目日期
date_label = QLabel(self.project.date)
date_label.setObjectName("projectDate")
date_label.setAlignment(Qt.AlignCenter)
footer_layout.addWidget(date_label)
layout.addWidget(footer_widget)
def create_menu_button(self, layout):
"""创建菜单按钮(用于列表视图)"""
self.menu_btn = QPushButton("")
self.menu_btn.setObjectName("menuBtn")
self.menu_btn.setFixedSize(32, 32)
self.menu_btn.clicked.connect(self.show_context_menu)
layout.addWidget(self.menu_btn)
def create_list_project_icon(self, layout):
"""创建列表视图中的项目图标"""
import os
from PyQt5.QtWidgets import QStackedLayout
# 图标容器
icon_container = QWidget()
icon_container.setObjectName("listProjectIconContainer")
icon_container.setFixedSize(48, 48) # 列表视图中使用较小的图标
# 图标控件 - 带圆角背景
icon_widget = QWidget()
icon_widget.setObjectName("listProjectIcon")
icon_widget.setProperty("status", self.project.status) # 设置状态属性
# 使用堆叠布局来切换图片和默认图标
stacked_layout = QStackedLayout(icon_widget)
stacked_layout.setContentsMargins(0, 0, 0, 0)
# 状态一:显示图片 (使用自定义的圆角图片控件)
image_display = ListImageDisplayWidget()
# 状态二:显示默认图标
default_icon_label = QLabel("📁")
default_icon_label.setObjectName("listProjectDefaultIcon")
default_icon_label.setAlignment(Qt.AlignCenter)
# 添加到堆叠布局
stacked_layout.addWidget(image_display) # 索引 0
stacked_layout.addWidget(default_icon_label) # 索引 1
# 根据条件切换显示
if hasattr(self.project, 'image') and self.project.image and os.path.exists(self.project.image) and os.path.isfile(self.project.image):
# 如果图片存在,显示图片
pixmap = QPixmap(self.project.image)
if not pixmap.isNull():
image_display.setPixmap(pixmap)
stacked_layout.setCurrentIndex(0)
else:
stacked_layout.setCurrentIndex(1)
else:
# 如果图片不存在,显示默认图标
stacked_layout.setCurrentIndex(1)
# 容器布局
container_layout = QVBoxLayout(icon_container)
container_layout.setContentsMargins(0, 0, 0, 0)
container_layout.addWidget(icon_widget)
layout.addWidget(icon_container)
def get_type_label(self):
"""获取项目类型标签"""
type_labels = {
'industrial': '工业',
'smart': '智能',
'vr': 'VR',
'game': '游戏',
'design': '设计'
}
return type_labels.get(self.project.type, '其他')
def show_context_menu(self):
"""显示右键菜单"""
menu = QMenu(self)
# 刷新预览图
if IconManager.icon_exists("Refresh"):
refresh_action = menu.addAction(IconManager.get_icon('Refresh'), "刷新预览图")
else:
refresh_action = menu.addAction("🔄 刷新预览图")
refresh_action.triggered.connect(self.refresh_preview_image)
menu.addSeparator()
# 在资源管理器显示
if IconManager.icon_exists('folder'):
show_in_explorer_action = menu.addAction(IconManager.get_icon('folder'), "在资源管理器显示")
else:
show_in_explorer_action = menu.addAction("📁 在资源管理器显示")
show_in_explorer_action.triggered.connect(self.show_in_explorer)
menu.addSeparator()
# 删除项目
if IconManager.icon_exists('delete'):
delete_action = menu.addAction(IconManager.get_icon('delete'), "移除项目")
else:
delete_action = menu.addAction("🗑️ 移除项目")
delete_action.triggered.connect(self.delete_project)
# 显示菜单
menu.exec_(self.menu_btn.mapToGlobal(self.menu_btn.rect().bottomLeft()))
def open_project(self):
"""打开项目"""
try:
# 优先使用项目目录路径,如果不存在则使用基础路径
project_path = self.project.project_dir if self.project.project_dir else self.project.path
# 使用项目管理器的验证方法进行全面检查
is_valid, error_message = self.project_manager.validate_project_open(project_path)
if not is_valid:
QMessageBox.warning(self, "无法打开项目", f"项目无法打开: {error_message}")
return
# 验证通过,显示成功信息
# QMessageBox.information(self, "打开项目", f"正在打开项目: {self.project.title}")
# 使用question对话框提供明确的确认选项
reply = QMessageBox.question(self, "打开项目",
f"确定要打开项目: {self.project.title}?",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes)
if reply == QMessageBox.Yes:
# 用户确认打开项目,继续执行打开逻辑
# TODO: 在这里添加实际的项目打开逻辑
print(f"正在打开项目路径: {project_path},正在启动应用程序: {self.project.title}")
# 连接信号
self.project_manager.pycharm_started.connect(self.on_pycharm_started)
self.project_manager.project_method_called.connect(self.on_project_method_called)
# # 启动PyCharm并调用项目方法
# # 修正参数顺序:
# # 第一个参数要在PyCharm中打开的项目路径EG项目
# # 第二个参数:要传递给项目方法的目标项目路径(当前项目)
success = self.project_manager.run_project_command(
self.project_settings_page.get_default_open_location(),
# "/home/tiger/文档/EG", # project_path - 要在PyCharm中打开的项目
project_path # target_project_path - 要传递给项目方法的目标项目路径
)
if not success:
QMessageBox.warning(
self,
"启动失败",
"无法启动,请检查打开项目路径。"
)
# if success:
# QMessageBox.information(
# self,
# "启动PyCharm",
# f"正在启动PyCharm并准备调用项目方法...\n目标项目: {project_path}"
# )
# else:
# QMessageBox.warning(
# self,
# "启动失败",
# "无法启动PyCharm请检查PyCharm安装。"
# )
else:
# 用户取消操作,直接返回
return
# success = self.project_manager.launch_pycharm_and_open_project(
# "/home/tiger/文档/EG", # project_path - 要在PyCharm中打开的项目
# project_path # target_project_path - 要传递给项目方法的目标项目路径
# )
# if success:
# QMessageBox.information(
# self,
# "启动PyCharm",
# f"正在启动PyCharm并准备调用项目方法...\n目标项目: {project_path}"
# )
# else:
# QMessageBox.warning(
# self,
# "启动失败",
# "无法启动PyCharm请检查PyCharm安装。"
# )
# self.project_manager.open_app_if_not_running(f'{project_path}/project.json', "project.json")
# self.project_manager.open_project_in_pycharm(project_path)
# except Exception as e:
# QMessageBox.critical(self, "错误", f"打开项目时发生错误:\n{str(e)}")
except Exception as e:
QMessageBox.critical(self, "错误", f"启动PyCharm时发生错误:\n{str(e)}")
def on_pycharm_started(self):
"""PyCharm启动完成回调"""
print("PyCharm has started and is ready")
def on_project_method_called(self, target_project_path):
"""项目方法调用完成回调"""
QMessageBox.information(
self,
"操作完成",
f"已成功在PyCharm中打开项目: {target_project_path}"
)
def show_in_explorer(self):
"""在资源管理器中显示项目目录"""
try:
# 获取项目路径并规范化
project_path_str = self.project.project_dir if self.project.project_dir else self.project.path
if not project_path_str:
QMessageBox.warning(self, "路径不存在", "项目路径为空,请检查项目配置。")
return
# 使用pathlib处理路径
project_path = Path(project_path_str).resolve()
print(f"项目ID: {self.project.id}")
print(f"项目标题: {self.project.title}")
print(f"最终使用的路径: '{project_path}'")
print(f"路径是否存在: {project_path.exists()}")
print(f"是否为目录: {project_path.is_dir()}")
# 检查项目路径是否存在
if not project_path.exists():
QMessageBox.warning(self, "路径不存在",
f"项目路径不存在或无效:\n{project_path}\n\n请检查项目是否已被移动或删除。")
return
# 获取操作系统类型
system = platform.system().lower()
if system == "windows":
try:
# Windows使用os.startfile会自动使用系统默认的文件管理器
os.startfile(str(project_path))
except OSError as e:
QMessageBox.critical(self, "打开失败", f"无法打开资源管理器:\n{str(e)}")
elif system == "darwin": # macOS
if project_path.is_file():
# 如果是文件,选中该文件
subprocess.run(['open', '-R', str(project_path)], check=True)
else:
# 如果是目录,直接打开
subprocess.run(['open', str(project_path)], check=True)
else: # Linux和其他Unix系统
try:
# 首先尝试使用nautilusGNOME文件管理器
subprocess.run(['nautilus', str(project_path)], check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
try:
# 尝试使用dolphin (KDE)
subprocess.run(['dolphin', str(project_path)], check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
try:
# 尝试使用thunar (XFCE)
subprocess.run(['thunar', str(project_path)], check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
try:
# 最后尝试使用xdg-open
subprocess.run(['xdg-open', str(project_path)], check=True)
except (FileNotFoundError, subprocess.CalledProcessError):
QMessageBox.warning(self, "无法打开文件管理器",
"系统中没有找到合适的文件管理器。\n"
f"请手动打开路径: {project_path}")
print(f"成功在资源管理器中打开: {project_path}")
except subprocess.CalledProcessError as e:
QMessageBox.critical(self, "打开失败",
f"无法打开资源管理器:\n{str(e)}")
except Exception as e:
QMessageBox.critical(self, "错误",
f"打开资源管理器时发生错误:\n{str(e)}")
def delete_project(self):
"""删除项目"""
reply = QMessageBox.question(self, "确认移除",
f"确定要移除项目 \"{self.project.title}\" 吗?\n此操作不可撤销。",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
self.project_manager.remove_project(self.project.id)
def confirm_delete_project(self):
"""确认删除待删除状态的项目"""
reply = QMessageBox.question(self, "确认删除项目",
f"确定要永久删除项目 \"{self.project.title}\" 吗?\n"
f"此操作不可撤销。\n\n"
f"提示:如果项目目录已恢复,您可以点击项目卡片来恢复项目。",
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
self.project_manager.confirm_delete_project(self.project.id)
def update_display(self):
"""更新显示"""
# 更新项目状态属性
self.setProperty("status", self.project.status)
# 重新创建UI以反映更改
for i in reversed(range(self.layout().count())):
child = self.layout().itemAt(i).widget()
if child:
child.setParent(None)
self.init_ui()
# 强制刷新样式
self.style().unpolish(self)
self.style().polish(self)
self.update()
def apply_fallback_styles(self):
"""应用备用样式,确保卡片有正确的外观"""
# 直接设置卡片的内联样式
card_style = """
QWidget#projectCard {
background-color: #4a4a5a;
border: 1px solid #5a5a6a;
border-radius: 16px;
}
QWidget#projectCard:hover {
background-color: #5a5a6a;
border-color: #6a6a7a;
}
"""
self.setStyleSheet(card_style)
def connect_signals(self):
"""连接信号"""
pass
def mousePressEvent(self, event):
"""鼠标点击事件"""
if event.button() == Qt.LeftButton:
# 检查是否点击了菜单按钮
if not self.menu_btn.geometry().contains(event.pos()):
if self.project.status == 'pending_delete':
# 待删除状态的项目,尝试恢复
self.try_restore_project()
else:
# 正常状态的项目,打开项目
self.open_project()
super().mousePressEvent(event)
def try_restore_project(self):
"""尝试恢复待删除状态的项目"""
if self.project_manager.restore_project(self.project.id):
QMessageBox.information(self, "项目已恢复",
f"项目 \"{self.project.title}\" 已成功恢复!")
else:
QMessageBox.information(self, "项目目录不存在",
f"项目 \"{self.project.title}\" 的目录仍然不存在:\n{self.project.project_dir}\n\n"
f"提示:当您恢复项目目录后,系统会自动检测并恢复项目状态,无需手动操作。")
def enterEvent(self, event):
"""鼠标进入事件"""
self.setProperty("hover", True)
self.style().unpolish(self)
self.style().polish(self)
# 强制重绘以确保悬停效果立即生效
self.update()
super().enterEvent(event)
def leaveEvent(self, event):
"""鼠标离开事件"""
self.setProperty("hover", False)
self.style().unpolish(self)
self.style().polish(self)
# 强制重绘以确保悬停效果立即消失
self.update()
super().leaveEvent(event)
def show_success_tooltip(self, message):
"""显示成功提示工具提示"""
# 临时改变菜单按钮的工具提示来显示成功状态
original_tooltip = self.menu_btn.toolTip()
self.menu_btn.setToolTip(f"{message}")
# 使用定时器恢复原状态
QTimer.singleShot(3000, lambda: self.restore_button_state(original_tooltip))
def restore_button_state(self, original_tooltip):
"""恢复按钮原始状态"""
self.menu_btn.setToolTip(original_tooltip)
def refresh_preview_image(self):
"""刷新预览图"""
try:
# 获取项目路径
project_path = self.project.project_dir if self.project.project_dir else self.project.path
if not project_path or not Path(project_path).exists():
QMessageBox.warning(self, "路径不存在", "项目路径不存在,无法生成预览图。")
return
# 显示进度提示
original_tooltip = self.menu_btn.toolTip()
self.menu_btn.setEnabled(False)
self.menu_btn.setToolTip("⏳ 正在生成预览图...")
QApplication.processEvents()
# 生成新的预览图
preview_path = self.generate_project_preview(project_path)
if preview_path and Path(preview_path).exists():
# 清理旧的预览图
self.project_manager.cleanup_old_preview_images(self.project.id)
# 更新项目的图片路径
old_image = self.project.image
self.project.image = preview_path
self.project_manager.update_project(self.project)
# 刷新显示
self.refresh_image_display()
# 显示成功提示(不使用阻塞对话框)
self.show_success_tooltip("预览图已刷新!")
# 如果有旧图片且不同于新图片,尝试删除
if old_image and old_image != preview_path and Path(old_image).exists():
try:
# 检查是否是我们生成的预览图
if "ProjectPreviews" in old_image:
Path(old_image).unlink()
except Exception:
pass # 忽略删除失败
else:
QMessageBox.warning(self, "生成失败",
"无法生成预览图。\n\n可能原因:\n"
"• 项目目录中没有图片文件\n"
"• 图片文件格式不支持\n"
"• 权限不足")
except Exception as e:
QMessageBox.critical(self, "错误", f"刷新预览图时发生错误:\n{str(e)}")
finally:
# 恢复按钮状态
self.menu_btn.setEnabled(True)
self.menu_btn.setToolTip(original_tooltip)
def generate_project_preview(self, project_path):
"""生成项目预览图"""
try:
project_path = Path(project_path)
# 查找项目中的图片文件
image_extensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff', '.webp']
found_images = []
# 搜索常见的图片目录
search_dirs = [
project_path,
project_path / 'images',
project_path / 'img',
project_path / 'assets',
project_path / 'static',
project_path / 'resources',
project_path / 'media',
project_path / 'screenshots',
project_path / 'preview'
]
for search_dir in search_dirs:
if search_dir.exists() and search_dir.is_dir():
for ext in image_extensions:
found_images.extend(search_dir.glob(f'*{ext}'))
found_images.extend(search_dir.glob(f'*{ext.upper()}'))
# 递归搜索子目录(限制深度)
found_images.extend(search_dir.glob(f'*/*{ext}'))
found_images.extend(search_dir.glob(f'*/*{ext.upper()}'))
if not found_images:
return self.create_default_preview(project_path)
# 优先选择特定名称的图片
priority_names = ['preview', 'screenshot', 'main', 'cover', 'thumbnail', 'icon']
selected_image = None
for priority_name in priority_names:
for img_path in found_images:
if priority_name in img_path.stem.lower():
selected_image = img_path
break
if selected_image:
break
# 如果没有找到优先图片,选择第一个
if not selected_image:
selected_image = found_images[0]
# 创建预览图存储目录
preview_dir = Path.cwd() / 'MetaCore' / 'Resources' / 'ProjectPreviews'
preview_dir.mkdir(parents=True, exist_ok=True)
# 生成预览图文件名
preview_filename = f"preview_{self.project.id}_{int(QDateTime.currentMSecsSinceEpoch())}.png"
preview_path = preview_dir / preview_filename
# 处理图片并保存预览图
original_pixmap = QPixmap(str(selected_image))
if not original_pixmap.isNull():
# 缩放到合适的预览尺寸
preview_size = QSize(400, 300)
scaled_pixmap = original_pixmap.scaled(
preview_size,
Qt.KeepAspectRatioByExpanding,
Qt.SmoothTransformation
)
# 裁剪到目标尺寸
if scaled_pixmap.size() != preview_size:
x = (scaled_pixmap.width() - preview_size.width()) // 2
y = (scaled_pixmap.height() - preview_size.height()) // 2
scaled_pixmap = scaled_pixmap.copy(x, y, preview_size.width(), preview_size.height())
# 保存预览图
if scaled_pixmap.save(str(preview_path), 'PNG'):
return str(preview_path)
return self.create_default_preview(project_path)
except Exception as e:
print(f"生成预览图时发生错误: {e}")
return self.create_default_preview(project_path)
def create_default_preview(self, project_path):
"""创建默认预览图"""
try:
# 创建预览图存储目录
preview_dir = Path.cwd() / 'MetaCore' / 'Resources' / 'ProjectPreviews'
preview_dir.mkdir(parents=True, exist_ok=True)
# 生成默认预览图文件名
preview_filename = f"default_preview_{self.project.id}.png"
preview_path = preview_dir / preview_filename
# 创建一个带有项目信息的默认预览图
pixmap = QPixmap(400, 300)
pixmap.fill(QColor(70, 70, 80)) # 深灰色背景
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.Antialiasing)
# 设置字体
font = QFont("微软雅黑", 16, QFont.Bold)
painter.setFont(font)
painter.setPen(QColor(255, 255, 255))
# 绘制项目名称
title_rect = QRect(20, 100, 360, 40)
painter.drawText(title_rect, Qt.AlignCenter | Qt.TextWordWrap, self.project.title)
# 绘制项目类型
type_font = QFont("微软雅黑", 12)
painter.setFont(type_font)
painter.setPen(QColor(200, 200, 200))
type_rect = QRect(20, 150, 360, 30)
type_text = self.get_type_label()
painter.drawText(type_rect, Qt.AlignCenter, f"项目类型: {type_text}")
# 绘制创建日期
date_rect = QRect(20, 180, 360, 30)
painter.drawText(date_rect, Qt.AlignCenter, f"创建时间: {self.project.date}")
# 绘制文件夹图标
icon_font = QFont("Segoe UI Emoji", 48)
painter.setFont(icon_font)
painter.setPen(QColor(150, 150, 150))
icon_rect = QRect(20, 30, 360, 60)
painter.drawText(icon_rect, Qt.AlignCenter, "📁")
painter.end()
# 保存预览图
if pixmap.save(str(preview_path), 'PNG'):
return str(preview_path)
except Exception as e:
print(f"创建默认预览图时发生错误: {e}")
return None
def refresh_image_display(self):
"""刷新图片显示"""
try:
# 更新网格视图中的图片显示
if self.view_mode == "grid":
self.update_grid_image_display()
else:
self.update_list_image_display()
except Exception as e:
print(f"刷新图片显示时发生错误: {e}")
def update_grid_image_display(self):
"""更新网格视图中的图片显示"""
# 找到图片容器
for i in range(self.layout().count()):
widget = self.layout().itemAt(i).widget()
if widget and widget.objectName() == "projectImageContainer":
# 找到内部的堆叠布局
for j in range(widget.layout().count()):
image_widget = widget.layout().itemAt(j).widget()
if image_widget and image_widget.objectName() == "projectImage":
stacked_layout = image_widget.layout()
if isinstance(stacked_layout, QStackedLayout):
# 获取图片显示控件
image_display = stacked_layout.widget(0)
if isinstance(image_display, ImageDisplayWidget):
# 检查是否有新的图片文件
if (hasattr(self.project, 'image') and
self.project.image and
os.path.exists(self.project.image) and
os.path.isfile(self.project.image)):
# 重新加载图片
pixmap = QPixmap(self.project.image)
if not pixmap.isNull():
image_display.setPixmap(pixmap)
stacked_layout.setCurrentIndex(0)
else:
stacked_layout.setCurrentIndex(1)
else:
stacked_layout.setCurrentIndex(1)
break
def update_list_image_display(self):
"""更新列表视图中的图片显示"""
# 在列表视图中查找并更新图片显示
for i in range(self.layout().count()):
widget = self.layout().itemAt(i).widget()
if widget and widget.objectName() == "listProjectIconContainer":
# 找到内部的堆叠布局
for j in range(widget.layout().count()):
icon_widget = widget.layout().itemAt(j).widget()
if icon_widget and icon_widget.objectName() == "listProjectIcon":
stacked_layout = icon_widget.layout()
if isinstance(stacked_layout, QStackedLayout):
# 获取图片显示控件
image_display = stacked_layout.widget(0)
if isinstance(image_display, ListImageDisplayWidget):
# 检查是否有新的图片文件
if (hasattr(self.project, 'image') and
self.project.image and
os.path.exists(self.project.image) and
os.path.isfile(self.project.image)):
# 重新加载图片
pixmap = QPixmap(self.project.image)
if not pixmap.isNull():
image_display.setPixmap(pixmap)
stacked_layout.setCurrentIndex(0)
else:
stacked_layout.setCurrentIndex(1)
else:
stacked_layout.setCurrentIndex(1)
break
class ListImageDisplayWidget(QWidget):
"""
专门用于列表视图的圆角图片显示控件
尺寸较小适合列表视图
"""
def __init__(self, parent=None):
super().__init__(parent)
self.pixmap = QPixmap()
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
def setPixmap(self, pixmap):
self.pixmap = pixmap
self.update()
def paintEvent(self, event):
if self.pixmap.isNull():
return
from PyQt5.QtCore import QSize
import math
target_rect = self.rect()
radius = 8.0 # 列表视图使用较小的圆角
# 过缩放因子
overscale_factor = 1.05
original_size = target_rect.size()
larger_width = math.ceil(original_size.width() * overscale_factor)
larger_height = math.ceil(original_size.height() * overscale_factor)
larger_target_size = QSize(larger_width, larger_height)
scaled_pixmap = self.pixmap.scaled(larger_target_size, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
# 计算绘制的起始坐标,使图片居中
draw_x = (target_rect.width() - scaled_pixmap.width()) / 2
draw_y = (target_rect.height() - scaled_pixmap.height()) / 2
# 绘制
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# # 创建圆角裁剪路径
# path = QPainterPath()
# path.addRoundedRect(QRectF(target_rect), radius, radius)
# painter.setClipPath(path)
# 绘制图片
painter.drawPixmap(int(draw_x), int(draw_y), scaled_pixmap)

View File

@ -0,0 +1,328 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
项目设置页面组件
这个页面允许用户配置项目相关的设置包括
- 默认项目创建位置
- 项目模板设置
- 项目命名规则
- 其他项目相关配置
"""
import os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class ProjectSettingsPage(QWidget):
"""
项目设置页面
提供项目相关的配置选项主要包括默认项目位置的设置
"""
# 信号定义
settings_changed = pyqtSignal() # 设置发生变化时发出
def __init__(self):
super().__init__()
self.settings = QSettings("MetaCore", "ProjectManager") # 用于保存设置
self.init_ui()
self.load_settings()
def init_ui(self):
"""初始化用户界面"""
layout = QVBoxLayout(self)
layout.setContentsMargins(30, 30, 30, 30)
layout.setSpacing(20)
# 页面标题
self.create_page_header(layout)
# 默认项目位置设置
self.create_default_location_section(layout)
self.create_open_location_section(layout)
# 项目创建设置
# self.create_project_creation_section(layout)
# 按钮区域
self.create_button_section(layout)
# 添加弹性空间
layout.addStretch()
def create_page_header(self, layout):
"""创建页面标题"""
header_widget = QWidget()
header_layout = QVBoxLayout(header_widget)
header_layout.setContentsMargins(0, 0, 0, 0)
header_layout.setSpacing(8)
# 主标题
title_label = QLabel("项目设置")
title_label.setObjectName("pageTitle")
header_layout.addWidget(title_label)
# 副标题
subtitle_label = QLabel("配置项目创建和管理的相关设置")
subtitle_label.setObjectName("pageSubtitle")
header_layout.addWidget(subtitle_label)
layout.addWidget(header_widget)
def create_default_location_section(self, layout):
"""创建默认项目位置设置区域"""
# 分组框
group_box = QGroupBox("默认项目位置")
group_box.setObjectName("settingsGroup")
group_layout = QVBoxLayout(group_box)
group_layout.setSpacing(15)
# 说明文字
desc_label = QLabel("设置新项目的默认创建位置。")
desc_label.setObjectName("settingsDescription")
desc_label.setWordWrap(True)
group_layout.addWidget(desc_label)
# 当前路径显示和选择
path_widget = QWidget()
path_layout = QHBoxLayout(path_widget)
path_layout.setContentsMargins(0, 0, 0, 0)
path_layout.setSpacing(10)
# 路径输入框
self.path_input = QLineEdit()
self.path_input.setObjectName("pathInput")
self.path_input.setPlaceholderText("选择默认项目创建位置...")
self.path_input.setReadOnly(True) # 只读,通过按钮选择
path_layout.addWidget(self.path_input)
# 浏览按钮
self.browse_btn = QPushButton("浏览...")
self.browse_btn.setObjectName("browseBtn")
self.browse_btn.clicked.connect(self.browse_default_location)
path_layout.addWidget(self.browse_btn)
# 重置按钮
self.reset_btn = QPushButton("重置")
self.reset_btn.setObjectName("resetBtn")
self.reset_btn.clicked.connect(self.reset_default_location)
path_layout.addWidget(self.reset_btn)
group_layout.addWidget(path_widget)
layout.addWidget(group_box)
def create_open_location_section(self, layout):
"""创建打开位置设置区域"""
# 分组框
group_box = QGroupBox("打开位置")
group_box.setObjectName("settingsGroup")
group_layout = QVBoxLayout(group_box)
group_layout.setSpacing(15)
# 说明文字
desc_label = QLabel("设置项目文件的默认打开位置。")
desc_label.setObjectName("settingsDescription")
desc_label.setWordWrap(True)
group_layout.addWidget(desc_label)
# 当前路径显示和选择
path_widget = QWidget()
path_layout = QHBoxLayout(path_widget)
path_layout.setContentsMargins(0, 0, 0, 0)
path_layout.setSpacing(10)
# 路径输入框
self.open_path_input = QLineEdit()
self.open_path_input.setObjectName("pathInput")
self.open_path_input.setPlaceholderText("选择默认项目打开位置...")
self.open_path_input.setReadOnly(True) # 只读,通过按钮选择
path_layout.addWidget(self.open_path_input)
# 浏览按钮
self.open_browse_btn = QPushButton("浏览...")
self.open_browse_btn.setObjectName("browseBtn")
self.open_browse_btn.clicked.connect(self.browse_open_location)
path_layout.addWidget(self.open_browse_btn)
# 重置按钮
self.open_reset_btn = QPushButton("重置")
self.open_reset_btn.setObjectName("resetBtn")
self.open_reset_btn.clicked.connect(self.reset_open_location)
path_layout.addWidget(self.open_reset_btn)
group_layout.addWidget(path_widget)
layout.addWidget(group_box)
def browse_open_location(self):
"""浏览选择打开位置"""
current_path = self.open_path_input.text() or self.get_default_projects_path()
folder = QFileDialog.getExistingDirectory(
self,
"选择默认项目打开位置",
current_path
)
if folder:
self.open_path_input.setText(folder)
# 可以根据需要添加保存逻辑
self.save_settings_immediately("default_open_location", self.open_path_input.text())
def reset_open_location(self):
"""重置为默认打开位置"""
default_path = self.get_default_projects_path()
self.open_path_input.setText(default_path)
def create_project_creation_section(self, layout):
"""创建项目创建设置区域"""
# 分组框
group_box = QGroupBox("项目创建设置")
group_box.setObjectName("settingsGroup")
group_layout = QVBoxLayout(group_box)
group_layout.setSpacing(15)
# 自动打开项目文件夹选项
self.auto_open_checkbox = QCheckBox("创建项目后自动打开项目文件夹")
self.auto_open_checkbox.setObjectName("settingsCheckbox")
group_layout.addWidget(self.auto_open_checkbox)
# 创建README文件选项
self.create_readme_checkbox = QCheckBox("自动创建 README.md 文件")
self.create_readme_checkbox.setObjectName("settingsCheckbox")
self.create_readme_checkbox.setChecked(True) # 默认选中
group_layout.addWidget(self.create_readme_checkbox)
# 创建.gitignore文件选项
self.create_gitignore_checkbox = QCheckBox("自动创建 .gitignore 文件")
self.create_gitignore_checkbox.setObjectName("settingsCheckbox")
group_layout.addWidget(self.create_gitignore_checkbox)
layout.addWidget(group_box)
def create_button_section(self, layout):
"""创建按钮区域(已移除,路径选择后自动保存)"""
# 不再需要按钮区域,路径选择后自动保存
pass
def get_default_projects_path(self):
"""获取默认项目目录路径"""
# 获取当前文件所在目录的上级目录(项目根目录)
# current_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# return os.path.join(current_dir, "MetaCore_Projects")
current_dir = ''
return current_dir
def browse_default_location(self):
"""浏览选择默认位置"""
current_path = self.path_input.text() or self.get_default_projects_path()
folder = QFileDialog.getExistingDirectory(
self,
"选择默认项目创建位置",
current_path
)
if folder:
self.path_input.setText(folder)
# 路径选择后立即保存设置
self.save_settings_immediately("default_project_location", self.path_input.text())
def reset_default_location(self):
"""重置为默认位置"""
default_path = self.get_default_projects_path()
self.path_input.setText(default_path)
def load_settings(self):
"""加载保存的设置"""
# 加载默认项目位置
default_path = self.settings.value(
"default_project_location",
self.get_default_projects_path()
)
self.path_input.setText(default_path)
default_open_path = self.settings.value(
"default_open_location",
self.get_default_projects_path()
)
self.open_path_input.setText(default_open_path)
# 加载其他设置
# self.auto_open_checkbox.setChecked(
# self.settings.value("auto_open_folder", False, type=bool)
# )
# self.create_readme_checkbox.setChecked(
# self.settings.value("create_readme", True, type=bool)
# )
# self.create_gitignore_checkbox.setChecked(
# self.settings.value("create_gitignore", False, type=bool)
# )
def save_settings_immediately(self, key, value):
"""立即保存设置(路径选择后自动调用)"""
# 保存默认项目位置
self.settings.setValue(key, value)
# 确保设置被保存
self.settings.sync()
# 发出设置变化信号
self.settings_changed.emit()
# 显示简短的成功提示(可选)
# QMessageBox.information(self, "设置已保存", "默认项目位置已更新!")
# def apply_settings(self):
# """应用设置(保留方法以防其他地方调用)"""
# self.save_settings_immediately()
#
# # 显示成功消息
# QMessageBox.information(self, "设置已保存", "项目设置已成功保存!")
#
# def restore_defaults(self):
# """恢复默认设置(已移除按钮,保留方法以防其他地方调用)"""
# reply = QMessageBox.question(
# self,
# "恢复默认设置",
# "确定要恢复所有设置为默认值吗?",
# QMessageBox.Yes | QMessageBox.No,
# QMessageBox.No
# )
#
# if reply == QMessageBox.Yes:
# # 恢复默认值
# self.path_input.setText(self.get_default_projects_path())
#
# # 立即保存恢复的设置
# self.save_settings_immediately()
#
# QMessageBox.information(self, "恢复完成", "已恢复默认设置!")
def get_default_project_location(self):
"""获取默认项目位置"""
return self.settings.value(
"default_project_location",
self.get_default_projects_path()
)
def get_default_open_location(self):
"""获取默认项目位置"""
return self.settings.value(
"default_open_location",
self.get_default_projects_path()
)
# def get_project_creation_settings(self):
# """获取项目创建设置"""
# return {
# 'auto_open_folder': self.settings.value("auto_open_folder", False, type=bool),
# 'create_readme': self.settings.value("create_readme", True, type=bool),
# 'create_gitignore': self.settings.value("create_gitignore", False, type=bool),
# }

283
MetaCore/ui/sidebar.py Normal file
View File

@ -0,0 +1,283 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
侧边栏组件
"""
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from MetaCore.data.project_manager import ProjectManager
from MetaCore.ui.icon_manager import IconManager
class Sidebar(QWidget):
"""侧边栏组件"""
# 信号定义
filter_changed = pyqtSignal(str)
navigation_changed = pyqtSignal(str, str, str) # 新增信号:(section, item_name, filter_type)
create_project_requested = pyqtSignal()
import_project_requested = pyqtSignal()
def __init__(self, project_manager: ProjectManager):
super().__init__()
self.project_manager = project_manager
self.current_filter = "overview"
# 导航项映射filter_type -> (section, item_name)
self.nav_mapping = {
"overview": ("我的项目", "项目概述"),
"management": ("我的项目", "项目管理"),
"resource_category": ("资源管理", "资源分类"),
"resource_management": ("资源管理", "资源管理"),
"project_settings": ("设置中心", "项目设置"),
"system_settings": ("设置中心", "系统设置"),
}
self.init_ui()
self.connect_signals()
# 设置固定宽度
self.setFixedWidth(280)
def init_ui(self):
"""初始化UI"""
layout = QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
# Logo区域
self.create_logo_section(layout)
# 快速操作区域
self.create_quick_actions(layout)
# 导航菜单
self.create_navigation_menu(layout)
# 底部用户信息
# layout.addStretch()
# self.create_user_info(layout)
def create_logo_section(self, layout):
"""创建Logo区域"""
logo_widget = QWidget()
logo_widget.setObjectName("logoWidget")
logo_layout = QHBoxLayout(logo_widget)
logo_layout.setContentsMargins(20, 20, 20, 20)
# Logo图标 - 使用更专业的图标
logo_icon = QLabel()
if IconManager.icon_exists('logo'):
logo_icon.setPixmap(IconManager.get_pixmap('logo', QSize(24, 24)))
else:
logo_icon.setText("") # 备选文字图标
logo_icon.setObjectName("logoIcon")
logo_layout.addWidget(logo_icon)
# Logo文字
logo_text = QLabel("MetaCore")
logo_text.setObjectName("logoText")
logo_layout.addWidget(logo_text)
logo_layout.addStretch()
layout.addWidget(logo_widget)
def create_quick_actions(self, layout):
"""创建快速操作区域"""
actions_widget = QWidget()
actions_widget.setObjectName("quickActions")
actions_layout = QVBoxLayout(actions_widget)
actions_layout.setContentsMargins(20, 10, 20, 20)
actions_layout.setSpacing(10)
# 创建新项目按钮
self.create_btn = QPushButton("创建新项目")
if IconManager.icon_exists('create'):
self.create_btn.setIcon(IconManager.get_icon('create'))
else:
self.create_btn = QPushButton("+ 创建新项目")
self.create_btn.setObjectName("createBtn")
self.create_btn.clicked.connect(self.create_project_requested.emit)
actions_layout.addWidget(self.create_btn)
# 导入项目按钮
self.import_btn = QPushButton("导入项目")
if IconManager.icon_exists('import'):
self.import_btn.setIcon(IconManager.get_icon('import'))
else:
self.import_btn = QPushButton("↑ 导入项目")
self.import_btn.setObjectName("sidebarImportBtn")
self.import_btn.clicked.connect(self.import_project_requested.emit)
actions_layout.addWidget(self.import_btn)
layout.addWidget(actions_widget)
def create_navigation_menu(self, layout):
"""创建导航菜单"""
# 滚动区域
scroll_area = QScrollArea()
scroll_area.setObjectName("navScrollArea") # 设置对象名称
scroll_area.setWidgetResizable(True) # 自适应内容大小
scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 水平滚动条
scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # 垂直滚动条
# 导航内容
nav_widget = QWidget()
nav_widget.setObjectName("navWidget")
nav_layout = QVBoxLayout(nav_widget)
nav_layout.setContentsMargins(0, 0, 0, 0) # 边距
nav_layout.setSpacing(0) # 间距
# 我的项目分组
self.create_nav_section(nav_layout, "我的项目", [
("📊", "项目概述", "overview"),
("📋", "项目管理", "management"),
])
# 资源管理分组
self.create_nav_section(nav_layout, "资源管理", [
("🏷", "资源分类", "resource_category"),
("📦", "资源管理", "resource_management"),
])
# 设置中心分组
self.create_nav_section(nav_layout, "设置中心", [
("📁", "项目设置", "project_settings"),
("", "系统设置", "system_settings"),
])
nav_layout.addStretch()
scroll_area.setWidget(nav_widget)
layout.addWidget(scroll_area)
def create_nav_section(self, layout, title, items):
"""创建导航分组"""
# 分组标题
section_widget = QWidget()
section_widget.setObjectName("navSection")
section_layout = QVBoxLayout(section_widget)
section_layout.setContentsMargins(0, 0, 0, 0)
section_layout.setSpacing(0)
# 标题按钮(可展开/收起)
title_btn = QPushButton(f"{title}")
if IconManager.icon_exists('down'):
title_btn.setIcon(IconManager.get_icon('down'))
else:
title_btn = QPushButton(f"{title}")
title_btn.setObjectName("navSectionTitle")
title_btn.setCheckable(True)
title_btn.setChecked(True)
section_layout.addWidget(title_btn)
# 子项容器
items_widget = QWidget()
items_widget.setObjectName("navItems")
items_layout = QVBoxLayout(items_widget)
items_layout.setContentsMargins(0, 0, 0, 0)
items_layout.setSpacing(0)
# 创建导航项
for icon, text, filter_type in items:
nav_item = self.create_nav_item(icon, text, filter_type)
items_layout.addWidget(nav_item)
section_layout.addWidget(items_widget)
# 展开/收起功能
def toggle_section():
is_expanded = title_btn.isChecked()
items_widget.setVisible(is_expanded)
if is_expanded:
if IconManager.icon_exists('down'):
title_btn.setIcon(IconManager.get_icon('down'))
title_btn.setText(f" {title}")
else:
title_btn.setText(f"{title}")
else:
if IconManager.icon_exists('right'):
title_btn.setIcon(IconManager.get_icon('right'))
title_btn.setText(f" {title}")
else:
title_btn.setText(f"{title}")
title_btn.clicked.connect(toggle_section)
layout.addWidget(section_widget)
def create_nav_item(self, icon, text, filter_type):
"""创建导航项"""
item_btn = QPushButton(f" {text}") # 移除文字图标,只保留空格用于间距
# 设置真实图标
if IconManager.icon_exists(filter_type):
item_btn.setIcon(IconManager.get_icon(filter_type, QSize(16, 16)))
item_btn.setIconSize(QSize(16, 16))
else:
# 如果图标不存在,使用原来的文字图标
item_btn.setText(f"{icon} {text}")
item_btn.setObjectName("navItem")
item_btn.setCheckable(True)
# 设置默认选中
if filter_type == "overview":
item_btn.setChecked(True)
# 发送初始导航信号
if filter_type in self.nav_mapping:
section, item_name = self.nav_mapping[filter_type]
# 使用 QTimer.singleShot 确保在UI完全初始化后发送信号
QTimer.singleShot(0, lambda: self.navigation_changed.emit(section, item_name, filter_type))
# 点击事件
def on_clicked():
# 取消其他按钮的选中状态
for btn in self.findChildren(QPushButton):
if btn.objectName() == "navItem" and btn != item_btn:
btn.setChecked(False)
item_btn.setChecked(True)
self.current_filter = filter_type
self.filter_changed.emit(filter_type)
# 发送导航变化信号
if filter_type in self.nav_mapping:
section, item_name = self.nav_mapping[filter_type]
self.navigation_changed.emit(section, item_name, filter_type)
item_btn.clicked.connect(on_clicked)
return item_btn
def create_user_info(self, layout):
"""创建用户信息区域"""
user_widget = QWidget()
user_widget.setObjectName("userInfo")
user_layout = QHBoxLayout(user_widget)
user_layout.setContentsMargins(20, 15, 20, 20)
# 用户头像 - 创建圆形头像
avatar_label = QLabel("U")
avatar_label.setObjectName("userAvatar")
avatar_label.setAlignment(Qt.AlignCenter)
avatar_label.setFixedSize(32, 32)
user_layout.addWidget(avatar_label)
# 用户名
username_label = QLabel("Admin")
username_label.setObjectName("userName")
user_layout.addWidget(username_label)
user_layout.addStretch()
# 下拉箭头
dropdown_label = QLabel("")
dropdown_label.setObjectName("userDropdown")
user_layout.addWidget(dropdown_label)
layout.addWidget(user_widget)
def connect_signals(self):
"""连接信号"""
pass

1705
MetaCore/ui/styles.py Normal file

File diff suppressed because it is too large Load Diff

45
MetaCore/启动应用.bat Normal file
View File

@ -0,0 +1,45 @@
@echo off
echo ========================================
echo MetaCore PyQt5 项目管理平台
echo ========================================
echo.
REM 检查Python是否可用
python --version >nul 2>&1
if errorlevel 1 (
echo [错误] Python未找到请确保Python已正确安装并添加到PATH
pause
exit /b 1
)
echo [信息] Python环境正常
python --version
REM 检查PyQt5是否已安装
python -c "import PyQt5" >nul 2>&1
if errorlevel 1 (
echo [警告] PyQt5未安装正在安装...
python -m pip install PyQt5
if errorlevel 1 (
echo [错误] PyQt5安装失败
pause
exit /b 1
)
echo [成功] PyQt5安装完成
) else (
echo [信息] PyQt5已安装
)
echo.
echo [信息] 正在启动MetaCore应用...
echo ========================================
echo.
REM 启动应用
python main.py
echo.
echo ========================================
echo [信息] MetaCore应用已退出
echo 感谢使用!
pause

78
MetaCore/验证安装.py Normal file
View File

@ -0,0 +1,78 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
验证MetaCore安装是否正确
"""
import sys
import os
def main():
print("=" * 50)
print("🧪 MetaCore安装验证")
print("=" * 50)
# 检查Python版本
print(f"🐍 Python版本: {sys.version}")
print(f"📁 Python路径: {sys.executable}")
# 检查PyQt5
try:
import PyQt5
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
print(f"✅ PyQt5版本: {PYQT_VERSION_STR}")
print(f"✅ Qt版本: {QT_VERSION_STR}")
# 测试创建应用
app = QApplication([])
print("✅ PyQt5可以正常创建应用程序")
app.quit()
except ImportError as e:
print(f"❌ PyQt5导入失败: {e}")
return False
# 检查项目文件
required_files = [
'main.py',
'ui/main_window.py',
'data/project_manager.py'
]
print("\n📁 检查项目文件:")
for file_path in required_files:
if os.path.exists(file_path):
print(f"{file_path}")
else:
print(f"{file_path} (缺失)")
return False
# 测试模块导入
print("\n📦 测试模块导入:")
try:
sys.path.insert(0, os.getcwd())
from ui.main_window import MainWindow
from data.project_manager import ProjectManager
print("✅ 所有模块导入成功")
except Exception as e:
print(f"❌ 模块导入失败: {e}")
return False
print("\n" + "=" * 50)
print("🎉 验证完成!")
print("✅ MetaCore安装正确可以正常运行")
print("\n🚀 启动命令:")
print(" python main.py")
print(" 或双击: 启动MetaCore.bat")
print("=" * 50)
return True
if __name__ == "__main__":
success = main()
if not success:
print("\n❌ 验证失败,请检查安装")
input("按Enter键退出...")
else:
input("按Enter键退出...")

139
README.md Normal file
View File

@ -0,0 +1,139 @@
# MetaCore 项目管理平台
现代化的项目管理平台提供Web版本和PyQt5桌面版本。
## 🚀 快速开始
### PyQt5桌面版本推荐
```cmd
# 一键启动
启动MetaCore.bat
# 或进入目录启动
cd MetaCore
启动应用.bat
```
### Web版本
```cmd
# 浏览器打开
web/index.html
```
## 📁 项目结构
```
MetaCore/
├── 🌐 Web版本
│ └── web/ # Web版本目录
│ ├── index.html # Web版本主页面
│ ├── script.js # JavaScript逻辑
│ ├── styles.css # 样式表
│ └── test-cards.html # 测试页面
├── 🖥️ PyQt5桌面版本
│ └── MetaCore/ # 桌面版本目录
│ ├── main.py # 主程序入口
│ ├── 启动应用.bat # 一键启动
│ ├── data/ # 数据模块
│ ├── ui/ # 界面模块
│ └── 验证安装.py # 环境验证工具
├── 📚 文档中心
│ └── Doc/ # 所有文档
│ ├── README.md # 文档索引
│ ├── 快速开始.md # 快速开始指南
│ ├── README_PyQt5.md # PyQt5详细说明
│ ├── 项目总览.md # 项目全面概述
│ ├── 功能对比说明.md # Web vs PyQt5对比
│ ├── 安装PyQt5指南.md # 安装问题解决
│ └── 虚拟环境完整指南.md # 环境配置指南
├── 🧪 测试文件
│ └── tests/ # 测试目录
│ ├── test_*.py # 各种测试文件
│ └── verify_button_fix.py # 验证修复文件
├── 🔧 开发工具
│ └── tools/ # 工具目录
│ ├── build.bat # 构建脚本
│ ├── build_config.py # 构建配置
│ ├── README_打包.md # 打包说明
│ └── 打包指南.md # 打包指南
├── 🚀 快速启动
│ └── 启动MetaCore.bat # 从根目录启动桌面版
└── 🔧 项目配置
├── .gitignore # Git忽略文件
├── data/ # 共享数据目录
└── 项目整理完成报告.md # 项目整理记录
```
## 📚 文档导航
### 🎯 新用户必读
- **[Doc/快速开始.md](Doc/快速开始.md)** - 快速上手指南
- **[Doc/安装PyQt5指南.md](Doc/安装PyQt5指南.md)** - 安装问题解决
### 📖 详细文档
- **[Doc/README.md](Doc/README.md)** - 📚 **文档中心索引**
- **[Doc/README_PyQt5.md](Doc/README_PyQt5.md)** - PyQt5版本完整说明
- **[Doc/项目总览.md](Doc/项目总览.md)** - 项目全面概述
### 🔧 技术文档
- **[Doc/功能对比说明.md](Doc/功能对比说明.md)** - Web vs PyQt5对比
- **[Doc/虚拟环境完整指南.md](Doc/虚拟环境完整指南.md)** - 环境配置指南
## ✨ 功能特性
### 项目管理
- ✅ 创建项目6种模板
- ✅ 导入项目(拖拽支持)
- ✅ 项目搜索和过滤
- ✅ 收藏和管理
### 界面设计
- ✅ 现代化深色主题
- ✅ 三段式项目卡片
- ✅ 2:1创建对话框
- ✅ 响应式布局
### 技术特点
- ✅ Web版本HTML/CSS/JavaScript
- ✅ 桌面版本Python + PyQt5
- ✅ 跨平台支持
- ✅ 数据持久化
## 🔧 系统要求
### PyQt5桌面版本
- Python 3.7+
- PyQt5 5.15.0+
- Windows/macOS/Linux
### Web版本
- 现代浏览器
- 支持HTML5/CSS3
## 🆘 获取帮助
### 常见问题
1. **PyQt5安装问题** → [Doc/安装PyQt5指南.md](Doc/安装PyQt5指南.md)
2. **使用方法** → [Doc/快速开始.md](Doc/快速开始.md)
3. **功能说明** → [Doc/README_PyQt5.md](Doc/README_PyQt5.md)
### 环境验证
```cmd
cd MetaCore
python 验证安装.py
```
### 完整文档
📚 **[Doc/README.md](Doc/README.md)** - 查看完整文档索引
---
🎉 **开始使用MetaCore管理您的项目吧**
💡 **提示:** 推荐使用桌面版本,性能更好,功能更完整。

1343
build/main/Analysis-00.toc Normal file

File diff suppressed because it is too large Load Diff

570
build/main/EXE-00.toc Normal file
View File

@ -0,0 +1,570 @@
('C:\\Users\\29381\\Desktop\\MetaCore-startup\\dist\\main.exe',
True,
False,
False,
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\bootloader\\images\\icon-console.ico',
None,
False,
False,
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
b'Privileges>\n <requestedExecutionLevel level="asInvoker" uiAccess='
b'"false"/>\n </requestedPrivileges>\n </security>\n </trustInfo>\n '
b'<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">\n <'
b'application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f'
b'0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>\n '
b' <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>\n <s'
b'upportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n <supporte'
b'dOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </application>\n <'
b'/compatibility>\n <application xmlns="urn:schemas-microsoft-com:asm.v3">'
b'\n <windowsSettings>\n <longPathAware xmlns="http://schemas.micros'
b'oft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </windowsSett'
b'ings>\n </application>\n <dependency>\n <dependentAssembly>\n <ass'
b'emblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version='
b'"6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" langua'
b'ge="*"/>\n </dependentAssembly>\n </dependency>\n</assembly>',
True,
False,
None,
None,
None,
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\main.pkg',
[('pyi-contents-directory _internal', '', 'OPTION'),
('PYZ-00.pyz',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\PYZ-00.pyz',
'PYZ'),
('struct',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\struct.pyc',
'PYMODULE'),
('pyimod01_archive',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod01_archive.pyc',
'PYMODULE'),
('pyimod02_importers',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod02_importers.pyc',
'PYMODULE'),
('pyimod03_ctypes',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod03_ctypes.pyc',
'PYMODULE'),
('pyimod04_pywin32',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod04_pywin32.pyc',
'PYMODULE'),
('pyiboot01_bootstrap',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
'PYSOURCE'),
('pyi_rth_inspect',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
'PYSOURCE'),
('pyi_rth_pyqt5',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py',
'PYSOURCE'),
('pyi_rth_pkgutil',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
'PYSOURCE'),
('main',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\MetaCore\\main.py',
'PYSOURCE'),
('python313.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\python313.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\opengl32sw.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\opengl32sw.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\libEGL.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libEGL.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\libGLESv2.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libGLESv2.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
'BINARY'),
('_decimal.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
'EXTENSION'),
('_hashlib.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
'EXTENSION'),
('_lzma.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
'EXTENSION'),
('_bz2.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
'EXTENSION'),
('select.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
'EXTENSION'),
('_socket.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
'EXTENSION'),
('unicodedata.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
'EXTENSION'),
('PyQt5\\QtGui.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtGui.pyd',
'EXTENSION'),
('PyQt5\\sip.cp313-win_amd64.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\sip.cp313-win_amd64.pyd',
'EXTENSION'),
('PyQt5\\QtCore.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtCore.pyd',
'EXTENSION'),
('PyQt5\\QtWidgets.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtWidgets.pyd',
'EXTENSION'),
('VCRUNTIME140.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\VCRUNTIME140.dll',
'BINARY'),
('api-ms-win-crt-stdio-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-stdio-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-convert-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-convert-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-heap-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-heap-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-process-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-process-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-time-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-time-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-conio-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-conio-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-locale-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-locale-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-environment-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-environment-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-string-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-string-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-runtime-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-runtime-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-math-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-math-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-filesystem-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-filesystem-l1-1-0.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Gui.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Gui.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Core.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Core.dll',
'BINARY'),
('api-ms-win-crt-utility-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-utility-l1-1-0.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5DBus.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5DBus.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Network.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Network.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Svg.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Svg.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\MSVCP140.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Quick.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Quick.dll',
'BINARY'),
('VCRUNTIME140_1.dll',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
'BINARY'),
('libcrypto-3.dll',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
'BINARY'),
('python3.dll',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\python3.dll',
'BINARY'),
('ucrtbase.dll', 'C:\\Windows\\system32\\ucrtbase.dll', 'BINARY'),
('PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Qml.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Qml.dll',
'BINARY'),
('api-ms-win-core-memory-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-memory-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-console-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-console-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-util-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-util-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-processthreads-l1-1-1.dll',
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-1.dll',
'BINARY'),
('api-ms-win-core-synch-l1-2-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-2-0.dll',
'BINARY'),
('api-ms-win-core-string-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-string-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-file-l2-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-file-l2-1-0.dll',
'BINARY'),
('api-ms-win-core-profile-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-profile-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-localization-l1-2-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-localization-l1-2-0.dll',
'BINARY'),
('api-ms-win-core-sysinfo-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-sysinfo-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-processenvironment-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-processenvironment-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-debug-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-debug-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-synch-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-processthreads-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-handle-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-handle-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-rtlsupport-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-rtlsupport-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-interlocked-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-interlocked-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-file-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-file-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-namedpipe-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-namedpipe-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-heap-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-heap-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-libraryloader-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-libraryloader-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-errorhandling-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-errorhandling-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-datetime-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-datetime-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-file-l1-2-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-file-l1-2-0.dll',
'BINARY'),
('api-ms-win-core-timezone-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-timezone-l1-1-0.dll',
'BINARY'),
('PyQt5\\Qt5\\translations\\qt_help_ja.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ja.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_bg.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_bg.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_gl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_gl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_bg.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_bg.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_de.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_de.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_he.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_he.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ko.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ko.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_es.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_es.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_cs.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_cs.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_cs.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_cs.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_gd.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gd.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_fr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ko.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ko.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_uk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_uk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_gd.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_gd.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_da.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_da.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ca.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ca.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_sk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_sk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_uk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_uk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ar.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ar.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_da.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_da.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_pt.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pt.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ca.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ca.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ar.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ar.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_tr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_tr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_it.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_it.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_uk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_uk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_it.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_it.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_it.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_it.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ko.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ko.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_sk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_hu.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_hu.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_da.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_da.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ja.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ja.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ru.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ru.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ja.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ja.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_tr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_tr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_tr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_tr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_fi.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fi.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_hu.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_hu.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_es.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_es.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_fa.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fa.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_en.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_en.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_cs.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_cs.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_en.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_en.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_bg.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_bg.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_fi.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fi.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_en.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_en.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_gl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ar.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ar.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_pl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_pl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ru.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ru.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_de.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_de.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_pl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_pl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_fr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_fr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_sk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_pl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_es.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_es.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_lt.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lt.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_sl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_he.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_he.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_hu.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_hu.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_sl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_fr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_sv.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sv.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_de.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_de.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_lv.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_lv.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_lv.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lv.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ca.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ca.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ru.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ru.qm',
'DATA'),
('base_library.zip',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\base_library.zip',
'DATA')],
[],
False,
False,
1758880462,
[('run.exe',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
'EXECUTABLE')],
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\python313.dll')

548
build/main/PKG-00.toc Normal file
View File

@ -0,0 +1,548 @@
('C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\main.pkg',
{'BINARY': True,
'DATA': True,
'EXECUTABLE': True,
'EXTENSION': True,
'PYMODULE': True,
'PYSOURCE': True,
'PYZ': False,
'SPLASH': True,
'SYMLINK': False},
[('pyi-contents-directory _internal', '', 'OPTION'),
('PYZ-00.pyz',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\PYZ-00.pyz',
'PYZ'),
('struct',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\struct.pyc',
'PYMODULE'),
('pyimod01_archive',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod01_archive.pyc',
'PYMODULE'),
('pyimod02_importers',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod02_importers.pyc',
'PYMODULE'),
('pyimod03_ctypes',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod03_ctypes.pyc',
'PYMODULE'),
('pyimod04_pywin32',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\localpycs\\pyimod04_pywin32.pyc',
'PYMODULE'),
('pyiboot01_bootstrap',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
'PYSOURCE'),
('pyi_rth_inspect',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
'PYSOURCE'),
('pyi_rth_pyqt5',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pyqt5.py',
'PYSOURCE'),
('pyi_rth_pkgutil',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
'PYSOURCE'),
('main',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\MetaCore\\main.py',
'PYSOURCE'),
('python313.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\python313.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qjpeg.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtga.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qtiff.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platformthemes\\qxdgdesktopportal.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\generic\\qtuiotouchplugin.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\iconengines\\qsvgicon.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwebgl.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwebp.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qico.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qicns.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qoffscreen.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qgif.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qwindows.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qwbmp.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\imageformats\\qsvg.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\platforms\\qminimal.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\d3dcompiler_47.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\opengl32sw.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\opengl32sw.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\libEGL.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libEGL.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\libGLESv2.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\libGLESv2.dll',
'BINARY'),
('PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\plugins\\styles\\qwindowsvistastyle.dll',
'BINARY'),
('_decimal.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
'EXTENSION'),
('_hashlib.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
'EXTENSION'),
('_lzma.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
'EXTENSION'),
('_bz2.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
'EXTENSION'),
('select.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
'EXTENSION'),
('_socket.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
'EXTENSION'),
('unicodedata.pyd',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
'EXTENSION'),
('PyQt5\\QtGui.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtGui.pyd',
'EXTENSION'),
('PyQt5\\sip.cp313-win_amd64.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\sip.cp313-win_amd64.pyd',
'EXTENSION'),
('PyQt5\\QtCore.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtCore.pyd',
'EXTENSION'),
('PyQt5\\QtWidgets.pyd',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\QtWidgets.pyd',
'EXTENSION'),
('VCRUNTIME140.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Scripts\\VCRUNTIME140.dll',
'BINARY'),
('api-ms-win-crt-stdio-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-stdio-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-convert-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-convert-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-heap-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-heap-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-process-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-process-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-time-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-time-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-conio-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-conio-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-locale-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-locale-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-environment-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-environment-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-string-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-string-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-runtime-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-runtime-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-math-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-math-l1-1-0.dll',
'BINARY'),
('api-ms-win-crt-filesystem-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-filesystem-l1-1-0.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Gui.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Gui.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Core.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Core.dll',
'BINARY'),
('api-ms-win-crt-utility-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-crt-utility-l1-1-0.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5DBus.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5DBus.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Network.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Network.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Svg.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Svg.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5WebSockets.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\MSVCP140.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Quick.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Quick.dll',
'BINARY'),
('VCRUNTIME140_1.dll',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\VCRUNTIME140_1.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Widgets.dll',
'BINARY'),
('libcrypto-3.dll',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
'BINARY'),
('python3.dll',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\python3.dll',
'BINARY'),
('ucrtbase.dll', 'C:\\Windows\\system32\\ucrtbase.dll', 'BINARY'),
('PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\MSVCP140_1.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5QmlModels.dll',
'BINARY'),
('PyQt5\\Qt5\\bin\\Qt5Qml.dll',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\bin\\Qt5Qml.dll',
'BINARY'),
('api-ms-win-core-memory-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-memory-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-console-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-console-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-util-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-util-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-processthreads-l1-1-1.dll',
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-1.dll',
'BINARY'),
('api-ms-win-core-synch-l1-2-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-2-0.dll',
'BINARY'),
('api-ms-win-core-string-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-string-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-file-l2-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-file-l2-1-0.dll',
'BINARY'),
('api-ms-win-core-profile-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-profile-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-localization-l1-2-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-localization-l1-2-0.dll',
'BINARY'),
('api-ms-win-core-sysinfo-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-sysinfo-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-processenvironment-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-processenvironment-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-debug-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-debug-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-synch-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-synch-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-processthreads-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-processthreads-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-handle-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-handle-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-rtlsupport-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-rtlsupport-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-interlocked-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-interlocked-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-file-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-file-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-namedpipe-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-namedpipe-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-heap-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-heap-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-libraryloader-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-libraryloader-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-errorhandling-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-errorhandling-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-datetime-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-datetime-l1-1-0.dll',
'BINARY'),
('api-ms-win-core-file-l1-2-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-file-l1-2-0.dll',
'BINARY'),
('api-ms-win-core-timezone-l1-1-0.dll',
'C:\\Windows\\system32\\api-ms-win-core-timezone-l1-1-0.dll',
'BINARY'),
('PyQt5\\Qt5\\translations\\qt_help_ja.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ja.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_bg.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_bg.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_gl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_gl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_bg.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_bg.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_de.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_de.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_he.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_he.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ko.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ko.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_es.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_es.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_cs.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_cs.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_TW.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_cs.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_cs.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_gd.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gd.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_fr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ko.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ko.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_uk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_uk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_TW.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_gd.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_gd.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_da.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_da.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ca.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ca.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_sk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_sk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_uk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_uk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_zh_TW.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ar.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ar.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_da.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_da.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_pt.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pt.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ca.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ca.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ar.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ar.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_tr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_tr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_it.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_it.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_uk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_uk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_it.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_it.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_it.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_it.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ko.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ko.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_sk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_hu.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_hu.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_da.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_da.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ja.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ja.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ru.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ru.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_ja.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_ja.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_tr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_tr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_tr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_tr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_fi.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_fi.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_zh_CN.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_hu.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_hu.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_es.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_es.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_fa.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fa.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_en.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_en.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_cs.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_cs.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_en.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_en.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_bg.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_bg.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_fi.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fi.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_en.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_en.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_gl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_gl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ar.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ar.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_pl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_pl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ru.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ru.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_de.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_de.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_zh_CN.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_pl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_pl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_fr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_fr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_sk.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sk.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_pl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_pl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_es.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_es.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_lt.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lt.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_sl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_sl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_he.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_he.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_hu.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_hu.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_sl.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sl.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_fr.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_fr.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_sv.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_sv.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_de.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_de.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_lv.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_lv.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_lv.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_lv.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qt_help_ca.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qt_help_ca.qm',
'DATA'),
('PyQt5\\Qt5\\translations\\qtbase_ru.qm',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\Qt5\\translations\\qtbase_ru.qm',
'DATA'),
('base_library.zip',
'C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\base_library.zip',
'DATA')],
'python313.dll',
False,
False,
False,
[],
None,
None,
None)

BIN
build/main/PYZ-00.pyz Normal file

Binary file not shown.

352
build/main/PYZ-00.toc Normal file
View File

@ -0,0 +1,352 @@
('C:\\Users\\29381\\Desktop\\MetaCore-startup\\build\\main\\PYZ-00.pyz',
[('PyQt5',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyQt5\\__init__.py',
'PYMODULE'),
('__future__',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\__future__.py',
'PYMODULE'),
('_colorize',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_colorize.py',
'PYMODULE'),
('_compat_pickle',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_compat_pickle.py',
'PYMODULE'),
('_compression',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_compression.py',
'PYMODULE'),
('_opcode_metadata',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_opcode_metadata.py',
'PYMODULE'),
('_py_abc',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_py_abc.py',
'PYMODULE'),
('_pydatetime',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_pydatetime.py',
'PYMODULE'),
('_pydecimal',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_pydecimal.py',
'PYMODULE'),
('_pyi_rth_utils',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\fake-modules\\_pyi_rth_utils\\__init__.py',
'PYMODULE'),
('_pyi_rth_utils.qt',
'D:\\PythonProject\\MetaCore-startup\\.venv\\Lib\\site-packages\\PyInstaller\\fake-modules\\_pyi_rth_utils\\qt.py',
'PYMODULE'),
('_strptime',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_strptime.py',
'PYMODULE'),
('_threading_local',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\_threading_local.py',
'PYMODULE'),
('argparse',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\argparse.py',
'PYMODULE'),
('ast',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ast.py',
'PYMODULE'),
('base64',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\base64.py',
'PYMODULE'),
('bisect',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\bisect.py',
'PYMODULE'),
('bz2',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\bz2.py',
'PYMODULE'),
('calendar',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\calendar.py',
'PYMODULE'),
('contextlib',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\contextlib.py',
'PYMODULE'),
('contextvars',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\contextvars.py',
'PYMODULE'),
('copy',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\copy.py',
'PYMODULE'),
('csv',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\csv.py',
'PYMODULE'),
('dataclasses',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\dataclasses.py',
'PYMODULE'),
('datetime',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\datetime.py',
'PYMODULE'),
('decimal',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\decimal.py',
'PYMODULE'),
('dis',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\dis.py',
'PYMODULE'),
('email',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\__init__.py',
'PYMODULE'),
('email._encoded_words',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_encoded_words.py',
'PYMODULE'),
('email._header_value_parser',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_header_value_parser.py',
'PYMODULE'),
('email._parseaddr',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_parseaddr.py',
'PYMODULE'),
('email._policybase',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\_policybase.py',
'PYMODULE'),
('email.base64mime',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\base64mime.py',
'PYMODULE'),
('email.charset',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\charset.py',
'PYMODULE'),
('email.contentmanager',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\contentmanager.py',
'PYMODULE'),
('email.encoders',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\encoders.py',
'PYMODULE'),
('email.errors',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\errors.py',
'PYMODULE'),
('email.feedparser',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\feedparser.py',
'PYMODULE'),
('email.generator',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\generator.py',
'PYMODULE'),
('email.header',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\header.py',
'PYMODULE'),
('email.headerregistry',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\headerregistry.py',
'PYMODULE'),
('email.iterators',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\iterators.py',
'PYMODULE'),
('email.message',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\message.py',
'PYMODULE'),
('email.parser',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\parser.py',
'PYMODULE'),
('email.policy',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\policy.py',
'PYMODULE'),
('email.quoprimime',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\quoprimime.py',
'PYMODULE'),
('email.utils',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\email\\utils.py',
'PYMODULE'),
('fnmatch',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\fnmatch.py',
'PYMODULE'),
('fractions',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\fractions.py',
'PYMODULE'),
('getopt',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\getopt.py',
'PYMODULE'),
('gettext',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\gettext.py',
'PYMODULE'),
('glob',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\glob.py',
'PYMODULE'),
('gzip',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\gzip.py',
'PYMODULE'),
('hashlib',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\hashlib.py',
'PYMODULE'),
('importlib',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\__init__.py',
'PYMODULE'),
('importlib._abc',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_abc.py',
'PYMODULE'),
('importlib._bootstrap',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_bootstrap.py',
'PYMODULE'),
('importlib._bootstrap_external',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\_bootstrap_external.py',
'PYMODULE'),
('importlib.abc',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\abc.py',
'PYMODULE'),
('importlib.machinery',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\machinery.py',
'PYMODULE'),
('importlib.metadata',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\__init__.py',
'PYMODULE'),
('importlib.metadata._adapters',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_adapters.py',
'PYMODULE'),
('importlib.metadata._collections',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_collections.py',
'PYMODULE'),
('importlib.metadata._functools',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_functools.py',
'PYMODULE'),
('importlib.metadata._itertools',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_itertools.py',
'PYMODULE'),
('importlib.metadata._meta',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_meta.py',
'PYMODULE'),
('importlib.metadata._text',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\metadata\\_text.py',
'PYMODULE'),
('importlib.readers',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\readers.py',
'PYMODULE'),
('importlib.resources',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\__init__.py',
'PYMODULE'),
('importlib.resources._adapters',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_adapters.py',
'PYMODULE'),
('importlib.resources._common',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_common.py',
'PYMODULE'),
('importlib.resources._functional',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_functional.py',
'PYMODULE'),
('importlib.resources._itertools',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\_itertools.py',
'PYMODULE'),
('importlib.resources.abc',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\abc.py',
'PYMODULE'),
('importlib.resources.readers',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\resources\\readers.py',
'PYMODULE'),
('importlib.util',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\importlib\\util.py',
'PYMODULE'),
('inspect',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\inspect.py',
'PYMODULE'),
('ipaddress',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\ipaddress.py',
'PYMODULE'),
('json',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\__init__.py',
'PYMODULE'),
('json.decoder',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\decoder.py',
'PYMODULE'),
('json.encoder',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\encoder.py',
'PYMODULE'),
('json.scanner',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\json\\scanner.py',
'PYMODULE'),
('logging',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\logging\\__init__.py',
'PYMODULE'),
('lzma',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\lzma.py',
'PYMODULE'),
('numbers',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\numbers.py',
'PYMODULE'),
('opcode',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\opcode.py',
'PYMODULE'),
('pathlib',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\__init__.py',
'PYMODULE'),
('pathlib._abc',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_abc.py',
'PYMODULE'),
('pathlib._local',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pathlib\\_local.py',
'PYMODULE'),
('pickle',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pickle.py',
'PYMODULE'),
('pkgutil',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pkgutil.py',
'PYMODULE'),
('pprint',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\pprint.py',
'PYMODULE'),
('py_compile',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\py_compile.py',
'PYMODULE'),
('quopri',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\quopri.py',
'PYMODULE'),
('random',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\random.py',
'PYMODULE'),
('selectors',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\selectors.py',
'PYMODULE'),
('shutil',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\shutil.py',
'PYMODULE'),
('signal',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\signal.py',
'PYMODULE'),
('socket',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\socket.py',
'PYMODULE'),
('statistics',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\statistics.py',
'PYMODULE'),
('string',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\string.py',
'PYMODULE'),
('stringprep',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\stringprep.py',
'PYMODULE'),
('subprocess',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\subprocess.py',
'PYMODULE'),
('tarfile',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tarfile.py',
'PYMODULE'),
('tempfile',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tempfile.py',
'PYMODULE'),
('textwrap',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\textwrap.py',
'PYMODULE'),
('threading',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\threading.py',
'PYMODULE'),
('token',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\token.py',
'PYMODULE'),
('tokenize',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tokenize.py',
'PYMODULE'),
('tracemalloc',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\tracemalloc.py',
'PYMODULE'),
('typing',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\typing.py',
'PYMODULE'),
('urllib',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\__init__.py',
'PYMODULE'),
('urllib.parse',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\urllib\\parse.py',
'PYMODULE'),
('zipfile',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\__init__.py',
'PYMODULE'),
('zipfile._path',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\_path\\__init__.py',
'PYMODULE'),
('zipfile._path.glob',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipfile\\_path\\glob.py',
'PYMODULE'),
('zipimport',
'C:\\Users\\29381\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\zipimport.py',
'PYMODULE')])

BIN
build/main/base_library.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build/main/main.pkg Normal file

Binary file not shown.

28
build/main/warn-main.txt Normal file
View File

@ -0,0 +1,28 @@
This file lists modules PyInstaller was not able to find. This does not
necessarily mean this module is required for running your program. Python and
Python 3rd-party packages include a lot of conditional or optional modules. For
example the module 'ntpath' only exists on Windows, whereas the module
'posixpath' only exists on Posix systems.
Types if import:
* top-level: imported at the top-level - look at these first
* conditional: imported within an if-statement
* delayed: imported within a function
* optional: imported within a try-except-statement
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
tracking down the missing module yourself. Thanks!
missing module named pyimod02_importers - imported by D:\PythonProject\MetaCore-startup\.venv\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
missing module named posix - imported by posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), os (conditional, optional)
missing module named resource - imported by posix (top-level)
missing module named 'collections.abc' - imported by tracemalloc (top-level), traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level)
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
missing module named 'MetaCore.data' - imported by C:\Users\29381\Desktop\MetaCore-startup\MetaCore\main.py (top-level)
missing module named 'MetaCore.ui' - imported by C:\Users\29381\Desktop\MetaCore-startup\MetaCore\main.py (top-level)
missing module named _posixsubprocess - imported by subprocess (conditional)
missing module named fcntl - imported by subprocess (optional)

7773
build/main/xref-main.html Normal file

File diff suppressed because it is too large Load Diff

203
build_app.py Normal file
View File

@ -0,0 +1,203 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MetaCore 应用程序打包脚本
这个脚本用于自动化打包 MetaCore 应用程序为可执行文件
它会
1. 清理之前的构建文件
2. 创建必要的资源目录
3. 使用优化的配置进行打包
4. 验证打包结果
使用方法
python build_app.py
作者: MetaCore Team
"""
import os
import sys
import shutil
import subprocess
from pathlib import Path
def clean_build_dirs():
"""清理构建目录"""
print("🧹 清理构建目录...")
dirs_to_clean = ['build', 'dist', '__pycache__']
for dir_name in dirs_to_clean:
dir_path = Path(dir_name)
if dir_path.exists():
print(f" 删除: {dir_path}")
shutil.rmtree(dir_path)
# 清理 .pyc 文件
for pyc_file in Path('.').rglob('*.pyc'):
pyc_file.unlink()
print("✅ 清理完成")
def ensure_resources():
"""确保必要的资源目录存在"""
print("📁 检查资源目录...")
resource_dirs = [
Path('MetaCore/Resources/Icons'),
Path('MetaCore/Resources/ProjectPreviews'),
Path('data')
]
for dir_path in resource_dirs:
if not dir_path.exists():
print(f" 创建目录: {dir_path}")
dir_path.mkdir(parents=True, exist_ok=True)
else:
print(f" ✓ 存在: {dir_path}")
print("✅ 资源目录检查完成")
def check_dependencies():
"""检查依赖"""
print("🔍 检查依赖...")
required_packages = ['PyQt5', 'pyinstaller']
missing = []
for package in required_packages:
try:
# 使用pip show来检查包是否安装
result = subprocess.run([sys.executable, '-m', 'pip', 'show', package],
capture_output=True, text=True)
if result.returncode == 0:
print(f"{package}")
else:
missing.append(package)
print(f"{package} - 缺失")
except Exception as e:
print(f" ⚠️ {package} - 检查失败: {e}")
# 如果pip检查失败尝试直接导入
try:
if package == 'PyQt5':
import PyQt5.QtCore
elif package == 'pyinstaller':
import PyInstaller
print(f"{package} (通过导入验证)")
except ImportError:
missing.append(package)
print(f"{package} - 确实缺失")
if missing:
print(f"❌ 缺少依赖: {', '.join(missing)}")
print("请运行: pip install " + ' '.join(missing))
return False
print("✅ 依赖检查完成")
return True
def build_app():
"""构建应用程序"""
print("🔨 开始构建应用程序...")
# 使用自定义的spec文件
spec_file = 'MetaCore.spec'
if not Path(spec_file).exists():
print(f"❌ 找不到 {spec_file} 文件")
return False
try:
# 运行PyInstaller
cmd = [sys.executable, '-m', 'PyInstaller', spec_file, '--clean']
print(f"执行命令: {' '.join(cmd)}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("✅ 构建成功!")
return True
else:
print("❌ 构建失败:")
print(result.stderr)
return False
except Exception as e:
print(f"❌ 构建过程中发生错误: {e}")
return False
def verify_build():
"""验证构建结果"""
print("🔍 验证构建结果...")
exe_path = Path('dist/MetaCore.exe')
if exe_path.exists():
size_mb = exe_path.stat().st_size / (1024 * 1024)
print(f"✅ 找到可执行文件: {exe_path}")
print(f"📊 文件大小: {size_mb:.1f} MB")
# 检查资源文件是否被正确包含
# 这里可以添加更多的验证逻辑
return True
else:
print("❌ 未找到可执行文件")
return False
def show_results():
"""显示构建结果"""
print("\n" + "="*50)
print("🎉 构建完成!")
print("="*50)
dist_path = Path('dist')
if dist_path.exists():
print(f"📦 输出目录: {dist_path.absolute()}")
for file in dist_path.glob('*'):
if file.is_file():
size_mb = file.stat().st_size / (1024 * 1024)
print(f" 📄 {file.name} ({size_mb:.1f} MB)")
print("\n💡 使用提示:")
print("1. 双击 MetaCore.exe 运行应用程序")
print("2. 可以将 exe 文件分发给其他用户")
print("3. 首次运行可能会慢一些(解压时间)")
def main():
"""主函数"""
print("🚀 MetaCore 应用程序打包工具")
print("="*50)
# 检查是否在项目根目录
if not Path('MetaCore/main.py').exists():
print("❌ 请在项目根目录运行此脚本")
return 1
# 执行构建步骤
try:
clean_build_dirs()
ensure_resources()
# 跳过依赖检查,直接尝试构建
# if not check_dependencies():
# return 1
print("⚠️ 跳过依赖检查,直接尝试构建...")
if not build_app():
return 1
if not verify_build():
return 1
show_results()
return 0
except KeyboardInterrupt:
print("\n⚠️ 用户中断构建")
return 1
except Exception as e:
print(f"\n❌ 构建过程中发生未预期的错误: {e}")
return 1
if __name__ == "__main__":
sys.exit(main())

57
data/projects.json Normal file
View File

@ -0,0 +1,57 @@
[
{
"id": 1,
"title": "智慧工厂",
"date": "2024-06-08 15:56:35",
"type": "industrial",
"image": "🏭",
"path": "",
"project_dir": "",
"description": "",
"status": "normal"
},
{
"id": 2,
"title": "智慧水务",
"date": "2023-01-10 12:09:04",
"type": "smart",
"image": "💧",
"path": "",
"project_dir": "",
"description": "",
"status": "normal"
},
{
"id": 3,
"title": "数字工厂",
"date": "2024-06-07 06:57:46",
"type": "industrial",
"image": "🏗️",
"path": "",
"project_dir": "",
"description": "",
"status": "normal"
},
{
"id": 4,
"title": "智慧监控",
"date": "2024-07-28 17:38:02",
"type": "smart",
"image": "📊",
"path": "",
"project_dir": "",
"description": "",
"status": "normal"
},
{
"id": 5,
"title": "工业设计平台",
"date": "2025-02-28 18:00:05",
"type": "design",
"image": "🎨",
"path": "",
"project_dir": "",
"description": "",
"status": "normal"
}
]

BIN
dist/MetaCore.exe vendored Normal file

Binary file not shown.

BIN
dist/Resources/Icons/Refresh.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
dist/Resources/Icons/app_icon.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
dist/Resources/Icons/category.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
dist/Resources/Icons/create.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
dist/Resources/Icons/delete.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
dist/Resources/Icons/down.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
dist/Resources/Icons/folder.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
dist/Resources/Icons/grid_view.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
dist/Resources/Icons/import.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Some files were not shown because too many files have changed in this diff Show More