Merge pull request #20 from muziing/dev

Version `0.3.1`
This commit is contained in:
木子 2024-01-04 22:21:16 +08:00 committed by GitHub
commit 35e24cb95b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 1500 additions and 301 deletions

View File

@ -1,4 +1,4 @@
![Py2exe-GUI Logo](docs/source/images/py2exe-gui_logo_big.png)
![Py2exe-GUI Logo](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/py2exe-gui_logo_big.png)
<h2 align="center">Easy-to-use Python GUI packaging tool</h2>
@ -24,9 +24,9 @@ English | <a href="README_zh.md">简体中文</a>
Py2exe-GUI is an assist tool based on [PySide6](https://doc.qt.io/qtforpython/index.html), designed to provide a
complete yet easy-to-use GUI for [PyInstaller](https://pyinstaller.org/).
![Screenshot](docs/source/images/Py2exe-GUI_v0.3.0_mainwindow_screenshot.png)
![Screenshot](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.3.1_mainwindow_screenshot_en.png)
![Screenshot](docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
![Screenshot](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
It has the following features:
@ -36,11 +36,6 @@ It has the following features:
in each interpreter environment to be packaged.
- Cross-platform, supports Windows, Linux and macOS.
> Note: As you can see, I am not an English speaker. Py2exe-GUI is currently only available in Simplified Chinese.
> However, I've reserved some interfaces in the code for internationalization, and the translation is slowly progressing.
> If you are interested in this project, you can star it. In a few months it will provide full English support and
> interfaces for translators to provide translations in more languages.
## How to install
> Note: Py2exe-GUI is still in the early stages of development, and the distributions provided are *beta versions*.
@ -112,7 +107,7 @@ the [checks](dev_scripts/check_funcs.py).
## License
![GPLv3](docs/source/images/gplv3-127x51.png)
![GPLv3](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/gplv3-127x51.png)
Py2exe-GUI is licensed under the GPLv3 open source license, see the [LICENSE](LICENSE) file for details.

View File

@ -1,4 +1,4 @@
![Py2exe-GUI Logo](docs/source/images/py2exe-gui_logo_big.png)
![Py2exe-GUI Logo](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/py2exe-gui_logo_big.png)
<h2 align="center">强大易用的 Python 图形界面打包工具</h2>
@ -23,9 +23,9 @@
Py2exe-GUI 是一个基于 [PySide6](https://doc.qt.io/qtforpython/index.html)
开发的辅助工具,旨在为 [PyInstaller](https://pyinstaller.org/) 提供完整易用的图形化界面,方便用户进行 Python 项目的打包。
![界面截图](docs/source/images/Py2exe-GUI_v0.3.0_mainwindow_screenshot.png)
![界面截图](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.3.0_mainwindow_screenshot.png)
![界面截图](docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
![界面截图](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/Py2exe-GUI_v0.2.0_screenshot.png)
有如下特性:
@ -101,7 +101,7 @@ request。请尽可能遵守原有的代码风格并确保新增代码能通
## 开源许可
![GPLv3](docs/source/images/gplv3-127x51.png)
![GPLv3](https://raw.githubusercontent.com/muziing/Py2exe-GUI/main/docs/source/images/gplv3-127x51.png)
Py2exe-GUI 采用 GPLv3 开源许可证,详情请参见 [LICENSE](LICENSE) 文件。

View File

@ -2,7 +2,6 @@
"""
import subprocess
from pathlib import Path
from dev_scripts.check_funcs import (
check_license_statement,
@ -11,63 +10,7 @@ from dev_scripts.check_funcs import (
check_version_num,
)
from dev_scripts.clear_cache import clear_pycache, clear_pyinstaller_dist
from dev_scripts.path_constants import (
PROJECT_ROOT,
README_FILE_LIST,
RESOURCES_PATH,
SRC_PATH,
)
def process_md_images(md_file_list: list[Path]) -> None:
"""处理 Markdown 文档中的图片链接
在构建前替换为 GitHub 图床链接在构建后替换回本地目录中的路径
:param md_file_list: Markdown 文件列表
"""
md_uri = "docs/source/images/"
github_uri = (
"https://github.com/muziing/Py2exe-GUI/raw/main" + "/docs/source/images/"
)
for md_file in md_file_list:
with open(md_file, "r+", encoding="UTF-8") as f:
all_text = f.read()
if github_uri not in all_text:
print(f"{md_file} 中的本地图片路径替换为GitHub在线路径")
all_text_new = all_text.replace(md_uri, github_uri)
else:
print(f"{md_file} 中的GitHub在线路径替换为本地图片路径")
all_text_new = all_text.replace(github_uri, md_uri)
f.seek(0)
f.write(all_text_new)
# FIXME 会在文件尾部多出来莫名其妙的行
def compile_resources() -> int:
"""调用 RCC 工具编译静态资源
:return: rcc 进程返回码
"""
compiled_file_path = RESOURCES_PATH / "COMPILED_RESOURCES.py"
qrc_file_path = RESOURCES_PATH / "resources.qrc"
cmd = [
"pyside6-rcc",
"-o",
str(compiled_file_path.absolute()),
str(qrc_file_path.absolute()),
]
try:
result = subprocess.run(cmd)
except subprocess.SubprocessError as e:
print(f"RCC编译进程错误{e}")
raise e
else:
print(f"已完成静态资源文件编译RCC返回码{result.returncode}")
return result.returncode
from dev_scripts.path_constants import PROJECT_ROOT, SRC_PATH
def export_requirements() -> int:
@ -102,23 +45,26 @@ def build_py2exe_gui() -> None:
# 准备工作
clear_pyinstaller_dist(SRC_PATH)
clear_pycache(SRC_PATH)
process_md_images(README_FILE_LIST)
# compile_resources()
export_requirements()
print(f"pre-commit 检查完毕,返回码:{check_pre_commit()}")
print(f"mypy 检查完毕,返回码:{check_mypy()}")
# 正式构建
subprocess.run(["poetry", "build"]) # TODO 处理异常与返回值
# 清理
process_md_images(README_FILE_LIST)
try:
result = subprocess.run(["poetry", "build"], check=True)
except subprocess.SubprocessError as e:
print(f"Poetry build 失败:{e}")
raise
else:
print(f"Poetry build 完毕,返回码:{result.returncode}")
finally:
# 清理
pass
else:
print("构建失败,有未通过的检查项")
print("有未通过的检查项,不进行构建")
if __name__ == "__main__":
# process_md_images()
# compile_resources()
# export_requirements()
build_py2exe_gui()

View File

@ -1,15 +1,16 @@
"""
开发脚本中使用的相对路径常量
"""开发脚本中使用的相对路径常量
所有脚本应以项目根目录为工作目录运行
"""
from pathlib import Path
PROJECT_ROOT = Path("../") # 项目根目录
PROJECT_ROOT = Path(__file__).parent.parent # 项目根目录
SRC_PATH = PROJECT_ROOT / "src" # 源码目录
SRC_PKG_PATH = SRC_PATH / "py2exe_gui"
SRC_PKG_PATH = SRC_PATH / "py2exe_gui" # 包目录
RESOURCES_PATH = SRC_PKG_PATH / "Resources" # 静态资源文件目录
COMPILED_RESOURCES = RESOURCES_PATH / "COMPILED_RESOURCES.py" # 编译静态资源文件
WIDGETS_PATH = SRC_PKG_PATH / "Widgets" # 控件目录
README_FILE_LIST = [
PROJECT_ROOT / "README.md",
PROJECT_ROOT / "README_zh.md",

View File

@ -0,0 +1,85 @@
"""开发脚本,便于调用 PySide6 提供的各种工具程序
"""
import subprocess
from dev_scripts.path_constants import (
COMPILED_RESOURCES,
PROJECT_ROOT,
RESOURCES_PATH,
SRC_PKG_PATH,
WIDGETS_PATH,
)
def compile_resources() -> int:
"""调用 RCC 工具编译静态资源
:return: rcc 进程返回码
"""
compiled_file_path = COMPILED_RESOURCES
qrc_file_path = RESOURCES_PATH / "resources.qrc"
cmd = [
"pyside6-rcc",
"-o",
compiled_file_path,
qrc_file_path,
]
try:
result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True)
except subprocess.SubprocessError as e:
print(f"RCC 编译进程错误:{e}")
raise e
else:
print(f"已完成静态资源文件编译RCC 返回码:{result.returncode}")
return result.returncode
def gen_ts(lang: str = "zh_CN") -> int:
"""调用 lupdate 工具分析源码,生成 .ts 文本翻译文件
:param lang: 目标翻译语言代码
:return: lupdate 返回码
"""
source = [*list(WIDGETS_PATH.glob("**/*.py")), SRC_PKG_PATH / "__main__.py"]
target = RESOURCES_PATH / "i18n" / f"{lang.replace('-', '_')}.ts"
cmd = ["pyside6-lupdate", *source, "-ts", target]
try:
result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True)
except subprocess.SubprocessError as e:
print(f"lupdate 进程错误:{e}")
raise
else:
print(f"已完成文本翻译文件生成lupdate 返回码:{result.returncode}")
return result.returncode
def gen_qm(lang: str = "zh_CN") -> int:
"""调用 lrelease 工具编译.ts 文本翻译文件
:param lang: 目标翻译语言代码
:return: lrelease 返回码
"""
source = RESOURCES_PATH / "i18n" / f"{lang.replace('-', '_')}.ts"
target = RESOURCES_PATH / "i18n" / f"{lang.replace('-', '_')}.qm"
cmd = ["pyside6-lrelease", source, "-qm", target]
try:
result = subprocess.run(cmd, cwd=PROJECT_ROOT, check=True)
except subprocess.SubprocessError as e:
print(f"lrelease 进程错误:{e}")
raise
else:
print(f"已完成文本翻译文件编译lrelease 返回码:{result.returncode}")
return result.returncode
if __name__ == "__main__":
# compile_resources()
gen_ts("zh_CN")
# gen_qm("zh_CN")

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

49
poetry.lock generated
View File

@ -428,15 +428,20 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
[[package]]
name = "pyinstaller-hooks-contrib"
version = "2023.11"
version = "2023.12"
description = "Community maintained hooks for PyInstaller"
optional = false
python-versions = ">=3.7"
files = [
{file = "pyinstaller-hooks-contrib-2023.11.tar.gz", hash = "sha256:5dd7a8a054a65c19cdaa381cabcfbe76f44d5f88d18214b0c570a0cd139be77f"},
{file = "pyinstaller_hooks_contrib-2023.11-py2.py3-none-any.whl", hash = "sha256:f2a75dac2968ec81f92dcd3768906f654fa4204bc496126ae8483e87a5d89602"},
{file = "pyinstaller-hooks-contrib-2023.12.tar.gz", hash = "sha256:11a9d59d903723dd693e8c10b054f3ea1ecad390623c9fa527c731d715fc5b3f"},
{file = "pyinstaller_hooks_contrib-2023.12-py2.py3-none-any.whl", hash = "sha256:6a601a0d783fa725327fc6ac712779475dc8979f639419c7fcd460dd8d0a6d2a"},
]
[package.dependencies]
importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""}
packaging = ">=22.0"
setuptools = ">=42.0.0"
[[package]]
name = "pyside6"
version = "6.6.1"
@ -560,28 +565,28 @@ files = [
[[package]]
name = "ruff"
version = "0.1.9"
version = "0.1.11"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e6a212f436122ac73df851f0cf006e0c6612fe6f9c864ed17ebefce0eff6a5fd"},
{file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:28d920e319783d5303333630dae46ecc80b7ba294aeffedf946a02ac0b7cc3db"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104aa9b5e12cb755d9dce698ab1b97726b83012487af415a4512fedd38b1459e"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e63bf5a4a91971082a4768a0aba9383c12392d0d6f1e2be2248c1f9054a20da"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d0738917c203246f3e275b37006faa3aa96c828b284ebfe3e99a8cb413c8c4b"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69dac82d63a50df2ab0906d97a01549f814b16bc806deeac4f064ff95c47ddf5"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2aec598fb65084e41a9c5d4b95726173768a62055aafb07b4eff976bac72a592"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:744dfe4b35470fa3820d5fe45758aace6269c578f7ddc43d447868cfe5078bcb"},
{file = "ruff-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479ca4250cab30f9218b2e563adc362bd6ae6343df7c7b5a7865300a5156d5a6"},
{file = "ruff-0.1.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:aa8344310f1ae79af9ccd6e4b32749e93cddc078f9b5ccd0e45bd76a6d2e8bb6"},
{file = "ruff-0.1.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:837c739729394df98f342319f5136f33c65286b28b6b70a87c28f59354ec939b"},
{file = "ruff-0.1.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e6837202c2859b9f22e43cb01992373c2dbfeae5c0c91ad691a4a2e725392464"},
{file = "ruff-0.1.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:331aae2cd4a0554667ac683243b151c74bd60e78fb08c3c2a4ac05ee1e606a39"},
{file = "ruff-0.1.9-py3-none-win32.whl", hash = "sha256:8151425a60878e66f23ad47da39265fc2fad42aed06fb0a01130e967a7a064f4"},
{file = "ruff-0.1.9-py3-none-win_amd64.whl", hash = "sha256:c497d769164df522fdaf54c6eba93f397342fe4ca2123a2e014a5b8fc7df81c7"},
{file = "ruff-0.1.9-py3-none-win_arm64.whl", hash = "sha256:0e17f53bcbb4fff8292dfd84cf72d767b5e146f009cccd40c2fad27641f8a7a9"},
{file = "ruff-0.1.9.tar.gz", hash = "sha256:b041dee2734719ddbb4518f762c982f2e912e7f28b8ee4fe1dee0b15d1b6e800"},
{file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"},
{file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"},
{file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"},
{file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"},
{file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"},
{file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"},
{file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"},
{file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"},
]
[[package]]
@ -684,4 +689,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata]
lock-version = "2.0"
python-versions = ">=3.8,<3.13"
content-hash = "a3e9cf4400a33e8958cc148c575a23017ff036c2dbd7a1185baadf8ad4d5e611"
content-hash = "73b33938229a7a1fa491c925f43bcd0c9d65b1ba4c0518d145420e254eaf8a9a"

View File

@ -1,13 +1,14 @@
[tool.poetry]
name = "py2exe-gui"
version = "0.3.0"
version = "0.3.1"
description = "GUI for PyInstaller, based on PySide6"
keywords = ["PyInstaller", "GUI", "PySide6"]
authors = ["muzing <muzi2001@foxmail.com>"]
license = "GPL-3.0-or-later"
readme = ["README.md", "README_zh.md"]
repository = "https://github.com/muziing/Py2exe-GUI"
exclude = ["src/py2exe_gui/Resources/Icons", "src/py2exe_gui/Resources/Texts"]
exclude = ["src/py2exe_gui/Resources"]
include = ["src/py2exe_gui/Resources/COMPILED_RESOURCES.py"]
classifiers = [
"Development Status :: 4 - Beta",
"Operating System :: Microsoft :: Windows",
@ -32,12 +33,11 @@ PySide6 = "^6.6.0"
pyyaml = "^6.0.1"
[tool.poetry.group.dev]
[tool.poetry.group.dev.dependencies]
pre-commit = "^3.5.0"
black = "^23.12.0"
isort = "^5.13.0"
ruff = "^0.1.9"
ruff = "^0.1.11"
mypy = "^1.8.0"
pyinstaller = "^6.2.0"
types-pyyaml = "^6.0.12.12"

View File

@ -11,13 +11,6 @@ Py2exe-GUI 启动方式:
python -m py2exe_gui
"""
import sys
from py2exe_gui.__main__ import main
from PySide6.QtWidgets import QApplication
from py2exe_gui.__main__ import MainApp
app = QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec())
main()

View File

@ -24,7 +24,7 @@ class AppConstant:
"""应用程序级的常量"""
NAME = "Py2exe-GUI"
VERSION = "0.3.0"
VERSION = "0.3.1"
AUTHORS = ["muzing <muzi2001@foxmail.com>"]
LICENSE = "GPL-3.0-or-later"
HOME_PAGE = APP_URLs["HOME_PAGE"]

View File

@ -6,6 +6,478 @@
from PySide6 import QtCore
qt_resource_data = b"\
\x00\x00\x1d^\
<\
\xb8d\x18\xca\xef\x9c\x95\xcd!\x1c\xbf`\xa1\xbd\xdd\xa7\
\x00\x00\x00\x05zh_CNB\x00\x00\x03\x00\x00\x00\
+;\x00\x00\x01\x82\x00\x00+;\x00\x00\x11\xbd\x00\x02\
\xb4\xc7\x00\x00\x01P\x00\x02\xb4\xc7\x00\x00\x11\x85\x00\x04\
\xa6y\x00\x00\x02&\x00\x05H5\x00\x00\x12w\x00\x05\
f\xbe\x00\x00\x0b\xc1\x00\x05f\xbe\x00\x00\x13\xa8\x00\x10\
\xcan\x00\x00\x04h\x00\x13U\xee\x00\x00\x0a;\x00*\
\xcf\x04\x00\x00\x0eN\x00*\xd0%\x00\x00\x0e~\x00*\
\xec0\x00\x00\x0e\xae\x00G\x96\xc4\x00\x00\x00\x00\x00I\
l\x0e\x00\x00\x03L\x00J+~\x00\x00\x05\x02\x00J\
6\x95\x00\x00\x14\xf0\x00Kdq\x00\x00\x15\x1b\x00L\
\x99b\x00\x00\x05\xa0\x00L\x99b\x00\x00\x17\xc3\x01*\
\xbc^\x00\x00\x04\xb4\x01\x8a\xa33\x00\x00\x11\xf4\x01\xdb\
\xb2\x8f\x00\x00\x07B\x01\xf3(\xfe\x00\x00\x15\xfd\x02$\
\x06\xee\x00\x00\x19E\x02TK\xfa\x00\x00\x03\x98\x02o\
\xeej\x00\x00\x17X\x02r\xf7\xfe\x00\x00\x05,\x02\xa7\
\x96\xc4\x00\x00\x0e\x1d\x02\xa7\xdeU\x00\x00\x0f\x81\x02\xb6\
\xee\xd3\x00\x00\x10\x7f\x03\x8aRY\x00\x00\x0bb\x03\xbc\
\xb9r\x00\x00\x01\xe6\x04\x13\xa2*\x00\x00\x08\x93\x04a\
\xc9p\x00\x00\x18T\x04t\xcbE\x00\x00\x06G\x04\x98\
I\xbc\x00\x00\x0b\x07\x04\x98I\xbc\x00\x00\x13|\x04\x98\
I\xbc\x00\x00\x14\xc4\x04\x99n\x95\x00\x00\x03\xcc\x04\x99\
n\x95\x00\x00\x17\x92\x04\xcfv\x94\x00\x00\x02S\x04\xd1\
N\xb2\x00\x00\x06~\x05g\xb0^\x00\x00\x13\x08\x05\x8b\
{\xbe\x00\x00\x0d\xf5\x06\x04\x81\x85\x00\x00\x0b1\x06L\
\xc5c\x00\x00\x01\xb3\x06\x5c\xc6\xd5\x00\x00\x14\x19\x06m\
\x81M\x00\x00\x0fF\x06\xc6l\x14\x00\x00\x0f\x12\x07$\
\xfe\xde\x00\x00\x0a\xdb\x07?\xfd\xfe\x00\x00\x18\xdf\x07\xca\
r\x11\x00\x00\x09x\x08\x05\x1f\xb0\x00\x00\x06\xfd\x08\xa1\
\x96\xd9\x00\x00\x0cm\x09\x07[\x85\x00\x00\x0f\xd4\x09\x08\
b\x8a\x00\x00\x08X\x09 \x93N\x00\x00\x10+\x09(\
n\x13\x00\x00\x02\xc1\x09<\x5c\x83\x00\x00\x10\xd9\x09M\
g\xfe\x00\x00\x12\xce\x09pU\x99\x00\x00\x14X\x09\xc4\
\xb21\x00\x00\x03\xf7\x09\xd8%U\x00\x00\x0c-\x09\xf2\
5X\x00\x00\x08\x05\x0a\x0f\xec\x8e\x00\x00\x00&\x0a\x1e\
\xda\xd4\x00\x00\x05\xca\x0ae\xa8\xe3\x00\x00\x15L\x0a\x98\
I\x9c\x00\x00\x00\xe6\x0a\x98I\x9c\x00\x00\x11\x0f\x0a\xac\
,\x85\x00\x00\x01\x1b\x0a\xac,\x85\x00\x00\x11J\x0a\xb8\
\xc2\xa1\x00\x00\x08\xe3\x0a\xebf\x09\x00\x00\x0a\x9e\x0a\xeb\
f\x09\x00\x00\x0b\xe9\x0a\xebf\x09\x00\x00\x13=\x0b\x05\
MN\x00\x00\x06\x00\x0b\xab\x22\xae\x00\x00\x02\xfc\x0b\xd4\
\xbf\xa1\x00\x00\x16\xa2\x0b\xddZ\xc5\x00\x00\x00\xa8\x0b\xe1\
gZ\x00\x00\x16\xf4\x0c\x05\x06\xc4\x00\x00\x15\xc6\x0c\x0a\
\xbe\xf5\x00\x00\x04%\x0c\x1b\xd1\xa1\x00\x00\x19\xb1\x0cP\
\xa0*\x00\x00\x06\xb7\x0c~`9\x00\x00\x0d\x87\x0c\xa8\
?b\x00\x00\x0c\xc6\x0c\xba\xefs\x00\x00\x0e\xde\x0c\xc9\
\xa0\x0e\x00\x00\x12\xa1\x0d\x89P\x17\x00\x00\x0a\x0f\x0e\x01\
+e\x00\x00\x18\x9f\x0ef\xfa\x7f\x00\x00\x17\xf3\x0e\x81\
2\x09\x00\x00\x0d\x13\x0f\xc0\xd03\x00\x00\x02\x82\x0f\xcf\
\xb2#\x00\x00\x129\x0f\xe8\x01e\x00\x00\x13\xd2i\x00\
\x00\x1a:\x03\x00\x00\x00\x04QsN\x8e\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x05About\x07\x00\x00\x00\x08\
AboutDlg\x01\x03\x00\x00\x00(e\xe0\
l\xd5bS_\x00QsN\x8ee\x87hc\xff\x0c\
\x8b\xf7\x5c\x1d\x8b\xd5\x91\xcde\xb0\x83\xb7S\xd6g,\
z\x0b^\x8f0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00=\
Can't open the A\
bout document, t\
ry to reinstall \
this program.\x07\x00\x00\
\x00\x08AboutDlg\x01\x03\x00\x00\x00\x10\
mO\x89\xc8e\x87N\xf6\x00(\x00&\x00B\x00)\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0c&Brows\
e File\x07\x00\x00\x00\x0dAddDa\
taWindow\x01\x03\x00\x00\x00\x0cS\xd6\
m\x88\x00(\x00&\x00C\x00)\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x07&Cancel\x07\x00\x00\x00\x0d\
AddDataWindow\x01\x03\x00\
\x00\x00\x0cR \x96d\x00(\x00&\x00D\x00)\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x07&Delete\
\x07\x00\x00\x00\x0dAddDataWind\
ow\x01\x03\x00\x00\x00\x0ce\xb0^\xfa\x00(\x00&\
\x00N\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04&N\
ew\x07\x00\x00\x00\x0dAddDataWi\
ndow\x01\x03\x00\x00\x00\x0cxn\x8b\xa4\x00(\
\x00&\x00O\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x03\
&OK\x07\x00\x00\x00\x0dAddDataW\
indow\x01\x03\x00\x00\x00\x08m\xfbR\xa0e\
\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09Add\
Files\x07\x00\x00\x00\x0dAddDa\
taWindow\x01\x03\x00\x00\x00\x10mO\
\x89\xc8v\xee_U\x00(\x00&\x00F\x00)\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x0eBrowse &\
Folder\x07\x00\x00\x00\x0dAddDa\
taWindow\x01\x03\x00\x00\x00\x04Y\x0d\
R6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04Copy\
\x07\x00\x00\x00\x10ArgumentsBr\
owser\x01\x03\x00\x00\x00\x04[\xfcQ\xfa\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x06Export\x07\
\x00\x00\x00\x10ArgumentsBro\
wser\x01\x03\x00\x00\x00\x0em\xfbR\xa0N\x8c\
\x8f\xdbR6e\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x10Add Binary Fil\
es\x07\x00\x00\x00\x0cCenterWid\
get\x01\x03\x00\x00\x00\x0cm\xfbR\xa0epc\
ne\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0eA\
dd Data Files\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x16m\xfbR\xa0N\x8c\x8f\xdbR6e\x87\
N\xf6]\xf2f\xf4e\xb00\x02\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x19Add binary f\
iles updated.\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x14m\xfbR\xa0epcne\x87N\xf6\
]\xf2f\xf4e\xb00\x02\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x17Add data files\
updated.\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x00\x0a\
\x98yv\xeeT\x0dy\xf0\xff\x1a\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x09App Name:\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x04mO\x89\xc8\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x06Browse\x07\x00\x00\x00\x0cCen\
terWidget\x01\x03\x00\x00\x00\x06b\
SS\x05\xff\x01\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07B\
undle!\x07\x00\x00\x00\x0cCente\
rWidget\x01\x03\x00\x00\x00\x12bSS\
\x05v\x84^\x94u(z\x0b^\x8fT\x0dy\xf0\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x10Bundled\
app name\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x00\x14\
\x5c\x06bSS\x05\x81\xf3SUN*e\x87N\xf6\
N-0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00\x17Bu\
ndling into one \
file.\x07\x00\x00\x00\x0cCenter\
Widget\x01\x03\x00\x00\x00\x14\x5c\x06bS\
S\x05\x81\xf3SUN*v\xee_UN-0\x02\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x19Bundli\
ng into one fold\
er.\x07\x00\x00\x00\x0cCenterWi\
dget\x01\x03\x00\x00\x00\x04n\x05t\x06\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x05Clean\x07\x00\x00\
\x00\x0cCenterWidget\x01\x03\
\x00\x00\x00\x1cg\x84^\xfaRM\x5c\x06n\x05\x96d\
\x7f\x13[XN\x0eN4e\xf6v\xee_U0\x02\
\x08\x00\x00\x00\x00\x06\x00\x00\x007Clean \
cache and remove\
temporary files\
before building\
.\x07\x00\x00\x00\x0cCenterWidg\
et\x01\x03\x00\x00\x00\x04\x95\x19\x8b\xef\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x05Error\x07\x00\x00\x00\x0c\
CenterWidget\x01\x03\x00\x00\
\x00\x08\x96\x90_\x0f[\xfcQe\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x0dHidden Impor\
t\x07\x00\x00\x00\x0cCenterWidg\
et\x01\x03\x00\x00\x00\x10\x96\x90_\x0f[\xfcQe\
]\xf2f\xf4e\xb00\x02\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x16Hidden import \
updated.\x07\x00\x00\x00\x0cCen\
terWidget\x01\x03\x00\x00\x00\x0eb\
SS\x05\x81\xf3SUN*e\x87N\xf6\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x08One File\x07\
\x00\x00\x00\x0cCenterWidget\
\x01\x03\x00\x00\x00\x0ebSS\x05\x81\xf3SUN*\
v\xee_U\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0aOn\
e Folder\x07\x00\x00\x00\x0cCen\
terWidget\x01\x03\x00\x00\x00\x10S\
Uv\xee_U\x00/SUe\x87N\xf6\xff\x1a\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x15One Fol\
der/ One File:\x07\x00\
\x00\x00\x0cCenterWidget\x01\
\x03\x00\x00\x00\x10bS_\x00\x81\x1ag,\x8d\xef_\
\x84\xff\x1a\x00 \x08\x00\x00\x00\x00\x06\x00\x00\x00\x14O\
pened script pat\
h: \x07\x00\x00\x00\x0cCenterWi\
dget\x01\x03\x00\x00\x00NW(\x8b\xe5\x00 \
\x00P\x00y\x00t\x00h\x00o\x00n\x00 s\xaf\
X\x83N-O<NNl\xa1g\x09[\x89\x88\xc5\
\x00 \x00P\x00y\x00i\x00n\x00s\x00t\x00a\
\x00l\x00l\x00e\x00r\xff\x0cf/T&N\xcd\
\x89\x81~\xe7~\xed\xff\x1f\x08\x00\x00\x00\x00\x06\x00\x00\
\x00TPyinstaller do\
esn't seem to be\
installed in th\
is Python enviro\
nment, still con\
tinue?\x07\x00\x00\x00\x0cCente\
rWidget\x01\x03\x00\x00\x00\x1a\x00P\x00\
y\x00t\x00h\x00o\x00n\x00 QeS\xe3\x81\
\x1ag,\x8d\xef_\x84\x08\x00\x00\x00\x00\x06\x00\x00\x00\
\x18Python entry sc\
ript path\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x00\x0c\
_\x85bSS\x05\x81\x1ag,\xff\x1a\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x0ePython scr\
ipt:\x07\x00\x00\x00\x0cCenterW\
idget\x01\x03\x00\x00\x00\x12]\xf2\x5c\x06\x98\
yv\xeeT\x0d\x8b\xbe\x7fnN:\xff\x1a\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x1dThe app n\
ame has been set\
to:\x07\x00\x00\x00\x0cCenterW\
idget\x01\x03\x00\x00\x000\x90\x09b\xe9v\
\x84N\x0df/g\x09eHv\x84\x00P\x00y\x00\
t\x00h\x00o\x00n\x89\xe3\x91\xcaVh\xff\x0c\x8b\
\xf7\x91\xcde\xb0\x90\x09b\xe9\xff\x01\x08\x00\x00\x00\x00\
\x06\x00\x00\x00DThe selecti\
on is not a vali\
d Python interpr\
eter, please res\
elect it!\x07\x00\x00\x00\x0cCe\
nterWidget\x01\x03\x00\x00\x002\
\x90\x09b\xe9v\x84N\x0df/g\x09eHv\x84\
\x00P\x00y\x00t\x00h\x00o\x00n\x81\x1ag,\
e\x87N\xf6\xff\x0c\x8b\xf7\x91\xcde\xb0\x90\x09b\xe9\
\xff\x01\x08\x00\x00\x00\x00\x06\x00\x00\x00DThe \
selection is not\
a valid Python \
script file, ple\
ase reselect it!\
\x07\x00\x00\x00\x0cCenterWidge\
t\x01\x03\x00\x00\x00\x04\x8bfTJ\x08\x00\x00\x00\x00\
\x06\x00\x00\x00\x07Warning\x07\x00\x00\x00\
\x0cCenterWidget\x01\x03\x00\
\x00\x00\x18N\x0dO\x1aR \x96d\x7f\x13[XN\
\x0eN4e\xf6e\x87N\xf60\x02\x08\x00\x00\x00\x00\
\x06\x00\x00\x00*Will not de\
lete cache and t\
emporary files.\x07\
\x00\x00\x00\x0cCenterWidget\
\x01\x03\x00\x00\x00\x10b@g\x09e\x87N\xf6\x00 \
\x00(\x00*\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0d\
All Files (*)\x07\x00\x00\
\x00\x0bIconFileDlg\x01\x03\x00\
\x00\x00\x04V\xfeh\x07\x08\x00\x00\x00\x00\x06\x00\x00\x00\
\x08App Icon\x07\x00\x00\x00\x0bIc\
onFileDlg\x01\x03\x00\x00\x00\x04S\
\xd6m\x88\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Can\
cel\x07\x00\x00\x00\x0bIconFile\
Dlg\x01\x03\x00\x00\x00\x08V\xfeh\x07e\x87N\
\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09Icon \
File\x07\x00\x00\x00\x0bIconFil\
eDlg\x01\x03\x00\x00\x00&V\xfeh\x07e\x87\
N\xf6\x00 \x00(\x00*\x00.\x00i\x00c\x00o\
\x00 \x00*\x00.\x00i\x00c\x00n\x00s\x00)\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x19Icon F\
iles (*.ico *.ic\
ns)\x07\x00\x00\x00\x0bIconFile\
Dlg\x01\x03\x00\x00\x00\x04bS_\x00\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x04Open\x07\x00\x00\x00\x0b\
IconFileDlg\x01\x03\x00\x00\x00\
\x10b@g\x09e\x87N\xf6\x00 \x00(\x00*\x00\
)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0dAll F\
iles (*)\x07\x00\x00\x00\x12Int\
erpreterFileDlg\x01\
\x03\x00\x00\x00\x0aS\xefbg\x88Le\x87N\xf6\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x0fExecuta\
ble File\x07\x00\x00\x00\x12Int\
erpreterFileDlg\x01\
\x03\x00\x00\x00\x1aS\xefbg\x88Le\x87N\xf6\x00\
\x00(\x00*\x00.\x00e\x00x\x00e\x00)\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x18Executa\
ble Files (*.exe\
)\x07\x00\x00\x00\x12Interprete\
rFileDlg\x01\x03\x00\x00\x00\x14\x00P\
\x00y\x00t\x00h\x00o\x00n\x00 \x89\xe3\x91\xca\
Vh\x08\x00\x00\x00\x00\x06\x00\x00\x00\x12Pyth\
on Interpreter\x07\x00\
\x00\x00\x12InterpreterFi\
leDlg\x01\x03\x00\x00\x00.\x00P\x00y\x00\
t\x00h\x00o\x00n\x00 \x89\xe3\x91\xcaVh\x00\
\x00(\x00p\x00y\x00t\x00h\x00o\x00n\x00\
.\x00e\x00x\x00e\x00)\x08\x00\x00\x00\x00\x06\x00\
\x00\x00\x1fPython Interp\
reter (python.ex\
e)\x07\x00\x00\x00\x12Interpret\
erFileDlg\x01\x03\x00\x00\x00*\x00\
P\x00y\x00t\x00h\x00o\x00n\x00 \x89\xe3\x91\
\xcaVh\x00 \x00(\x00p\x00y\x00t\x00h\x00\
o\x00n\x003\x00*\x00)\x08\x00\x00\x00\x00\x06\x00\
\x00\x00\x1dPython Interp\
reter (python3*)\
\x07\x00\x00\x00\x12Interpreter\
FileDlg\x01\x03\x00\x00\x00\x06\x5c1~\
\xea0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Rea\
dy.\x07\x00\x00\x00\x07MainApp\x01\
\x03\x00\x00\x00\x0cQsN\x8e\x00(\x00&\x00A\x00\
)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06&Abou\
t\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0c\x90\x00Q\xfa\x00(\x00&\x00E\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05&Exi\
t\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0ce\x87N\xf6\x00(\x00&\x00F\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05&Fil\
e\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0c^.R\xa9\x00(\x00&\x00H\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x05&Hel\
p\x07\x00\x00\x00\x0aMainWindow\
\x01\x03\x00\x00\x00\x0c\x8b\xbe\x7fn\x00(\x00&\x00S\
\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09&Set\
tings\x07\x00\x00\x00\x0aMainWi\
ndow\x01\x03\x00\x00\x00\x0cQsN\x8e\x00 \
\x00&\x00Q\x00t\x08\x00\x00\x00\x00\x06\x00\x00\x00\x09\
About &Qt\x07\x00\x00\x00\x0aMa\
inWindow\x01\x03\x00\x00\x00\x0aQs\
N\x8ekdz\x0b^\x8f\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x12About This Pro\
gram\x07\x00\x00\x00\x0aMainWin\
dow\x01\x03\x00\x00\x00\x1a[\xfcQ\xfa\x91M\x7f\
n\x81\xf3\x00 \x00J\x00S\x00O\x00N\x00 e\
\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1aExp\
ort Config To JS\
ON File\x07\x00\x00\x00\x0aMain\
Window\x01\x03\x00\x00\x00\x1cN\xce\x00 \
\x00J\x00S\x00O\x00N\x00 e\x87N\xf6N-\
[\xfcQe\x91M\x7fn\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x1cImport Config \
From JSON File\x07\x00\
\x00\x00\x0aMainWindow\x01\x03\x00\
\x00\x00\x1c\x00P\x00y\x00I\x00n\x00s\x00t\x00\
a\x00l\x00l\x00e\x00r\x00 e\x87hc\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x19PyInsta\
ller Documentati\
on\x07\x00\x00\x00\x0aMainWindo\
w\x01\x03\x00\x00\x00 \x00P\x00y\x00I\x00n\x00\
s\x00t\x00a\x00l\x00l\x00e\x00r\x00 \x90\
\x09\x98y\x8b\xe6`\xc5\x08\x00\x00\x00\x00\x06\x00\x00\x00\
\x1bPyInstaller Opt\
ions Details\x07\x00\x00\x00\
\x0aMainWindow\x01\x03\x00\x00\x00\
\x0cb\xa5TJ\x00 \x00B\x00u\x00g\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x0bReport Bu\
gs\x07\x00\x00\x00\x0aMainWindo\
w\x01\x03\x00\x00\x00\x0cS\xd6m\x88\x00(\x00&\x00\
C\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x07&Ca\
ncel\x07\x00\x00\x00\x13MultiIt\
emEditWindow\x01\x03\x00\x00\
\x00\x0cR \x96d\x00(\x00&\x00D\x00)\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x07&Delete\x07\
\x00\x00\x00\x13MultiItemEdi\
tWindow\x01\x03\x00\x00\x00\x0ce\xb0^\
\xfa\x00(\x00&\x00N\x00)\x08\x00\x00\x00\x00\x06\x00\
\x00\x00\x04&New\x07\x00\x00\x00\x13Mult\
iItemEditWindow\x01\
\x03\x00\x00\x00\x0cxn\x8b\xa4\x00(\x00&\x00O\x00\
)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x03&OK\x07\x00\
\x00\x00\x13MultiItemEdit\
Window\x01\x03\x00\x00\x00\x0emO\x89\xc8\
S\x05\x00(\x00&\x00B\x00)\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x10&Browse pack\
ages\x07\x00\x00\x00\x12MultiPk\
gEditWindow\x01\x03\x00\x00\x00\
\x0a]\xf2[\x89\x88\xc5v\x84S\x05\x08\x00\x00\x00\x00\
\x06\x00\x00\x00\x12Installed P\
ackages\x07\x00\x00\x00\x0dPkgB\
rowserDlg\x01\x03\x00\x00\x00\x04S\
\x05T\x0d\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04Nam\
e\x07\x00\x00\x00\x0dPkgBrowser\
Dlg\x01\x03\x00\x00\x00\x04rHg,\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x07Version\x07\x00\
\x00\x00\x0dPkgBrowserDlg\
\x01\x03\x00\x00\x00\x04c\xcf\x8f\xf0\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x0bDescription\x07\
\x00\x00\x00\x16PyinstallerO\
ptionTable\x01\x03\x00\x00\x00\x04\
\x90\x09\x98y\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Op\
tion\x07\x00\x00\x00\x16Pyinsta\
llerOptionTable\x01\
\x03\x00\x00\x00\x10b@g\x09e\x87N\xf6\x00 \x00\
(\x00*\x00)\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0dA\
ll Files (*)\x07\x00\x00\x00\
\x0dScriptFileDlg\x01\x03\
\x00\x00\x00\x04S\xd6m\x88\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x06Cancel\x07\x00\x00\x00\x0dScr\
iptFileDlg\x01\x03\x00\x00\x00\x04\
bS_\x00\x08\x00\x00\x00\x00\x06\x00\x00\x00\x04Op\
en\x07\x00\x00\x00\x0dScriptFil\
eDlg\x01\x03\x00\x00\x00\x14\x00P\x00y\x00t\
\x00h\x00o\x00nQeS\xe3e\x87N\xf6\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x11Python E\
ntry File\x07\x00\x00\x00\x0dSc\
riptFileDlg\x01\x03\x00\x00\x00\
\x12\x00P\x00y\x00t\x00h\x00o\x00n\x00 e\
\x87N\xf6\x08\x00\x00\x00\x00\x06\x00\x00\x00\x0bPyt\
hon File\x07\x00\x00\x00\x0dScr\
iptFileDlg\x01\x03\x00\x00\x000\
\x00P\x00y\x00t\x00h\x00o\x00n\x00 \x81\x1a\
g,e\x87N\xf6\x00 \x00(\x00*\x00.\x00p\
\x00y\x00 \x00*\x00.\x00p\x00y\x00w\x00)\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1aPython\
Script (*.py *.\
pyw)\x07\x00\x00\x00\x0dScriptF\
ileDlg\x01\x03\x00\x00\x00\x04S\xd6m\x88\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x06Cancel\
\x07\x00\x00\x00\x0dSubProcessD\
lg\x01\x03\x00\x00\x00\x04Qs\x95\xed\x08\x00\x00\x00\
\x00\x06\x00\x00\x00\x05Close\x07\x00\x00\x00\x0d\
SubProcessDlg\x01\x03\x00\
\x00\x00\x0abSS\x05[\x8cb\x10\xff\x01\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x05Done!\x07\x00\x00\x00\
\x0dSubProcessDlg\x01\x03\
\x00\x00\x00 \x8f\xd0\x88L~\xd3g_\xff\x0cOF\
g\x09\x95\x19\x8b\xefS\xd1u\x1f\xff\x0c\x90\x00Q\xfa\
x\x01N:\x08\x00\x00\x00\x00\x06\x00\x00\x008Ex\
ecution ends, bu\
t an error occur\
s and the exit c\
ode is\x07\x00\x00\x00\x0dSubPr\
ocessDlg\x01\x03\x00\x00\x00\x0cbS\
_\x00\x8f\x93Q\xfaOM\x7fn\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x09Open Dist\x07\x00\x00\
\x00\x0dSubProcessDlg\x01\
\x03\x00\x00\x006\x8b\xf7h\xc0g\xe5f/T&]\
\xf2~\xcf[\x89\x88\xc5kcxnrHg,v\
\x84\x00 \x00P\x00y\x00I\x00n\x00s\x00t\x00\
a\x00l\x00l\x00e\x00r0\x02\x08\x00\x00\x00\x00\
\x06\x00\x00\x00MPlease chec\
k if you have in\
stalled the corr\
ect version of P\
yInstaller or no\
t.\x07\x00\x00\x00\x0dSubProces\
sDlg\x01\x03\x00\x00\x00\x1e\x00P\x00y\x00I\
\x00n\x00s\x00t\x00a\x00l\x00l\x00e\x00r\
\x00 \x95\x19\x8b\xef\xff\x01\x08\x00\x00\x00\x00\x06\x00\x00\
\x00\x12PyInstaller Er\
ror!\x07\x00\x00\x00\x0dSubProc\
essDlg\x01\x03\x00\x00\x00$\x00P\x00y\
\x00I\x00n\x00s\x00t\x00a\x00l\x00l\x00e\
\x00r\x00 [P\x8f\xdbz\x0b\x8f\x93Q\xfa\xff\x1a\
\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1ePyInst\
aller subprocess\
output:\x07\x00\x00\x00\x0dSub\
ProcessDlg\x01\x03\x00\x00\x00\x0a\
^\x94u(V\xfeh\x07\xff\x1a\x08\x00\x00\x00\x00\x06\
\x00\x00\x00\x09App icon:\x07\x00\x00\
\x00\x12WinMacCenterWi\
dget\x01\x03\x00\x00\x00\x04mO\x89\xc8\x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x06Browse\x07\x00\
\x00\x00\x12WinMacCenterW\
idget\x01\x03\x00\x00\x00\x04\x95\x19\x8b\xef\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x05Error\x07\x00\
\x00\x00\x12WinMacCenterW\
idget\x01\x03\x00\x00\x00\x14N:h\x07Q\
\xc6\x00I\x00/\x00OT/u(~\xc8z\xef\x08\
\x00\x00\x00\x00\x06\x00\x00\x00&Open a \
console window f\
or standard I/O\x07\
\x00\x00\x00\x12WinMacCenter\
Widget\x01\x03\x00\x00\x00\x12bS_\x00\
v\x84V\xfeh\x07\x8d\xef_\x84\xff\x1a\x00 \x08\x00\
\x00\x00\x00\x06\x00\x00\x00\x12Opened i\
con path: \x07\x00\x00\x00\x12W\
inMacCenterWidge\
t\x01\x03\x00\x00\x00\x08V\xfeh\x07\x8d\xef_\x84\x08\
\x00\x00\x00\x00\x06\x00\x00\x00\x11Path to\
icon file\x07\x00\x00\x00\x12W\
inMacCenterWidge\
t\x01\x03\x00\x00\x00&\x5c\x06N:bSS\x05z\
\x0b^\x8fv\x84\x00 \x00s\x00t\x00d\x00i\x00\
o\x00 T/u(~\xc8z\xef0\x02\x08\x00\x00\
\x00\x00\x06\x00\x00\x00\x19Terminal \
will be enabled.\
\x07\x00\x00\x00\x12WinMacCente\
rWidget\x01\x03\x00\x00\x00(N\x0dO\
\x1aN:bSS\x05z\x0b^\x8fv\x84\x00 \x00\
s\x00t\x00d\x00i\x00o\x00 T/u(~\
\xc8z\xef0\x02\x08\x00\x00\x00\x00\x06\x00\x00\x00\x1dT\
erminal will not\
be enabled.\x07\x00\x00\x00\
\x12WinMacCenterWid\
get\x01\x03\x00\x00\x00&\x90\x09b\xe9v\x84N\
\x0df/g\x09eHv\x84V\xfeh\x07e\x87N\
\xf6\xff\x0c\x8b\xf7\x91\xcde\xb0\x90\x09b\xe9\xff\x01\x08\
\x00\x00\x00\x00\x06\x00\x00\x00<The sel\
ection is not a \
valid icon file,\
please re-selec\
t it!\x07\x00\x00\x00\x12WinMac\
CenterWidget\x01\
\x00\x00\x0c\xf9\
\x89\
PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\
@ -3680,7 +4152,7 @@ tware Foundation\
3 of the Licens\
e, or any later \
version.\x0a\x0aCopyri\
ght \xc2\xa9 2022-2023\
ght \xc2\xa9 2022-2024\
[Muzing \x5c<muzi\
2001@foxmail.com\
\x5c>](https://muzi\
@ -3726,7 +4198,7 @@ e) \xe7\x9a\x84\xe7\xba\xa6\xe6\x9d\x9f\xe4\xb8\x8b\xef\
\xb6\xe8\xbf\x9b\xe8\xa1\x8c\xe5\x86\x8d\xe5\x8f\x91\xe5\xb8\x83\
\xe5\x92\x8c/\xe6\x88\x96\xe4\xbf\xae\xe6\x94\xb9\xe3\x80\x82\
\x0a\x0a\xe7\x89\x88\xe6\x9d\x83\xe6\x89\x80\xe6\x9c\x89 \xc2\
\xa9 2022-2023 [Mu\
\xa9 2022-2024 [Mu\
zing \x5c<muzi2001@\
foxmail.com\x5c>](h\
ttps://muzing.to\
@ -3742,6 +4214,14 @@ qt_resource_name = b"\
\x00O\xa6S\
\x00I\
\x00c\x00o\x00n\x00s\
\x00\x04\
\x00\x06\xc4\xee\
\x00i\
\x001\x008\x00n\
\x00\x08\
\x0e8\x05}\
\x00z\
\x00h\x00_\x00C\x00N\x00.\x00q\x00m\
\x00\x14\
\x01O\xad\x98\
\x00P\
@ -3779,32 +4259,36 @@ qt_resource_name = b"\
"
qt_resource_struct = b"\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x01\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x10\x00\x02\x00\x00\x00\x06\x00\x00\x00\x07\
\x00\x00\x00 \x00\x02\x00\x00\x00\x01\x00\x00\x00\x0e\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x03\
\x00\x00\x00\x10\x00\x02\x00\x00\x00\x06\x00\x00\x00\x08\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\xc6\x00\x00\x00\x00\x00K\x00\x00\x80\xaa\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\xc6\x00\x00\x00\x00\x00:\x00\x00\xb2A\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\xf2\x00\x00\x00\x00\x00K\x00\x00\xe1\x9d\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\xf2\x00\x00\x00\x00\x00:\x00\x00\xe4\xb0\
\x00\x00\x01\x8c\x9a\xb7\xd3\xac\
\x00\x00\x00\x9a\x00\x00\x00\x00\x00\x01\x00\x00f\x93\
\x00\x00\x01\x8c\xbd[\xc8Z\
\x00\x00\x00 \x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x8c\x9a\xb7\xd3\xaa\
\x00\x00\x00l\x00\x00\x00\x00\x00\x01\x00\x00\x19\xb6\
\x00\x00\x01\x8c\x9a\xb7\xd3\xab\
\x00\x00\x00\xaa\x00\x00\x00\x00\x00\x01\x00\x00w_\
\x00\x00\x01\x8c\xb3\xa0\x98\xeb\
\x00\x00\x00~\x00\x00\x00\x00\x00\x01\x00\x00<\x13\
\x00\x00\x01\x8c\x9a\xb7\xd3\xab\
\x00\x00\x00N\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xfd\
\x00\x00\x01\x8c\x9a\xb7\xd3\xaa\
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x04\
\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\xea\x00\x00\x00\x00\x00K\x00\x00\x9e\x0c\
\x00\x00\x01\x8c\x9fP\xce\x07\
\x00\x00\x00\xea\x00\x00\x002\x00:\x00\x00\xcf\xa3\
\x00\x00\x01\x8c\x9fP\xce\x07\
\x00\x00\x01\x16\x00\x00\x00\x00\x00K\x00\x00\xfe\xff\
\x00\x00\x01\x8c\xd4u\x1b\xc8\
\x00\x00\x01\x16\x00\x00\x002\x00:\x00\x01\x02\x12\
\x00\x00\x01\x8c\xd4u\x1b\xcf\
\x00\x00\x00\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x83\xf5\
\x00\x00\x01\x8c\xbd\xfa\xbd\x88\
\x00\x00\x00D\x00\x00\x00\x00\x00\x01\x00\x00\x1db\
\x00\x00\x01\x8b\xbd\x8a$\x9a\
\x00\x00\x00\x90\x00\x00\x00\x00\x00\x01\x00\x007\x18\
\x00\x00\x01\x8cz\xef\xd4\x05\
\x00\x00\x00\xce\x00\x00\x00\x00\x00\x01\x00\x00\x94\xc1\
\x00\x00\x01\x8c\xb3\x93\xcb\xe3\
\x00\x00\x00\xa2\x00\x00\x00\x00\x00\x01\x00\x00Yu\
\x00\x00\x01\x8c\xbd\xfa\xbd\x88\
\x00\x00\x00r\x00\x00\x00\x00\x00\x01\x00\x00*_\
\x00\x00\x01\x8b\xbd\x8a$\x9a\
\x00\x00\x00.\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
\x00\x00\x01\x8c\xd3\xb8s\xe7\
"

View File

@ -6,4 +6,4 @@ This program is **open source software**: all source code is hosted on [GitHub](
This program is **free software**: you can redistribute it and/or modify it under the terms of the [GNU General Public License](https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license) as published by the Free Software Foundation, either version 3 of the License, or any later version.
Copyright © 2022-2023 [Muzing \<muzi2001@foxmail.com\>](https://muzing.top/about)
Copyright © 2022-2024 [Muzing \<muzi2001@foxmail.com\>](https://muzing.top/about)

View File

@ -6,4 +6,4 @@ Py2exe-GUI 是一个基于 [PyInstaller](https://pyinstaller.org/) 的图形化
本程序为**自由软件**:在自由软件联盟发布的 [*GNU 通用公共许可协议第3版或更新的版本*](https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license) 的约束下,你可以对其进行再发布和/或修改。
版权所有 © 2022-2023 [Muzing \<muzi2001@foxmail.com\>](https://muzing.top/about)
版权所有 © 2022-2024 [Muzing \<muzi2001@foxmail.com\>](https://muzing.top/about)

Binary file not shown.

View File

@ -0,0 +1,540 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN" sourcelanguage="en">
<context>
<name>AboutDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="138"/>
<source>About</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="163"/>
<source>Can&apos;t open the About document, try to reinstall this program.</source>
<translation></translation>
</message>
</context>
<context>
<name>AddDataWindow</name>
<message>
<location filename="../../Widgets/add_data_widget.py" line="71"/>
<source>Add Files</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="88"/>
<source>&amp;New</source>
<translation>(&amp;N)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="89"/>
<source>&amp;Browse File</source>
<translation>(&amp;B)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="90"/>
<source>Browse &amp;Folder</source>
<translation>(&amp;F)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="91"/>
<source>&amp;Delete</source>
<translation>(&amp;D)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="93"/>
<source>&amp;OK</source>
<translation>(&amp;O)</translation>
</message>
<message>
<location filename="../../Widgets/add_data_widget.py" line="94"/>
<source>&amp;Cancel</source>
<translation>(&amp;C)</translation>
</message>
</context>
<context>
<name>ArgumentsBrowser</name>
<message>
<location filename="../../Widgets/arguments_browser.py" line="65"/>
<source>Copy</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/arguments_browser.py" line="67"/>
<source>Export</source>
<translation></translation>
</message>
</context>
<context>
<name>CenterWidget</name>
<message>
<location filename="../../Widgets/center_widget.py" line="128"/>
<source>Python entry script path</source>
<translation>Python </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="129"/>
<location filename="../../Widgets/center_widget.py" line="132"/>
<source>Browse</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="124"/>
<source>Python script:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="135"/>
<source>App Name:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="136"/>
<source>Bundled app name</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="138"/>
<source>One Folder/ One File:</source>
<translation>/</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="139"/>
<source>One Folder</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="141"/>
<source>One File</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="145"/>
<location filename="../../Widgets/center_widget.py" line="147"/>
<source>Add Data Files</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="146"/>
<location filename="../../Widgets/center_widget.py" line="148"/>
<source>Add Binary Files</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="150"/>
<source>Hidden Import</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="153"/>
<source>Clean</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="157"/>
<source>Bundle!</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="212"/>
<source>Bundling into one folder.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="215"/>
<source>Bundling into one file.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="229"/>
<source>Add data files updated.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="244"/>
<source>Add binary files updated.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="261"/>
<source>Hidden import updated.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="277"/>
<source>Clean cache and remove temporary files before building.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="282"/>
<source>Will not delete cache and temporary files.</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="375"/>
<source>Opened script path: </source>
<translation> </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="383"/>
<source>The app name has been set to:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="399"/>
<location filename="../../Widgets/center_widget.py" line="472"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="403"/>
<source>The selection is not a valid Python script file, please reselect it!</source>
<translation>Python脚本文件</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="450"/>
<source>Warning</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="454"/>
<source>Pyinstaller doesn&apos;t seem to be installed in this Python environment, still continue?</source>
<translation> Python Pyinstaller</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="476"/>
<source>The selection is not a valid Python interpreter, please reselect it!</source>
<translation>Python解释器</translation>
</message>
</context>
<context>
<name>IconFileDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="78"/>
<source>Icon Files (*.ico *.icns)</source>
<translation> (*.ico *.icns)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="79"/>
<source>All Files (*)</source>
<translation> (*)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="83"/>
<source>App Icon</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="84"/>
<source>Icon File</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="85"/>
<source>Open</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="86"/>
<source>Cancel</source>
<translation></translation>
</message>
</context>
<context>
<name>InterpreterFileDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="104"/>
<source>Python Interpreter</source>
<translation>Python </translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="108"/>
<source>Executable File</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="113"/>
<source>Python Interpreter (python.exe)</source>
<translation>Python (python.exe)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="114"/>
<source>Executable Files (*.exe)</source>
<translation> (*.exe)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="115"/>
<location filename="../../Widgets/dialog_widgets.py" line="122"/>
<source>All Files (*)</source>
<translation> (*)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="121"/>
<source>Python Interpreter (python3*)</source>
<translation>Python (python3*)</translation>
</message>
</context>
<context>
<name>MainApp</name>
<message>
<location filename="../../__main__.py" line="36"/>
<source>Ready.</source>
<translation></translation>
</message>
</context>
<context>
<name>MainWindow</name>
<message>
<location filename="../../Widgets/main_window.py" line="67"/>
<source>&amp;File</source>
<translation>(&amp;F)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="68"/>
<source>Import Config From JSON File</source>
<translation> JSON </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="69"/>
<source>Export Config To JSON File</source>
<translation> JSON </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="71"/>
<source>&amp;Settings</source>
<translation>(&amp;S)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="73"/>
<source>&amp;Exit</source>
<translation>退(&amp;E)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="75"/>
<source>&amp;Help</source>
<translation>(&amp;H)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="78"/>
<source>PyInstaller Documentation</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="82"/>
<source>PyInstaller Options Details</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="87"/>
<source>Report Bugs</source>
<translation> Bug</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="90"/>
<source>&amp;About</source>
<translation>(&amp;A)</translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="91"/>
<source>About This Program</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/main_window.py" line="92"/>
<source>About &amp;Qt</source>
<translation> &amp;Qt</translation>
</message>
</context>
<context>
<name>MultiItemEditWindow</name>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="72"/>
<source>&amp;New</source>
<translation>(&amp;N)</translation>
</message>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="73"/>
<source>&amp;Delete</source>
<translation>(&amp;D)</translation>
</message>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="75"/>
<source>&amp;OK</source>
<translation>(&amp;O)</translation>
</message>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="76"/>
<source>&amp;Cancel</source>
<translation>(&amp;C)</translation>
</message>
</context>
<context>
<name>MultiPkgEditWindow</name>
<message>
<location filename="../../Widgets/multi_item_edit_widget.py" line="192"/>
<source>&amp;Browse packages</source>
<translation>(&amp;B)</translation>
</message>
</context>
<context>
<name>PkgBrowserDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="184"/>
<source>Installed Packages</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="189"/>
<source>Name</source>
<translatorcomment></translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="190"/>
<source>Version</source>
<translation></translation>
</message>
</context>
<context>
<name>PyinstallerOptionTable</name>
<message>
<location filename="../../Widgets/pyinstaller_option_widget.py" line="76"/>
<source>Option</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/pyinstaller_option_widget.py" line="77"/>
<source>Description</source>
<translation></translation>
</message>
</context>
<context>
<name>ScriptFileDlg</name>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="49"/>
<source>Python Script (*.py *.pyw)</source>
<translation>Python (*.py *.pyw)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="50"/>
<source>All Files (*)</source>
<translation> (*)</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="56"/>
<source>Python Entry File</source>
<translation>Python入口文件</translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="59"/>
<source>Python File</source>
<translation>Python </translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="60"/>
<source>Open</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/dialog_widgets.py" line="61"/>
<source>Cancel</source>
<translation></translation>
</message>
</context>
<context>
<name>SubProcessDlg</name>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="78"/>
<source>Done!</source>
<translatorcomment>PyInstaller运行完成</translatorcomment>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="79"/>
<location filename="../../__main__.py" line="94"/>
<source>Open Dist</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="85"/>
<source>Execution ends, but an error occurs and the exit code is</source>
<translation>退</translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="68"/>
<location filename="../../Widgets/subprocess_widget.py" line="87"/>
<location filename="../../__main__.py" line="91"/>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="90"/>
<source>PyInstaller Error!</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="92"/>
<source>PyInstaller subprocess output:</source>
<translation>PyInstaller </translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="99"/>
<source>Please check if you have installed the correct version of PyInstaller or not.</source>
<translation> PyInstaller</translation>
</message>
<message>
<location filename="../../Widgets/subprocess_widget.py" line="100"/>
<location filename="../../__main__.py" line="100"/>
<source>Close</source>
<translation></translation>
</message>
</context>
<context>
<name>WinMacCenterWidget</name>
<message>
<location filename="../../Widgets/center_widget.py" line="519"/>
<source>App icon:</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="521"/>
<source>Path to icon file</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="522"/>
<source>Browse</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="527"/>
<source>Open a console window for standard I/O</source>
<translation>I/O启用终端</translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="565"/>
<source>Terminal will be enabled.</source>
<translation> stdio </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="570"/>
<source>Terminal will not be enabled.</source>
<translation> stdio </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="615"/>
<source>Opened icon path: </source>
<translation> </translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="632"/>
<source>Error</source>
<translation></translation>
</message>
<message>
<location filename="../../Widgets/center_widget.py" line="635"/>
<source>The selection is not a valid icon file, please re-select it!</source>
<translation></translation>
</message>
</context>
</TS>

View File

@ -8,9 +8,12 @@
<file alias="Poetry">Icons/poetry-icon_128px.png</file>
<file alias="Conda">Icons/conda-icon_72px.png</file>
</qresource>
<qresource prefix="Texts" lang="zh">
<file alias="About_Text">Texts/About_zh.md</file>
<file alias="PyInstaller_Options">Texts/pyinstaller_options_zh.yaml</file>
<qresource>
<file>i18n/zh_CN.qm</file>
</qresource>
<qresource prefix="Texts" lang="zh_CN">
<file alias="About_Text">Texts/About_zh_CN.md</file>
<file alias="PyInstaller_Options">Texts/pyinstaller_options_zh_CN.yaml</file>
</qresource>
<qresource prefix="Texts" lang="en">
<file alias="About_Text">Texts/About_en.md</file>

View File

@ -6,3 +6,4 @@
from .open_qfile import QtFileOpen
from .platform_specifc_funcs import get_sys_python, open_dir_in_explorer
from .python_env import ALL_PY_ENVs, PyEnv
from .qobject_tr import QObjTr

View File

@ -0,0 +1,48 @@
# Licensed under the GPLv3 License: https://www.gnu.org/licenses/gpl-3.0.html
# For details: https://github.com/muziing/Py2exe-GUI/blob/main/README.md#license
"""自实现 QObject.tr() 方法,使得 PyCharm 等静态检查工具不再报错。
"""
__all__ = [
"QObjTr",
]
from typing import Optional
from PySide6.QtCore import QCoreApplication
class QObjTr:
"""利用 Python 多继承机制为任何需要Qt翻译的类提供类方法 `tr()`。
只能通过类名调用形如 CLASSNAME.tr()不能通过实例调用形如 self.tr()对于有继承关系的控件
通过子类的实例调用 tr() 只能得到子类方法中涉及的字符串而在父类中涉及的字符串都会丢失
假设有名为 MainWindow 的类继承自 PySide6.QtWidgets.QMainWindow需要在其实例属性中设置带翻译的文本
那么应当这样做
1. MainWindow 同时继承自 QObjTr QMainWindow`class MainWindow(QObjTr, QMainWindow): ...`
2. 在实例属性中凡需要翻译的字符串使用 MainWindow.tr()包裹比如`MainWindow.tr("&File")`
"""
@classmethod
def tr(cls, msg: str, disambiguation: Optional[str] = None, n: int = -1) -> str:
"""Returns a translated version of `msg`
**Note: Can only be used as `CLASSNAME.tr()`, not as `self.tr()`!**
**注意只能通过类名调用不能通过实例调用否则会在涉及到继承的控件中失效**
Wrap `QCoreApplication.translate()` to `QObject.tr()`.This will make PyCharm
happy. Now you can use `CLASSNAME.tr()` freely. For more details, see:
<https://doc.qt.io/qt-6/qcoreapplication.html#translate>
<https://doc.qt.io/qt-6/qobject.html#tr>
:param msg: Origin messages
:param disambiguation: Disambiguate identical text, see Qt Docs for details
:param n: Handle plural forms, see Qt Docs for details
:return: Translated messages
"""
return QCoreApplication.translate(cls.__name__, msg, disambiguation, n)

View File

@ -6,14 +6,12 @@
__all__ = ["AddDataWindow"]
import sys
from pathlib import Path
from typing import Optional
from PySide6.QtCore import QItemSelectionModel, Qt, Signal, Slot
from PySide6.QtGui import QIcon, QPixmap
from PySide6.QtWidgets import (
QApplication,
QFileDialog,
QHBoxLayout,
QHeaderView,
@ -24,8 +22,10 @@ from PySide6.QtWidgets import (
QWidget,
)
from ..Utilities import QObjTr
class AddDataWindow(QWidget):
class AddDataWindow(QObjTr, QWidget):
"""用于提供 PyInstaller --add-data 和 --add-binary 功能的窗口"""
# 类型别名
@ -68,7 +68,7 @@ class AddDataWindow(QWidget):
def _setup_ui(self) -> None:
"""处理 UI 内容"""
self.setWindowTitle("添加文件")
self.setWindowTitle(AddDataWindow.tr("Add Files"))
self.setMinimumWidth(550)
self.setWindowIcon(QIcon(QPixmap(":/Icons/Py2exe-GUI_icon_72px")))
@ -85,13 +85,13 @@ class AddDataWindow(QWidget):
1, QHeaderView.ResizeMode.ResizeToContents
)
self.new_btn.setText("新建(&N)")
self.browse_btn.setText("浏览文件(&B)")
self.browse_dir_btn.setText("浏览目录(&F)")
self.delete_btn.setText("删除(&D)")
self.new_btn.setText(AddDataWindow.tr("&New"))
self.browse_btn.setText(AddDataWindow.tr("&Browse File"))
self.browse_dir_btn.setText(AddDataWindow.tr("Browse &Folder"))
self.delete_btn.setText(AddDataWindow.tr("&Delete"))
self.ok_btn.setText("确定")
self.cancel_btn.setText("取消")
self.ok_btn.setText(AddDataWindow.tr("&OK"))
self.cancel_btn.setText(AddDataWindow.tr("&Cancel"))
# noinspection DuplicatedCode
def _setup_layout(self) -> None:
@ -119,6 +119,7 @@ class AddDataWindow(QWidget):
self.setLayout(main_layout)
# noinspection DuplicatedCode
def _connect_slots(self) -> None:
"""构建各槽函数、连接信号"""
@ -212,7 +213,6 @@ class AddDataWindow(QWidget):
self.data_selected.emit(self._submit())
self.close()
# noinspection DuplicatedCode
self.new_btn.clicked.connect(handle_new_btn)
self.delete_btn.clicked.connect(handle_delete_btn)
self.browse_btn.clicked.connect(handel_browse_btn)
@ -261,10 +261,3 @@ class AddDataWindow(QWidget):
)
self.item_table.setItem(row, 0, source_item)
self.item_table.setItem(row, 1, QTableWidgetItem(data_item[1]))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = AddDataWindow()
window.show()
sys.exit(app.exec())

View File

@ -4,7 +4,10 @@
"""此模块主要包含用于在界面上预览显示 PyInstaller 命令选项的 `ArgumentsBrowser` 类
"""
__all__ = ["get_line_continuation", "ArgumentsBrowser"]
__all__ = [
"get_line_continuation",
"ArgumentsBrowser",
]
from typing import Optional
@ -12,6 +15,7 @@ from PySide6.QtGui import QContextMenuEvent
from PySide6.QtWidgets import QMenu, QTextBrowser, QWidget
from ..Constants import RUNTIME_INFO, Platform
from ..Utilities import QObjTr
# 一组适合浅色背景的颜色
colors = ["#FD6D5A", "#FEB40B", "#6DC354", "#994487", "#518CD8", "#443295"]
@ -46,7 +50,7 @@ def wrap_font_tag(raw_text: str, color: str, **kwargs):
return f"<font {tag_attributes}>{raw_text}</font>"
class ArgumentsBrowser(QTextBrowser):
class ArgumentsBrowser(QObjTr, QTextBrowser):
"""针对命令行参数列表特别优化的文本浏览器"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -58,9 +62,9 @@ class ArgumentsBrowser(QTextBrowser):
# 右键菜单
self.context_menu = QMenu(self)
copy_action = self.context_menu.addAction("复制")
copy_action = self.context_menu.addAction(ArgumentsBrowser.tr("Copy"))
copy_action.triggered.connect(self._handle_copy_action)
export_action = self.context_menu.addAction("导出")
export_action = self.context_menu.addAction(ArgumentsBrowser.tr("Export"))
export_action.triggered.connect(self._handle_export_action)
def contextMenuEvent(self, event: QContextMenuEvent) -> None:

View File

@ -31,7 +31,7 @@ from PySide6.QtWidgets import (
from ..Constants import PyInstOpt
from ..Core import InterpreterValidator
from ..Utilities import ALL_PY_ENVs, PyEnv
from ..Utilities import ALL_PY_ENVs, PyEnv, QObjTr
from .add_data_widget import AddDataWindow
from .arguments_browser import ArgumentsBrowser
from .dialog_widgets import (
@ -45,7 +45,7 @@ from .pyenv_combobox import PyEnvComboBox
from .pyinstaller_option_widget import PyinstallerOptionTable
class CenterWidget(QWidget):
class CenterWidget(QObjTr, QWidget):
"""主界面的中央控件
此类为可以实例化的基类适用于所有平台
@ -54,7 +54,6 @@ class CenterWidget(QWidget):
# 自定义信号
option_selected = QtCore.Signal(tuple) # 用户通过界面控件选择选项后发射此信号
# option_selected 实际类型为 tuple[PyinstallerArgs, str]
def __init__(self, parent: QMainWindow) -> None:
@ -122,38 +121,40 @@ class CenterWidget(QWidget):
def _setup_ui(self) -> None:
"""设置各种控件的属性"""
self.script_path_label.setText("待打包脚本:")
self.script_path_label.setText(CenterWidget.tr("Python script:"))
self.script_path_le.setReadOnly(True)
self.script_path_le.setPlaceholderText("Python入口文件路径")
self.script_browse_btn.setText("浏览")
self.script_path_le.setPlaceholderText(
CenterWidget.tr("Python entry script path")
)
self.script_browse_btn.setText(CenterWidget.tr("Browse"))
self.script_browse_btn.setFixedWidth(80)
self.pyenv_browse_btn.setText("浏览")
self.pyenv_browse_btn.setText(CenterWidget.tr("Browse"))
self.pyenv_browse_btn.setFixedWidth(80)
self.project_name_label.setText("项目名称:")
self.project_name_le.setPlaceholderText("打包的应用程序名称")
self.project_name_label.setText(CenterWidget.tr("App Name:"))
self.project_name_le.setPlaceholderText(CenterWidget.tr("Bundled app name"))
self.fd_label.setText("单文件/单目录:")
self.one_dir_btn.setText("打包至单个目录")
self.fd_label.setText(CenterWidget.tr("One Folder/ One File:"))
self.one_dir_btn.setText(CenterWidget.tr("One Folder"))
self.one_dir_btn.setChecked(True) # 默认值
self.one_file_btn.setText("打包至单个文件")
self.one_file_btn.setText(CenterWidget.tr("One File"))
self.fd_group.addButton(self.one_dir_btn, 0)
self.fd_group.addButton(self.one_file_btn, 1)
self.add_data_btn.setText("添加数据文件")
self.add_binary_btn.setText("添加二进制文件")
self.add_data_dlg.setWindowTitle("添加数据文件")
self.add_binary_dlg.setWindowTitle("添加二进制文件")
self.add_data_btn.setText(CenterWidget.tr("Add Data Files"))
self.add_binary_btn.setText(CenterWidget.tr("Add Binary Files"))
self.add_data_dlg.setWindowTitle(CenterWidget.tr("Add Data Files"))
self.add_binary_dlg.setWindowTitle(CenterWidget.tr("Add Binary Files"))
self.hidden_import_btn.setText("隐式导入")
self.hidden_import_dlg.setWindowTitle("Hidden import")
self.hidden_import_btn.setText(CenterWidget.tr("Hidden Import"))
self.hidden_import_dlg.setWindowTitle("Hidden Import")
self.clean_checkbox.setText("清理")
self.clean_checkbox.setText(CenterWidget.tr("Clean"))
self.clean_checkbox.setChecked(False)
self.pyinstaller_args_browser.setMaximumHeight(80)
self.run_packaging_btn.setText("打包!")
self.run_packaging_btn.setText(CenterWidget.tr("Bundle!"))
self.run_packaging_btn.setEnabled(False)
# 将 PyInstaller 选项详情设置成各控件的 ToolTip
@ -183,16 +184,13 @@ class CenterWidget(QWidget):
self.option_selected.emit((PyInstOpt.script_path, file_path))
@QtCore.Slot(int)
def handle_pyenv_change(new_index: int) -> None:
"""处理用户通过选择不同的 Python 解释器时的响应
:param new_index: 选择的 Python 解释器在 `pyenv_combobox` 中的索引
"""
@QtCore.Slot()
def handle_pyenv_change() -> None:
"""处理用户通过选择不同的 Python 解释器时的响应"""
current_pyenv = self.pyenv_combobox.get_current_pyenv()
# TODO 设置为懒加载,用户打开“已安装的包”对话框时才运行
# 首次调用 current_pyenv.installed_packages 为重大性能热点,优化时应首先考虑
self.pkg_browser_dlg.load_pkg_list(current_pyenv.installed_packages)
@QtCore.Slot()
@ -211,10 +209,10 @@ class CenterWidget(QWidget):
if btn_id == 0:
self.option_selected.emit((PyInstOpt.FD, "--onedir"))
self.parent_widget.statusBar().showMessage("将打包至单个目录中")
self.show_status_msg(CenterWidget.tr("Bundling into one folder."))
elif btn_id == 1:
self.option_selected.emit((PyInstOpt.FD, "--onefile"))
self.parent_widget.statusBar().showMessage("将打包至单个文件中")
self.show_status_msg(CenterWidget.tr("Bundling into one file."))
@QtCore.Slot()
def handle_add_data_btn_clicked() -> None:
@ -228,7 +226,7 @@ class CenterWidget(QWidget):
"""用户完成了添加数据操作的槽函数"""
self.data_item_list = data_item_list
self.parent_widget.statusBar().showMessage("添加数据文件已更新")
self.show_status_msg(CenterWidget.tr("Add data files updated."))
self.option_selected.emit((PyInstOpt.add_data, data_item_list))
@QtCore.Slot()
@ -243,7 +241,7 @@ class CenterWidget(QWidget):
"""用户完成了添加二进制文件操作的槽函数"""
self.binary_item_list = binary_item_list
self.parent_widget.statusBar().showMessage("添加二进制文件已更新")
self.show_status_msg(CenterWidget.tr("Add binary files updated."))
self.option_selected.emit((PyInstOpt.add_binary, binary_item_list))
@QtCore.Slot()
@ -260,7 +258,7 @@ class CenterWidget(QWidget):
"""
self.hidden_import_list = hidden_import_list
self.parent_widget.statusBar().showMessage("隐式导入已更新")
self.show_status_msg(CenterWidget.tr("Hidden import updated."))
self.option_selected.emit((PyInstOpt.hidden_import, hidden_import_list))
@QtCore.Slot(bool)
@ -272,10 +270,16 @@ class CenterWidget(QWidget):
if selected:
self.option_selected.emit((PyInstOpt.clean, "--clean"))
self.parent_widget.statusBar().showMessage("构建前将清理缓存与临时文件")
self.show_status_msg(
CenterWidget.tr(
"Clean cache and remove temporary files before building."
)
)
else:
self.option_selected.emit((PyInstOpt.clean, ""))
self.parent_widget.statusBar().showMessage("不会删除缓存与临时文件")
self.show_status_msg(
CenterWidget.tr("Will not delete cache and temporary files.")
)
# 连接信号与槽
# 入口脚本文件
@ -285,7 +289,7 @@ class CenterWidget(QWidget):
# 添加与选择 Python 解释器
self.pyenv_browse_btn.clicked.connect(self.itp_dlg.open)
self.itp_dlg.fileSelected.connect(self._handle_itp_file_selected)
handle_pyenv_change(0) # 显式调用一次,为默认项设置相关内容
handle_pyenv_change() # 显式调用一次,为默认项设置相关内容
self.pyenv_combobox.currentIndexChanged.connect(handle_pyenv_change)
# 项目名称
@ -366,15 +370,18 @@ class CenterWidget(QWidget):
if option_key == PyInstOpt.script_path:
script_path = Path(option_value)
self.script_path_le.setText(script_path.name)
self.parent_widget.statusBar().showMessage(
f"打开脚本路径:{str(script_path.absolute())}"
self.show_status_msg(
CenterWidget.tr("Opened script path: ")
+ f"{str(script_path.absolute())}"
)
self.add_data_dlg.set_work_dir(script_path.parent)
self.add_binary_dlg.set_work_dir(script_path.parent)
elif option_key == PyInstOpt.out_name:
self.project_name_le.setText(option_value)
self.parent_widget.statusBar().showMessage(f"已将项目名设置为:{option_value}")
self.show_status_msg(
CenterWidget.tr("The app name has been set to:") + f"{option_value}"
)
@QtCore.Slot(PyInstOpt)
def handle_option_error(self, option: PyInstOpt) -> None:
@ -389,8 +396,11 @@ class CenterWidget(QWidget):
# 警告对话框
result = QMessageBox.critical(
self,
"错误",
"选择的不是有效的Python脚本文件请重新选择",
CenterWidget.tr("Error"),
CenterWidget.tr(
"The selection is not a valid Python script file, "
"please reselect it!"
),
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Ok,
)
@ -437,8 +447,11 @@ class CenterWidget(QWidget):
# TODO 自实现 MessageBox包含"仍要使用"、"取消"、"尝试安装PyInstaller"三个按钮
result = QMessageBox.warning(
self,
"警告",
"在该 Python 环境中似乎没有安装 Pyinstaller" "是否仍要继续?",
CenterWidget.tr("Warning"),
CenterWidget.tr(
"Pyinstaller doesn't seem to be installed in this Python "
"environment, still continue?"
),
QMessageBox.StandardButton.Ok,
QMessageBox.StandardButton.Cancel,
)
@ -456,14 +469,25 @@ class CenterWidget(QWidget):
self.itp_dlg.close()
result = QMessageBox.critical(
self,
"错误",
"选择的不是有效的Python解释器请重新选择",
CenterWidget.tr("Error"),
CenterWidget.tr(
"The selection is not a valid Python interpreter, "
"please reselect it!"
),
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Ok,
)
if result == QMessageBox.StandardButton.Ok:
self.itp_dlg.exec()
def show_status_msg(self, msg: str) -> None:
"""向父控件QMainWindow的状态栏显示信息
:param msg: 要在状态栏显示的信息
"""
self.parent_widget.statusBar().showMessage(msg)
class WinMacCenterWidget(CenterWidget):
"""包含 Windows 与 MacOS 特有功能的主界面中央控件
@ -492,13 +516,15 @@ class WinMacCenterWidget(CenterWidget):
super()._setup_ui()
self.icon_path_label.setText("应用图标:")
self.icon_path_label.setText(WinMacCenterWidget.tr("App icon:"))
self.icon_path_le.setReadOnly(True)
self.icon_path_le.setPlaceholderText("图标文件路径")
self.icon_browse_btn.setText("浏览")
self.icon_path_le.setPlaceholderText(WinMacCenterWidget.tr("Path to icon file"))
self.icon_browse_btn.setText(WinMacCenterWidget.tr("Browse"))
self.icon_browse_btn.setFixedWidth(80)
self.console_checkbox.setText("为标准I/O启用终端")
self.console_checkbox.setText(
WinMacCenterWidget.tr("Open a console window for standard I/O")
)
self.console_checkbox.setChecked(True) # 默认值
# 将 PyInstaller 选项详情设置成各控件的 ToolTip
@ -520,8 +546,8 @@ class WinMacCenterWidget(CenterWidget):
@QtCore.Slot(str)
def handle_icon_file_selected(file_path: str) -> None:
"""
图标文件完成选择的槽函数 \n
"""图标文件完成选择的槽函数
:param file_path: 图标路径
"""
@ -536,10 +562,12 @@ class WinMacCenterWidget(CenterWidget):
if console:
self.option_selected.emit((PyInstOpt.console, "--console"))
self.parent_widget.statusBar().showMessage("将为打包程序的 stdio 启用终端")
self.show_status_msg(WinMacCenterWidget.tr("Terminal will be enabled."))
else:
self.option_selected.emit((PyInstOpt.console, "--windowed"))
self.parent_widget.statusBar().showMessage("不会为打包程序的 stdio 启用终端")
self.show_status_msg(
WinMacCenterWidget.tr("Terminal will not be enabled.")
)
# 图标文件
self.icon_browse_btn.clicked.connect(self.icon_file_dlg.open)
@ -582,9 +610,11 @@ class WinMacCenterWidget(CenterWidget):
elif option_key == PyInstOpt.icon_path:
icon_path = Path(option_value)
self.icon_path_le.setText(icon_path.name)
self.parent_widget.statusBar().showMessage(
f"打开图标路径:{str(icon_path.absolute())}"
msg = (
WinMacCenterWidget.tr("Opened icon path: ")
+ f"{str(icon_path.absolute())}"
)
self.show_status_msg(msg)
@QtCore.Slot(PyInstOpt)
def handle_option_error(self, option: PyInstOpt) -> None:
@ -599,8 +629,10 @@ class WinMacCenterWidget(CenterWidget):
self.icon_file_dlg.close()
result = QMessageBox.critical(
self.parent_widget,
"错误",
"选择的不是有效的图标文件,请重新选择!",
WinMacCenterWidget.tr("Error"),
WinMacCenterWidget.tr(
"The selection is not a valid icon file, please re-select it!"
),
QMessageBox.StandardButton.Cancel,
QMessageBox.StandardButton.Ok,
)

View File

@ -29,10 +29,10 @@ from PySide6.QtWidgets import (
)
from ..Constants import RUNTIME_INFO, Platform
from ..Utilities import QtFileOpen
from ..Utilities import QObjTr, QtFileOpen
class ScriptFileDlg(QFileDialog):
class ScriptFileDlg(QObjTr, QFileDialog):
"""用于获取入口脚本文件的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -44,15 +44,24 @@ class ScriptFileDlg(QFileDialog):
self.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
self.setViewMode(QFileDialog.ViewMode.Detail)
self.setNameFilters(("Python脚本文件 (*.py *.pyw)", "所有文件 (*)"))
self.setNameFilters(
(
ScriptFileDlg.tr("Python Script (*.py *.pyw)"),
ScriptFileDlg.tr("All Files (*)"),
)
)
self.setFileMode(QFileDialog.FileMode.ExistingFiles)
self.setLabelText(QFileDialog.DialogLabel.FileName, "Python入口文件")
self.setLabelText(QFileDialog.DialogLabel.FileType, "Python文件")
self.setLabelText(QFileDialog.DialogLabel.Accept, "打开")
self.setLabelText(QFileDialog.DialogLabel.Reject, "取消")
self.setLabelText(
QFileDialog.DialogLabel.FileName, ScriptFileDlg.tr("Python Entry File")
)
self.setLabelText(
QFileDialog.DialogLabel.FileType, ScriptFileDlg.tr("Python File")
)
self.setLabelText(QFileDialog.DialogLabel.Accept, ScriptFileDlg.tr("Open"))
self.setLabelText(QFileDialog.DialogLabel.Reject, ScriptFileDlg.tr("Cancel"))
class IconFileDlg(QFileDialog):
class IconFileDlg(QObjTr, QFileDialog):
"""用于获取应用图标文件的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -64,15 +73,20 @@ class IconFileDlg(QFileDialog):
self.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
self.setViewMode(QFileDialog.ViewMode.Detail)
self.setNameFilters(("图标文件 (*.ico *.icns)", "所有文件 (*)"))
self.setNameFilters(
(
IconFileDlg.tr("Icon Files (*.ico *.icns)"),
IconFileDlg.tr("All Files (*)"),
)
)
self.setFileMode(QFileDialog.FileMode.ExistingFile)
self.setLabelText(QFileDialog.DialogLabel.FileName, "图标")
self.setLabelText(QFileDialog.DialogLabel.FileType, "图标文件")
self.setLabelText(QFileDialog.DialogLabel.Accept, "打开")
self.setLabelText(QFileDialog.DialogLabel.Reject, "取消")
self.setLabelText(QFileDialog.DialogLabel.FileName, IconFileDlg.tr("App Icon"))
self.setLabelText(QFileDialog.DialogLabel.FileType, IconFileDlg.tr("Icon File"))
self.setLabelText(QFileDialog.DialogLabel.Accept, IconFileDlg.tr("Open"))
self.setLabelText(QFileDialog.DialogLabel.Reject, IconFileDlg.tr("Cancel"))
class InterpreterFileDlg(QFileDialog):
class InterpreterFileDlg(QObjTr, QFileDialog):
"""用于获取 Python 解释器可执行文件的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -85,17 +99,32 @@ class InterpreterFileDlg(QFileDialog):
self.setAcceptMode(QFileDialog.AcceptMode.AcceptOpen)
self.setViewMode(QFileDialog.ViewMode.Detail)
self.setFileMode(QFileDialog.FileMode.ExistingFile)
self.setLabelText(QFileDialog.DialogLabel.FileName, "Python解释器")
self.setLabelText(QFileDialog.DialogLabel.FileType, "可执行文件")
self.setLabelText(
QFileDialog.DialogLabel.FileName,
InterpreterFileDlg.tr("Python Interpreter"),
)
self.setLabelText(
QFileDialog.DialogLabel.FileType, InterpreterFileDlg.tr("Executable File")
)
# 进行一定的文件过滤
# 目前已知的可行方法只有 Windows 下按文件后缀Linux 下似乎不可行
# https://stackoverflow.com/questions/50213049/
if RUNTIME_INFO.platform == Platform.windows:
self.setNameFilters(("可执行文件 (*.exe)", "所有文件 (*)"))
self.setNameFilters(
(
InterpreterFileDlg.tr("Python Interpreter (python.exe)"),
InterpreterFileDlg.tr("Executable Files (*.exe)"),
InterpreterFileDlg.tr("All Files (*)"),
)
)
else:
self.setNameFilters(
(
InterpreterFileDlg.tr("Python Interpreter (python3*)"),
InterpreterFileDlg.tr("All Files (*)"),
)
)
class AboutDlg(QMessageBox):
class AboutDlg(QObjTr, QMessageBox):
"""用于显示关于信息的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -106,7 +135,7 @@ class AboutDlg(QMessageBox):
super().__init__(parent)
self._about_text: str = ""
self.setWindowTitle("关于")
self.setWindowTitle(AboutDlg.tr("About"))
self.setStandardButtons(QMessageBox.StandardButton.Ok)
self.setTextFormat(Qt.TextFormat.MarkdownText)
self.setText(self.about_text)
@ -124,13 +153,17 @@ class AboutDlg(QMessageBox):
with QtFileOpen(":/Texts/About_Text", encoding="utf-8") as about_file:
self._about_text = about_file.read()
except OSError as e:
warnings.warn(f"无法打开关于文档,错误信息:{e}", RuntimeWarning, stacklevel=1)
self._about_text = "无法打开关于文档,请尝试重新获取本程序。"
warnings.warn(
f"Cannot open About document: {e}", RuntimeWarning, stacklevel=1
)
self._about_text = AboutDlg.tr(
"Can't open the About document, try to reinstall this program."
)
return self._about_text
class PkgBrowserDlg(QDialog):
class PkgBrowserDlg(QObjTr, QDialog):
"""浏览已安装的所有包的对话框"""
def __init__(self, parent: Optional[QWidget] = None) -> None:
@ -148,11 +181,13 @@ class PkgBrowserDlg(QDialog):
def _setup_ui(self) -> None:
"""处理 UI"""
self.setWindowTitle("已安装的包")
self.setWindowTitle(PkgBrowserDlg.tr("Installed Packages"))
self.setWindowIcon(QIcon(QPixmap(":/Icons/Python_128px")))
self.pkg_table.setColumnCount(2)
self.pkg_table.setHorizontalHeaderLabels(["包名", "版本"])
self.pkg_table.setHorizontalHeaderLabels(
[PkgBrowserDlg.tr("Name"), PkgBrowserDlg.tr("Version")]
)
self.pkg_table.horizontalHeader().setSectionResizeMode(
0, QHeaderView.ResizeMode.Stretch
)

View File

@ -13,9 +13,9 @@ from PySide6.QtGui import QDesktopServices, QIcon, QPixmap
from PySide6.QtWidgets import QApplication, QLabel, QMainWindow, QMenuBar, QStatusBar
from ..Constants import RUNTIME_INFO, APP_URLs, AppConstant, Platform
from ..Utilities.qobject_tr import QObjTr
from .center_widget import CenterWidget, WinMacCenterWidget
from .dialog_widgets import AboutDlg
from .pyinstaller_option_widget import PyinstallerOptionTable
def open_url(url: str) -> None:
@ -27,7 +27,7 @@ def open_url(url: str) -> None:
QDesktopServices.openUrl(QUrl(url))
class MainWindow(QMainWindow):
class MainWindow(QObjTr, QMainWindow):
"""
主界面主窗口
"""
@ -64,29 +64,32 @@ class MainWindow(QMainWindow):
def _setup_menu_bar(self) -> None:
"""配置主窗口菜单栏"""
file_menu = self.menu_bar.addMenu("文件(&F)")
file_menu.addAction("打开打包任务") # 暂时只为占位
file_menu.addAction("保存当前打包任务") # 暂时只为占位
file_menu = self.menu_bar.addMenu(MainWindow.tr("&File"))
file_menu.addAction(MainWindow.tr("Import Config From JSON File")) # 暂时只为占位
file_menu.addAction(MainWindow.tr("Export Config To JSON File")) # 暂时只为占位
file_menu.addSeparator()
file_menu.addAction("设置") # 暂时只为占位
file_menu.addAction(MainWindow.tr("&Settings")) # 暂时只为占位
file_menu.addSeparator()
file_menu.addAction("退出(&X)", self.close)
file_menu.addAction(MainWindow.tr("&Exit"), self.close)
help_menu = self.menu_bar.addMenu("帮助(&H)")
help_menu = self.menu_bar.addMenu(MainWindow.tr("&Help"))
help_menu.addAction(
"PyInstaller官方文档",
MainWindow.tr("PyInstaller Documentation"),
lambda: open_url(APP_URLs["Pyinstaller_doc"]),
)
help_menu.addAction(
"PyInstaller选项详情", self.center_widget.pyinstaller_option_table.show
MainWindow.tr("PyInstaller Options Details"),
self.center_widget.pyinstaller_option_table.show,
)
help_menu.addSeparator()
help_menu.addAction("报告Bug", lambda: open_url(APP_URLs["BugTracker"]))
help_menu.addAction(
MainWindow.tr("Report Bugs"), lambda: open_url(APP_URLs["BugTracker"])
)
about_menu = self.menu_bar.addMenu("关于(&A)")
about_menu.addAction("关于本程序", AboutDlg(self).exec)
about_menu.addAction("关于 &Qt", QApplication.aboutQt)
about_menu = self.menu_bar.addMenu(MainWindow.tr("&About"))
about_menu.addAction(MainWindow.tr("About This Program"), AboutDlg(self).exec)
about_menu.addAction(MainWindow.tr("About &Qt"), QApplication.aboutQt)
def _setup_status_bar(self) -> None:
"""配置主窗口状态栏"""

View File

@ -8,7 +8,10 @@
`MultiPkgEditWindow` 继承自 `MultiItemEditWindow`多了一个浏览当前 Python 环境中已安装 Python 包的功能
"""
__all__ = ["MultiItemEditWindow", "MultiPkgEditWindow"]
__all__ = [
"MultiItemEditWindow",
"MultiPkgEditWindow",
]
from typing import Optional
@ -23,10 +26,11 @@ from PySide6.QtWidgets import (
QWidget,
)
from ..Utilities import QObjTr
from .dialog_widgets import PkgBrowserDlg
class MultiItemEditWindow(QWidget):
class MultiItemEditWindow(QObjTr, QWidget):
"""用于添加多个条目的窗口控件,实现如 --hidden-import、--collect-submodules 等功能"""
items_selected = Signal(list) # 用户在添加条目窗口完成所有编辑后,提交的信号.完整数据类型为 list[str]
@ -65,11 +69,11 @@ class MultiItemEditWindow(QWidget):
self.setWindowIcon(QIcon(QPixmap(":/Icons/Py2exe-GUI_icon_72px")))
self.new_btn.setText("新建(&N)")
self.delete_btn.setText("删除(&D)")
self.new_btn.setText(MultiItemEditWindow.tr("&New"))
self.delete_btn.setText(MultiItemEditWindow.tr("&Delete"))
self.ok_btn.setText("确定")
self.cancel_btn.setText("取消")
self.ok_btn.setText(MultiItemEditWindow.tr("&OK"))
self.cancel_btn.setText(MultiItemEditWindow.tr("&Cancel"))
# noinspection DuplicatedCode
def _setup_layout(self) -> None:
@ -185,7 +189,7 @@ class MultiPkgEditWindow(MultiItemEditWindow):
"""处理 UI"""
super()._setup_ui()
self.browse_pkg_button.setText("浏览包(&B)")
self.browse_pkg_button.setText(MultiPkgEditWindow.tr("&Browse packages"))
def _setup_layout(self) -> None:
"""构建与设置布局管理器"""

View File

@ -7,7 +7,10 @@
`PyinstallerOptionTable` 类是用于显示 PyInstaller 命令行选项的表格控件窗口界面有待进一步优化
"""
__all__ = ["load_pyinst_options", "PyinstallerOptionTable"]
__all__ = [
"load_pyinst_options",
"PyinstallerOptionTable",
]
import warnings
@ -16,7 +19,7 @@ from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import QHeaderView, QTableWidget, QTableWidgetItem
from ..Constants import RUNTIME_INFO
from ..Utilities import QtFileOpen
from ..Utilities import QObjTr, QtFileOpen
def load_pyinst_options() -> dict[str, str]:
@ -33,7 +36,7 @@ def load_pyinst_options() -> dict[str, str]:
option_file_text = option_file.read()
except OSError as e:
warnings.warn(
f"PyInstaller Options 加载失败,错误信息:{e}", RuntimeWarning, stacklevel=1
f"Failed to load PyInstaller Options: {e}", RuntimeWarning, stacklevel=1
)
return dict()
@ -57,7 +60,7 @@ def load_pyinst_options() -> dict[str, str]:
return option_dict
class PyinstallerOptionTable(QTableWidget):
class PyinstallerOptionTable(QObjTr, QTableWidget):
"""用于显示 PyInstaller 命令行选项的表格控件"""
def __init__(self) -> None:
@ -68,7 +71,12 @@ class PyinstallerOptionTable(QTableWidget):
self.setMinimumSize(700, 430)
self.setWindowIcon(QPixmap(":/Icons/PyInstaller"))
self.setColumnCount(2)
self.setHorizontalHeaderLabels(["选项", "描述"])
self.setHorizontalHeaderLabels(
[
PyinstallerOptionTable.tr("Option"),
PyinstallerOptionTable.tr("Description"),
]
)
self.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
# 存储选项信息的字典

View File

@ -18,9 +18,10 @@ from PySide6.QtWidgets import (
)
from ..Core.subprocess_tool import SubProcessTool
from ..Utilities import QObjTr
class SubProcessDlg(QDialog):
class SubProcessDlg(QObjTr, QDialog):
"""用于显示子进程信息的对话框"""
def __init__(self, parent: QWidget) -> None:
@ -64,7 +65,7 @@ class SubProcessDlg(QDialog):
if output_type == SubProcessTool.OutputType.STATE:
self.info_label.setText(output_text)
if output_text == "The process is running...":
self.multifunction_btn.setText("取消")
self.multifunction_btn.setText(SubProcessDlg.tr("Cancel"))
elif (
output_type == SubProcessTool.OutputType.STDOUT
@ -74,20 +75,32 @@ class SubProcessDlg(QDialog):
elif output_type == SubProcessTool.OutputType.FINISHED:
if output_text == "0":
self.info_label.setText("打包完成!")
self.multifunction_btn.setText("打开输出位置")
self.info_label.setText(SubProcessDlg.tr("Done!"))
self.multifunction_btn.setText(SubProcessDlg.tr("Open Dist"))
else:
self.info_label.setText(f"运行结束,但有错误发生,退出码为 {output_text}")
self.multifunction_btn.setText("取消")
self.info_label.setText(
SubProcessDlg.tr(
"Execution ends, but an error occurs and the exit code is"
)
+ f"{output_text}"
)
self.multifunction_btn.setText(SubProcessDlg.tr("Cancel"))
elif output_type == SubProcessTool.OutputType.ERROR:
self.info_label.setText("PyInstaller错误")
self.text_browser.append(f"PyInstaller 子进程输出信息:{output_text}")
self.text_browser.append("请检查是否已经安装正确版本的 PyInstaller")
self.multifunction_btn.setText("关闭")
self.info_label.setText(SubProcessDlg.tr("PyInstaller Error!"))
self.text_browser.append(
SubProcessDlg.tr("PyInstaller subprocess output:") + f"{output_text}"
)
self.text_browser.append(
SubProcessDlg.tr(
"Please check if you have installed "
"the correct version of PyInstaller or not."
)
)
self.multifunction_btn.setText(SubProcessDlg.tr("Close"))
elif not isinstance(output_type, SubProcessTool.OutputType):
raise ValueError(f"不支持的输出类型:{output_type}")
raise ValueError(f"Unsupported output type: {output_type}")
def closeEvent(self, event: QCloseEvent) -> None:
"""重写关闭事件,进行收尾清理

View File

@ -7,4 +7,4 @@ designed to provide a complete yet easy-to-use GUI for PyInstaller.
HomePage: https://github.com/muziing/Py2exe-GUI
"""
__version__ = "0.3.0"
__version__ = "0.3.1"

View File

@ -10,14 +10,14 @@
import sys
from pathlib import Path
from PySide6.QtCore import Slot
from PySide6.QtCore import QTranslator, Slot
from PySide6.QtGui import QCloseEvent
from PySide6.QtWidgets import QApplication
from .Constants import PyInstOpt
from .Constants import RUNTIME_INFO, PyInstOpt
from .Core import Packaging, PackagingTask
from .Resources import COMPILED_RESOURCES # noqa
from .Utilities import PyEnv, open_dir_in_explorer
from .Utilities import open_dir_in_explorer
from .Widgets import MainWindow, SubProcessDlg
@ -27,17 +27,16 @@ class MainApp(MainWindow):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.current_pyenv: PyEnv
self.packaging_task = PackagingTask(self)
self.packager = Packaging(self)
self.subprocess_dlg = SubProcessDlg(self)
self._connect_slots()
self.status_bar.showMessage("就绪")
self.status_bar.showMessage(MainApp.tr("Ready."))
# def show(self):
# """仅供性能分析使用,切勿取消注释!!!
# """仅供分析启动性能使用,切勿取消注释!!!
# """
#
# super().show()
@ -88,16 +87,16 @@ class MainApp(MainWindow):
"""处理子进程窗口多功能按钮点击信号的槽"""
btn_text = self.subprocess_dlg.multifunction_btn.text()
if btn_text == "取消":
if btn_text == SubProcessDlg.tr("Cancel"):
self.packager.subprocess.abort_process()
self.subprocess_dlg.close()
elif btn_text == "打开输出位置":
elif btn_text == SubProcessDlg.tr("Open Dist"):
script_path: Path = self.packaging_task.using_option[
PyInstOpt.script_path
]
dist_path = script_path.parent / "dist"
open_dir_in_explorer(dist_path)
elif btn_text == "关闭":
elif btn_text == SubProcessDlg.tr("Close"):
self.subprocess_dlg.close()
subprocess_dlg.multifunction_btn.clicked.connect(handle_mul_btn_clicked)
@ -116,6 +115,13 @@ def main() -> None:
"""应用程序主入口函数,便于 Poetry 由此函数级入口构建启动脚本"""
app = QApplication(sys.argv)
# TODO 翻译机制待优化
translator = QTranslator()
if RUNTIME_INFO.language_code == "zh_CN":
translator.load(":/i18n/zh_CN.qm")
app.installTranslator(translator)
window = MainApp()
window.show()
sys.exit(app.exec())