Python打包exe小工具,解决打包后体积过大痛点,基于坛友分享
最近更新 2026年07月11日
资源编号 22446

Python打包exe小工具,解决打包后体积过大痛点,基于坛友分享

郑重承诺丨三色资源网提供安全交易、信息保真!
增值服务:
¥ 免费 元宝
VIP折扣
    折扣详情
  • 体验VIP会员

    免费

  • 月卡VIP会员

    免费

  • 年卡VIP会员

    免费

  • 永久VIP会员

    免费

开通VIP尊享优惠特权
立即获取 升级会员
详情介绍

文章摘要

本文介绍了一个**Python打包exe**小工具,旨在解决打包后**体积**过大的痛点。其核心方法包括:临时创建**虚拟环境**、自动解析脚本**依赖**并采用清华源安装、支持

Python打包exe,解决打包后体积过大的痛点,基于坛友分享的知识和源码,表示感谢!
实现方法:
1、临时创建一个新的运行环境;
2、解析py脚本的运行依赖库,自动安装,采用清华源;
3、如果存在不能完全解析的库,可以手动添加;
4、打包结束后,删除临时运行环境。

通过网盘分享的文件:Python打包exe小工具
链接: 提取码:
–来自百度网盘超级会员v5的分享
(提示:电脑需要安装有Python环境)
Python打包exe小工具,解决打包后体积过大痛点,基于坛友分享
经实测,打包后的体积,成倍数的缩小,再一次感谢坛友的分享!
欢迎各位修改提高,也请不吝分享。

  1. # !/usr/bin/env python
  2. # coding=utf-8
  3. import sys
  4. import os
  5. import re
  6. import shutil
  7. import subprocess
  8. import venv
  9. import ast
  10. from PyQt6.QtWidgets import (QApplication, QMainWindow, QPushButton,
  11.                              QFileDialog, QLabel, QVBoxLayout, QWidget,
  12.                              QProgressBar, QCheckBox, QGroupBox, QGridLayout,
  13.                              QLineEdit, QTextEdit, QHBoxLayout, QMessageBox, QListWidget)
  14. from PyQt6.QtCore import Qt, QThread, pyqtSignal
  15. from PyQt6.QtGui import QFont
  16. PACKAGE_MAPPING = {
  17.     # 科学计算 / 数据处理
  18.     ‘PIL’: ‘Pillow’,
  19.     ‘cv2’: ‘opencv-python’,
  20.     ‘sklearn’: ‘scikit-learn’,
  21.     ‘yaml’: ‘PyYAML’,
  22.     ‘bs4’: ‘beautifulsoup4’,
  23.     ‘attr’: ‘attrs’,
  24.     ‘gi’: ‘PyGObject’,
  25.     ‘wx’: ‘wxPython’,
  26.     ‘fitz’: ‘PyMuPDF’,
  27.     ‘docx’: ‘python-docx’,
  28.     ‘pptx’: ‘python-pptx’,
  29.     ‘tables’: ‘pytables’,
  30.     ‘xlsxwriter’: ‘XlsxWriter’,
  31.     # Web / 网络
  32.     ‘jwt’: ‘PyJWT’,
  33.     ‘jose’: ‘python-jose’,
  34.     ‘dotenv’: ‘python-dotenv’,
  35.     ‘socks’: ‘PySocks’,
  36.     ‘websocket’: ‘websocket-client’,
  37.     ‘flask’: ‘Flask’,
  38.     ‘django’: ‘Django’,
  39.     # GUI / 图形
  40.     ‘tkinter’: None,  # 标准库,标记为None跳过安装
  41.     ‘kivy’: ‘Kivy’,
  42.     ‘pyautogui’: ‘PyAutoGUI’,
  43.     ‘customtkinter’: ‘customtkinter’,
  44.     ‘ttkbootstrap’: ‘ttkbootstrap’,
  45.     # 数据库
  46.     ‘psycopg2’: ‘psycopg2-binary’,
  47.     ‘pymysql’: ‘PyMySQL’,
  48.     ‘mysql’: ‘mysql-connector-python’,
  49.     ‘sqlalchemy’: ‘SQLAlchemy’,
  50.     ‘sqlite3’: None,  # 标准库
  51.     # 加密 / 安全
  52.     ‘Crypto’: ‘pycryptodome’,
  53.     ‘Cryptodome’: ‘pycryptodome’,
  54.     ‘nacl’: ‘PyNaCl’,
  55.     ‘OpenSSL’: ‘pyOpenSSL’,
  56.     # 工具 / 杂项
  57.     ‘dateutil’: ‘python-dateutil’,
  58.     ‘serial’: ‘pyserial’,
  59.     ‘usb’: ‘pyusb’,
  60.     ‘magic’: ‘python-magic’,
  61.     ‘slugify’: ‘python-slugify’,
  62.     ‘barcode’: ‘python-barcode’,
  63.     ‘win32api’: ‘pywin32’,
  64.     ‘win32com’: ‘pywin32’,
  65.     ‘winreg’: None,  # 标准库
  66.     ‘apscheduler’: ‘APScheduler’,
  67.     ‘charset_normalizer’: ‘charset-normalizer’,
  68.     ‘Levenshtein’: ‘python-Levenshtein’,
  69.     ‘qrcode’: ‘qrcode’,
  70.     ‘zbar’: ‘pyzbar’,
  71. }
  72. class PackThread(QThread):
  73.     progress = pyqtSignal(str)
  74.     finished = pyqtSignal(bool, str)
  75.     stop_flag = False
  76.     def __init__(self, file_path, options, manual_deps):
  77.         super().__init__()
  78.         self.file_path = file_path
  79.         self.options = options
  80.         self.manual_deps = manual_deps
  81.         self.stop_flag = False
  82.         self.venv_dir = None
  83.     def log(self, message):
  84.         self.progress.emit(message)
  85.     def run_command(self, cmd, cwd=None, env=None):
  86.         “””执行命令并实时返回输出,统一使用UTF-8编码防止GBK崩溃”””
  87.         try:
  88.             process = subprocess.Popen(
  89.                 cmd,
  90.                 stdout=subprocess.PIPE,
  91.                 stderr=subprocess.STDOUT,
  92.                 text=True,
  93.                 encoding=’utf-8′,       # ✅ 修复: 显式指定UTF-8
  94.                 errors=’replace’,       # ✅ 修复: 无法解码的字符用替代而非抛异常
  95.                 cwd=cwd,
  96.                 env=env,
  97.                 bufsize=1,
  98.                 universal_newlines=True
  99.             )
  100.             for line in iter(process.stdout.readline, ”):
  101.                 if self.stop_flag:
  102.                     process.terminate()
  103.                     return False, “用户停止操作”
  104.                 if line:
  105.                     self.log(line.strip())
  106.             process.wait()
  107.             return process.returncode == 0, “”
  108.         except Exception as e:
  109.             return False, str(e)
  110.     def extract_imports(self, file_path):
  111.         “””使用AST提取第三方库名称,并应用包名映射”””
  112.         imports = set()
  113.         try:
  114.             with open(file_path, ‘r’, encoding=’utf-8′) as f:
  115.                 tree = ast.parse(f.read(), filename=file_path)
  116.             for node in ast.walk(tree):
  117.                 if isinstance(node, ast.Import):
  118.                     for alias in node.names:
  119.                         imports.add(alias.name.split(‘.’)[0])
  120.                 elif isinstance(node, ast.ImportFrom):
  121.                     if node.module:
  122.                         imports.add(node.module.split(‘.’)[0])
  123.         except Exception as e:
  124.             self.log(f”警告: 无法解析导入语句: {str(e)}”)
  125.         # 过滤标准库(优先使用Python内置集合,回退到手动列表)
  126.         stdlib_modules = set(sys.stdlib_module_names) if hasattr(sys, ‘stdlib_module_names’) else {
  127.             ‘os’, ‘sys’, ‘re’, ‘json’, ‘time’, ‘datetime’, ‘math’, ‘random’,
  128.             ‘collections’, ‘itertools’, ‘functools’, ‘pathlib’, ‘typing’,
  129.             ‘subprocess’, ‘shutil’, ‘glob’, ‘copy’, ‘string’, ‘io’, ‘abc’,
  130.             ‘contextlib’, ‘unittest’, ‘logging’, ‘argparse’, ‘configparser’,
  131.             ‘csv’, ‘xml’, ‘html’, ‘http’, ‘urllib’, ‘socket’, ‘ssl’, ‘threading’,
  132.             ‘multiprocessing’, ‘concurrent’, ‘asyncio’, ‘signal’, ‘mmap’, ‘struct’,
  133.             ‘codecs’, ‘unicodedata’, ‘textwrap’, ‘difflib’, ‘pprint’, ‘enum’,
  134.             ‘operator’, ‘decimal’, ‘fractions’, ‘statistics’, ‘array’,
  135.             ‘bisect’, ‘heapq’, ‘queue’, ‘types’, ‘weakref’, ‘gc’, ‘inspect’,
  136.             ‘dis’, ‘pickle’, ‘shelve’, ‘dbm’, ‘sqlite3’, ‘zlib’, ‘gzip’, ‘bz2’,
  137.             ‘lzma’, ‘zipfile’, ‘tarfile’, ‘tempfile’, ‘fnmatch’, ‘linecache’,
  138.             ‘tokenize’, ‘token’, ‘keyword’, ‘ast’, ‘symtable’, ‘compileall’,
  139.             ‘py_compile’, ‘traceback’, ‘warnings’, ‘dataclasses’,
  140.             ‘importlib’, ‘pkgutil’, ‘modulefinder’, ‘runpy’, ‘site’, ‘sysconfig’,
  141.             ‘builtins’, ‘errno’, ‘ctypes’, ‘platform’, ‘locale’, ‘gettext’,
  142.             ‘curses’, ‘readline’, ‘rlcompleter’, ‘tty’, ‘termios’, ‘pty’, ‘fcntl’,
  143.             ‘pipes’, ‘posixpath’, ‘ntpath’, ‘genericpath’, ‘posix’, ‘nt’, ‘pwd’,
  144.             ‘grp’, ‘resource’, ‘select’, ‘selectors’, ‘stat’, ‘fileinput’, ‘filecmp’,
  145.             ‘netrc’, ‘xdrlib’, ‘plistlib’, ‘hashlib’, ‘hmac’, ‘secrets’, ‘uuid’,
  146.             ‘ipaddress’, ’email’, ‘mailbox’, ‘mimetypes’, ‘base64’, ‘binascii’,
  147.             ‘quopri’, ‘uu’, ‘colorsys’, ‘imghdr’, ‘sndhdr’, ‘ossaudiodev’, ‘aifc’,
  148.             ‘sunau’, ‘wave’, ‘chunk’, ‘cgi’, ‘cgitb’, ‘wsgiref’, ‘xmlrpc’, ‘ftplib’,
  149.             ‘poplib’, ‘imaplib’, ‘nntplib’, ‘smtplib’, ‘smtpd’, ‘telnetlib’, ‘socketserver’,
  150.             ‘robotparser’, ‘webbrowser’, ‘cmd’, ‘shlex’, ‘tkinter’,
  151.             ‘turtle’, ‘turtledemo’, ‘idlelib’, ‘test’, ‘doctest’, ‘unittest’,
  152.             ‘lib2to3’, ‘pdb’, ‘profile’, ‘cProfile’, ‘timeit’, ‘trace’, ‘tracemalloc’,
  153.             ‘faulthandler’, ‘atexit’
  154.         }
  155.         mapped_deps = []
  156.         for mod in imports:
  157.             if mod in stdlib_modules or mod.startswith(‘.’):
  158.                 continue
  159.             mapped = PACKAGE_MAPPING.get(mod)
  160.             if mapped is None and mod in PACKAGE_MAPPING:
  161.                 # 显式标记为None的是标准库,跳过
  162.                 continue
  163.             mapped_deps.append(mapped if mapped else mod)
  164.         return list(set(mapped_deps))
  165.     def run(self):
  166.         if self.stop_flag:
  167.             return
  168.         script_dir = os.path.dirname(os.path.abspath(self.file_path))
  169.         script_name = os.path.basename(self.file_path)
  170.         base_name = self.options[‘name’] if self.options[‘name’] else os.path.splitext(script_name)[0]
  171.         # 清理非法字符
  172.         if not re.match(r’^[a-zA-Z0-9_\-.\u4e00-\u9fa5][a-zA-Z0-9_\-.\u4e00-\u9fa5 ]*$’, base_name):
  173.             self.finished.emit(False, “程序名称包含非法字符或格式不正确!”)
  174.             return
  175.         dist_dir = os.path.join(script_dir, ‘dist_clean’)
  176.         venv_path = os.path.join(script_dir, ‘.temp_build_venv’)
  177.         self.venv_dir = venv_path
  178.         try:
  179.             # 1. 创建虚拟环境
  180.             self.log(f”正在创建临时虚拟环境: {venv_path}”)
  181.             if os.path.exists(venv_path):
  182.                 shutil.rmtree(venv_path)
  183.             venv.create(venv_path, with_pip=True)
  184.             self.log(“虚拟环境创建成功”)
  185.             # 确定虚拟环境中的 python 和 pip 路径
  186.             if os.name == ‘nt’:
  187.                 py_exe = os.path.join(venv_path, ‘Scripts’, ‘python.exe’)
  188.                 pip_exe = os.path.join(venv_path, ‘Scripts’, ‘pip.exe’)
  189.                 pyinstaller_exe = os.path.join(venv_path, ‘Scripts’, ‘pyinstaller.exe’)
  190.             else:
  191.                 py_exe = os.path.join(venv_path, ‘bin’, ‘python’)
  192.                 pip_exe = os.path.join(venv_path, ‘bin’, ‘pip’)
  193.                 pyinstaller_exe = os.path.join(venv_path, ‘bin’, ‘pyinstaller’)
  194.             # 2. 安装 PyInstaller
  195.             self.log(“正在安装 PyInstaller…”)
  196.             success, msg = self.run_command(
  197.                 [pip_exe, ‘install’, ‘pyinstaller’, ‘-i’, ‘https://pypi.tuna.tsinghua.edu.cn/simple’, ‘–trusted-host’,
  198.                  ‘pypi.tuna.tsinghua.edu.cn’])
  199.             if not success:
  200.                 self.finished.emit(False, f”安装 PyInstaller 失败: {msg}”)
  201.                 return
  202.             # 3. 分析并安装项目依赖
  203.             self.log(“正在分析源码依赖…”)
  204.             deps = self.extract_imports(self.file_path)
  205.             # 合并手动添加的依赖
  206.             if self.manual_deps:
  207.                 for dep in self.manual_deps:
  208.                     dep = dep.strip()
  209.                     if dep and dep not in deps:
  210.                         deps.append(dep)
  211.                 self.log(f”已添加手动指定的依赖: {‘, ‘.join(self.manual_deps)}”)
  212.             if deps:
  213.                 self.log(f”最终需要安装的依赖: {‘, ‘.join(deps)}”)
  214.                 self.log(“正在安装项目依赖(使用清华源加速)…”)
  215.                 install_cmd = [pip_exe, ‘install’] + deps + [‘-i’, ‘https://pypi.tuna.tsinghua.edu.cn/simple’,
  216.                                                              ‘–trusted-host’, ‘pypi.tuna.tsinghua.edu.cn’]
  217.                 success, msg = self.run_command(install_cmd)
  218.                 if not success:
  219.                     self.log(f”部分依赖安装可能失败,继续尝试打包: {msg}”)
  220.             else:
  221.                 self.log(“未检测到明显的第三方依赖”)
  222.             # 4. 执行 PyInstaller
  223.             self.log(“开始打包…”)
  224.             command = [pyinstaller_exe]
  225.             if self.options[‘onefile’]:
  226.                 command.append(‘–onefile’)
  227.             else:
  228.                 command.append(‘–onedir’)
  229.             if self.options[‘noconsole’]:
  230.                 command.append(‘–noconsole’)
  231.                 command.append(‘–windowed’)
  232.             command.extend([‘–clean’])
  233.             command.extend([‘–distpath’, dist_dir])
  234.             command.extend([‘–workpath’, os.path.join(script_dir, ‘build_temp’)])
  235.             # 处理图标
  236.             if self.options[‘icon’] and os.path.exists(self.options[‘icon’]):
  237.                 command.extend([‘–icon’, self.options[‘icon’]])
  238.             # 处理附加数据 (images 文件夹)
  239.             images_dir = os.path.join(script_dir, ‘images’)
  240.             if os.path.exists(images_dir):
  241.                 if os.name == ‘nt’:
  242.                     command.extend([‘–add-data’, f'{images_dir};images’])
  243.                 else:
  244.                     command.extend([‘–add-data’, f'{images_dir}:images’])
  245.             command.extend([‘–name’, base_name])
  246.             command.append(self.file_path)
  247.             self.log(f”执行命令: {‘ ‘.join(command)}”)
  248.             success, msg = self.run_command(command, cwd=script_dir)
  249.             if not success:
  250.                 self.finished.emit(False, f”打包失败: {msg}”)
  251.                 return
  252.             # 5. 验证输出
  253.             output_ext = ‘.exe’ if os.name == ‘nt’ else ”
  254.             if self.options[‘onefile’]:
  255.                 final_path = os.path.join(dist_dir, f”{base_name}{output_ext}”)
  256.             else:
  257.                 final_path = os.path.join(dist_dir, base_name)
  258.             if os.path.exists(final_path):
  259.                 self.log(f”打包成功!输出路径: {final_path}”)
  260.                 self.finished.emit(True, f”转换成功!请查看 {final_path}”)
  261.             else:
  262.                 self.finished.emit(False, “打包完成但未找到输出文件,请检查日志”)
  263.         except Exception as e:
  264.             self.log(f”发生未知错误: {str(e)}”)
  265.             self.finished.emit(False, f”发生未知错误: {str(e)}”)
  266.         finally:
  267.             # 6. 清理工作
  268.             self.log(“正在清理临时文件…”)
  269.             if os.path.exists(venv_path):
  270.                 try:
  271.                     shutil.rmtree(venv_path)
  272.                     self.log(“已删除临时虚拟环境”)
  273.                 except Exception as e:
  274.                     self.log(f”删除虚拟环境失败: {str(e)}”)
  275.             build_temp = os.path.join(script_dir, ‘build_temp’)
  276.             if os.path.exists(build_temp):
  277.                 try:
  278.                     shutil.rmtree(build_temp)
  279.                 except Exception:
  280.                     pass
  281.             self.log(“清理完成”)
  282. class Py2ExeConverter(QMainWindow):
  283.     def __init__(self):
  284.         super().__init__()
  285.         self.setWindowTitle(“Python打包exe小工具”)
  286.         self.setGeometry(100, 100, 800, 650)
  287.         self.setStyleSheet(“””
  288.             QMainWindow { background-color: #f0f2f5; }
  289.             QGroupBox { font-weight: bold; color: #333; border: 1px solid #ddd; border-radius: 5px; margin-top: 10px; padding-top: 10px; }
  290.             QPushButton { background-color: #0078d4; color: white; border: none; padding: 8px 16px; border-radius: 4px; font-weight: bold; }
  291.             QPushButton:hover { background-color: #005a9e; }
  292.             QPushButton:disabled { background-color: #ccc; }
  293.             QLineEdit, QTextEdit, QListWidget { border: 1px solid #ccc; border-radius: 4px; padding: 5px; background: white; }
  294.             QProgressBar { height: 10px; border-radius: 5px; }
  295.             QProgressBar::chunk { background-color: #0078d4; }
  296.         “””)
  297.         central_widget = QWidget()
  298.         self.setCentralWidget(central_widget)
  299.         main_layout = QVBoxLayout(central_widget)
  300.         # 文件选择区域
  301.         file_group = QGroupBox(“1. 选择 Python 脚本”)
  302.         file_layout = QHBoxLayout()
  303.         self.file_input = QLineEdit()
  304.         self.file_input.setPlaceholderText(“请选择 .py 文件”)
  305.         self.file_input.setReadOnly(True)
  306.         self.btn_browse = QPushButton(“浏览”)
  307.         self.btn_browse.clicked.connect(self.browse_file)
  308.         file_layout.addWidget(self.file_input)
  309.         file_layout.addWidget(self.btn_browse)
  310.         file_group.setLayout(file_layout)
  311.         main_layout.addWidget(file_group)
  312.         # 依赖管理区域
  313.         dep_group = QGroupBox(“2. 依赖管理 (解决缺失库问题)”)
  314.         dep_layout = QVBoxLayout()
  315.         dep_hint = QLabel(“如果打包后报错缺少模块,请在此处手动添加库名(如:pandas, numpy)”)
  316.         dep_hint.setStyleSheet(“color: #666; font-size: 12px;”)
  317.         dep_layout.addWidget(dep_hint)
  318.         dep_input_layout = QHBoxLayout()
  319.         self.dep_input = QLineEdit()
  320.         self.dep_input.setPlaceholderText(“输入库名,例如: pandas”)
  321.         self.btn_add_dep = QPushButton(“添加”)
  322.         self.btn_add_dep.clicked.connect(self.add_manual_dep)
  323.         self.btn_clear_dep = QPushButton(“清空”)
  324.         self.btn_clear_dep.clicked.connect(self.clear_manual_deps)
  325.         dep_input_layout.addWidget(self.dep_input)
  326.         dep_input_layout.addWidget(self.btn_add_dep)
  327.         dep_input_layout.addWidget(self.btn_clear_dep)
  328.         dep_layout.addLayout(dep_input_layout)
  329.         self.dep_list = QListWidget()
  330.         self.dep_list.setMaximumHeight(100)
  331.         dep_layout.addWidget(self.dep_list)
  332.         dep_group.setLayout(dep_layout)
  333.         main_layout.addWidget(dep_group)
  334.         # 打包选项区域
  335.         options_group = QGroupBox(“3. 打包选项”)
  336.         options_layout = QGridLayout()
  337.         self.check_onefile = QCheckBox(“单文件模式 (–onefile)”)
  338.         self.check_onefile.setChecked(True)
  339.         options_layout.addWidget(self.check_onefile, 0, 0)
  340.         self.check_noconsole = QCheckBox(“无控制台窗口 (–windowed)”)
  341.         self.check_noconsole.setChecked(False)
  342.         options_layout.addWidget(self.check_noconsole, 0, 1)
  343.         self.input_name = QLineEdit()
  344.         self.input_name.setPlaceholderText(“可选:生成的 exe 名称”)
  345.         options_layout.addWidget(QLabel(“程序名称:”), 1, 0)
  346.         options_layout.addWidget(self.input_name, 1, 1)
  347.         self.input_icon = QLineEdit()
  348.         self.input_icon.setPlaceholderText(“可选:图标文件 (.ico)”)
  349.         self.btn_icon = QPushButton(“选择图标”)
  350.         self.btn_icon.clicked.connect(self.browse_icon)
  351.         icon_layout = QHBoxLayout()
  352.         icon_layout.addWidget(self.input_icon)
  353.         icon_layout.addWidget(self.btn_icon)
  354.         options_layout.addWidget(QLabel(“图标:”), 2, 0)
  355.         options_layout.addLayout(icon_layout, 2, 1)
  356.         options_group.setLayout(options_layout)
  357.         main_layout.addWidget(options_group)
  358.         # 控制按钮
  359.         btn_layout = QHBoxLayout()
  360.         self.btn_start = QPushButton(“开始打包”)
  361.         self.btn_start.clicked.connect(self.start_conversion)
  362.         self.btn_stop = QPushButton(“停止”)
  363.         self.btn_stop.setEnabled(False)
  364.         self.btn_stop.clicked.connect(self.stop_conversion)
  365.         btn_layout.addWidget(self.btn_start)
  366.         btn_layout.addWidget(self.btn_stop)
  367.         main_layout.addLayout(btn_layout)
  368.         # 日志区域
  369.         log_group = QGroupBox(“4. 进度日志”)
  370.         log_layout = QVBoxLayout()
  371.         self.log_text = QTextEdit()
  372.         self.log_text.setReadOnly(True)
  373.         self.log_text.setFont(QFont(“Consolas”, 9))
  374.         self.progress_bar = QProgressBar()
  375.         self.progress_bar.setTextVisible(False)
  376.         log_layout.addWidget(self.log_text)
  377.         log_layout.addWidget(self.progress_bar)
  378.         log_group.setLayout(log_layout)
  379.         main_layout.addWidget(log_group)
  380.         self.thread = None
  381.         self.manual_deps = []
  382.     def browse_file(self):
  383.         file_path, _ = QFileDialog.getOpenFileName(self, “选择 Python 脚本”, “”, “Python Files (*.py)”)
  384.         if file_path:
  385.             self.file_input.setText(file_path)
  386.     def browse_icon(self):
  387.         file_path, _ = QFileDialog.getOpenFileName(self, “选择图标”, “”, “Icon Files (*.ico);;All Files (*)”)
  388.         if file_path:
  389.             self.input_icon.setText(file_path)
  390.     def add_manual_dep(self):
  391.         dep = self.dep_input.text().strip()
  392.         if dep:
  393.             if re.match(r’^[a-zA-Z0-9_\-\.]+$’, dep):
  394.                 if dep not in self.manual_deps:
  395.                     self.manual_deps.append(dep)
  396.                     self.dep_list.addItem(dep)
  397.                     self.dep_input.clear()
  398.                 else:
  399.                     QMessageBox.warning(self, “提示”, “该依赖已存在”)
  400.             else:
  401.                 QMessageBox.warning(self, “错误”, “库名格式不正确,只能包含字母、数字、下划线、横线和点”)
  402.         else:
  403.             QMessageBox.warning(self, “提示”, “请输入库名”)
  404.     def clear_manual_deps(self):
  405.         self.manual_deps.clear()
  406.         self.dep_list.clear()
  407.     def log_message(self, msg):
  408.         self.log_text.append(msg)
  409.         scrollbar = self.log_text.verticalScrollBar()
  410.         scrollbar.setValue(scrollbar.maximum())
  411.     def start_conversion(self):
  412.         file_path = self.file_input.text()
  413.         if not file_path or not os.path.exists(file_path):
  414.             QMessageBox.warning(self, “错误”, “请先选择一个有效的 Python 脚本文件!”)
  415.             return
  416.         options = {
  417.             ‘onefile’: self.check_onefile.isChecked(),
  418.             ‘noconsole’: self.check_noconsole.isChecked(),
  419.             ‘name’: self.input_name.text().strip(),
  420.             ‘icon’: self.input_icon.text().strip()
  421.         }
  422.         self.btn_start.setEnabled(False)
  423.         self.btn_stop.setEnabled(True)
  424.         self.log_text.clear()
  425.         self.progress_bar.setRange(0, 0)
  426.         self.thread = PackThread(file_path, options, self.manual_deps)
  427.         self.thread.progress.connect(self.log_message)
  428.         self.thread.finished.connect(self.on_finished)
  429.         self.thread.start()
  430.     def stop_conversion(self):
  431.         if self.thread:
  432.             self.thread.stop_flag = True
  433.             self.log_message(“正在请求停止…”)
  434.             self.btn_stop.setEnabled(False)
  435.     def on_finished(self, success, message):
  436.         self.btn_start.setEnabled(True)
  437.         self.btn_stop.setEnabled(False)
  438.         self.progress_bar.setRange(0, 100)
  439.         self.progress_bar.setValue(100 if success else 0)
  440.         if success:
  441.             QMessageBox.information(self, “成功”, message)
  442.         else:
  443.             QMessageBox.critical(self, “失败”, message)
  444.         self.log_message(“— 任务结束 —“)
  445. if __name__ == ‘__main__’:
  446.     app = QApplication(sys.argv)
  447.     window = Py2ExeConverter()
  448.     window.show()
  449.     sys.exit(app.exec())
 

 

付费下载
当前内容需要支付免费 元宝才能下载
VIP折扣
    折扣详情
  • 体验VIP会员

    免费

  • 月卡VIP会员

    免费

  • 年卡VIP会员

    免费

  • 永久VIP会员

    免费

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

本站所有资源来源于网络,仅限用于学习研究;无任何技术支持!不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除内容。如果您喜欢,请支持正版。如有侵权请邮件与我们联系处理。

Python打包exe小工具,解决打包后体积过大痛点,基于坛友分享
下一篇:

已经没有下一篇了!

常见问题
  • 网盘有时候会因为名字 关键词导致失效 大家可以给管理员提供失效信息,我们会给大家适当积分进行奖励 我们会第一时间进行补充修正 感谢大家的配合 让我们共同努力 打造良好的资源分享平台
查看详情

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务