当前位置: 首页 > ds >正文

Python项目75:PyInstaller+Tkinter+subprocess打包工具1.0(安排 !!)

这个打包工具包含以下功能:

1.主要功能:选择Python脚本文件,设置打包选项(单文件打包、无控制台窗口),自定义程序图标,指定输出目录,实时显示打包日志。
2.自适应布局改进:使用grid布局替代部分pack布局,增强布局控制,为所有容器设置grid_columnconfigure和grid_rowconfigure的weight参数,为Entry组件添加sticky="ew"使其可以水平扩展,日志区域使用nsew粘性设置,配合滚动条实现双向扩展,设置窗口最小尺寸限制minsize(600, 400)。
3.使用说明:选择要打包的Python脚本文件(.py),根据需要设置打包选项(可选)选择程序图标(.ico),(可选)添加版本信息文件选择组件(支持.rc,.txt文件),(可选)指定输出目录,点击"开始打包"按钮启动打包过程。

4.注意事项:电脑上需要提前安装PyInstaller:pip install pyinstaller,输出目录默认使用PyInstaller的默认设置(当前目录下的dist文件夹)。在这里插入图片描述

# -*- coding: utf-8 -*-
# @Author : 小红牛
# 微信公众号:wdPython
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import subprocess
import os
import threadingclass PyInstallerPacker:def __init__(self, root):self.root = rootroot.title("PyInstaller打包exe工具1.0")root.geometry("720x550")root.minsize(640, 480)# 配置根窗口网格布局root.grid_columnconfigure(0, weight=1)root.grid_rowconfigure(0, weight=1)# 样式配置self.style = ttk.Style()self.style.configure("TButton", padding=6)self.style.configure("TLabel", padding=3)self.style.configure("TEntry", padding=3)# 主框架main_frame = ttk.Frame(root, padding=15)main_frame.grid(row=0, column=0, sticky="nsew")main_frame.grid_columnconfigure(1, weight=1)main_frame.grid_rowconfigure(3, weight=1)# 脚本选择组件ttk.Label(main_frame, text="Python脚本路径:").grid(row=0, column=0, sticky="w", pady=3)self.script_entry = ttk.Entry(main_frame)self.script_entry.grid(row=0, column=1, sticky="ew", padx=5)ttk.Button(main_frame, text="浏览",command=self.browse_script).grid(row=0, column=2, padx=5)# 打包选项框架options_frame = ttk.LabelFrame(main_frame, text="打包选项", padding=10)options_frame.grid(row=1, column=0, columnspan=3,pady=10, sticky="ew")options_frame.grid_columnconfigure(1, weight=1)# 打包选项内容self.onefile_var = tk.BooleanVar()ttk.Checkbutton(options_frame, text="单文件打包",variable=self.onefile_var).grid(row=0, column=0, sticky="w", padx=5)self.noconsole_var = tk.BooleanVar(value=True)ttk.Checkbutton(options_frame, text="无控制台窗口",variable=self.noconsole_var).grid(row=0, column=1, sticky="w", padx=5)# 图标设置ttk.Label(options_frame, text="程序图标:").grid(row=1, column=0, sticky="w", pady=5)self.icon_entry = ttk.Entry(options_frame)self.icon_entry.grid(row=1, column=1, sticky="ew", padx=5)ttk.Button(options_frame, text="选择图标",command=self.browse_icon, width=10).grid(row=1, column=2)# 版本信息设置ttk.Label(options_frame, text="版本信息文件:").grid(row=2, column=0, sticky="w", pady=5)self.version_entry = ttk.Entry(options_frame)self.version_entry.grid(row=2, column=1, sticky="ew", padx=5)ttk.Button(options_frame, text="选择文件",command=self.browse_version, width=10).grid(row=2, column=2)# 输出目录设置ttk.Label(main_frame, text="输出目录:").grid(row=2, column=0, sticky="w", pady=3)self.output_entry = ttk.Entry(main_frame)self.output_entry.grid(row=2, column=1, sticky="ew", padx=5)ttk.Button(main_frame, text="选择目录",command=self.browse_output).grid(row=2, column=2, padx=5)# 日志区域log_frame = ttk.LabelFrame(main_frame, text="打包日志", padding=5)log_frame.grid(row=3, column=0, columnspan=3,pady=10, sticky="nsew")log_frame.grid_rowconfigure(0, weight=1)log_frame.grid_columnconfigure(0, weight=1)self.log_text = tk.Text(log_frame, wrap=tk.WORD,font=('Consolas', 10))scrollbar = ttk.Scrollbar(log_frame, orient="vertical",command=self.log_text.yview)self.log_text.configure(yscrollcommand=scrollbar.set)self.log_text.grid(row=0, column=0, sticky="nsew")scrollbar.grid(row=0, column=1, sticky="ns")# 打包按钮self.pack_btn = ttk.Button(main_frame, text="开始打包",command=self.start_packing)self.pack_btn.grid(row=4, column=1, pady=10)def browse_script(self):"""选择Python脚本文件"""path = filedialog.askopenfilename(filetypes=[("Python文件", "*.py"), ("所有文件", "*.*")])if path:self.script_entry.delete(0, tk.END)self.script_entry.insert(0, os.path.normpath(path))def browse_icon(self):"""选择图标文件"""path = filedialog.askopenfilename(filetypes=[("图标文件", "*.ico"), ("所有文件", "*.*")])if path:self.icon_entry.delete(0, tk.END)self.icon_entry.insert(0, os.path.normpath(path))def browse_version(self):"""选择版本信息文件"""path = filedialog.askopenfilename(filetypes=[("资源文件", "*.rc *.txt"), ("所有文件", "*.*")])if path:self.version_entry.delete(0, tk.END)self.version_entry.insert(0, os.path.normpath(path))def browse_output(self):"""选择输出目录"""path = filedialog.askdirectory()if path:self.output_entry.delete(0, tk.END)self.output_entry.insert(0, os.path.normpath(path))def log_message(self, message):"""在日志区域显示消息"""self.log_text.insert(tk.END, message + "\n")self.log_text.see(tk.END)self.root.update_idletasks()def start_packing(self):"""启动打包过程"""script_path = self.script_entry.get()if not script_path:messagebox.showerror("错误", "请选择要打包的Python脚本!")returnif not os.path.exists(script_path):messagebox.showerror("错误", "指定的Python脚本不存在!")return# 构建PyInstaller命令cmd = ["pyinstaller", "--clean"]# 添加基本选项if self.onefile_var.get():cmd.append("--onefile")if self.noconsole_var.get():cmd.append("--onefile")cmd.append("--noconsole")# 添加图标if icon_path := self.icon_entry.get():if not os.path.exists(icon_path):messagebox.showerror("错误", "指定的图标文件不存在!")returncmd.extend(["--icon", f'"{icon_path}"'])# 添加版本信息if version_path := self.version_entry.get():if not os.path.exists(version_path):messagebox.showerror("错误", "版本信息文件不存在!")returncmd.extend(["--version-file", f'"{version_path}"'])# 添加输出目录if output_dir := self.output_entry.get():cmd.extend(["--distpath", f'"{output_dir}"'])cmd.append(f'"{script_path}"')# 初始化界面状态self.pack_btn.config(state=tk.DISABLED)self.log_text.delete(1.0, tk.END)self.log_message(">>> 开始打包命令: " + " ".join(cmd))# 启动后台线程执行打包命令threading.Thread(target=self.run_pack_command,args=(cmd,),daemon=True).start()def run_pack_command(self, cmd):"""执行打包命令"""try:process = subprocess.Popen(" ".join(cmd),stdout=subprocess.PIPE,stderr=subprocess.STDOUT,shell=True,encoding="utf-8",errors="replace")# 实时读取输出while True:output = process.stdout.readline()if output == "" and process.poll() is not None:breakif output:self.root.after(0, self.log_message, output.strip())# 处理返回结果return_code = process.poll()if return_code == 0:self.root.after(0, self.log_message, ">>> 打包成功完成!")self.root.after(0, messagebox.showinfo,"完成", "打包操作成功完成!")else:error_msg = f">>> 打包失败,错误码:{return_code}"self.root.after(0, self.log_message, error_msg)self.root.after(0, messagebox.showerror,"错误", f"打包失败,错误码:{return_code}")except Exception as e:error_msg = f">>> 发生异常错误:{str(e)}"self.root.after(0, self.log_message, error_msg)self.root.after(0, messagebox.showerror,"异常错误", f"发生未预期错误:{str(e)}")finally:self.root.after(0, self.pack_btn.config, {"state": tk.NORMAL})if __name__ == "__main__":root = tk.Tk()app = PyInstallerPacker(root)root.mainloop()

完毕!!感谢您的收看

----------★★跳转到历史博文集合★★----------
我的零基础Python教程,Python入门篇 进阶篇 视频教程 Py安装py项目 Python模块 Python爬虫 Json Xpath 正则表达式 Selenium Etree CssGui程序开发 Tkinter Pyqt5 列表元组字典数据可视化 matplotlib 词云图 Pyecharts 海龟画图 Pandas Bug处理 电脑小知识office自动化办公 编程工具 NumPy Pygame

http://www.xdnf.cn/news/5499.html

相关文章:

  • 阿里云OSS-服务端加签直传说明/示例(SpringBoot)
  • Python数据分析案例75——基于图神经网络的交通路段流量时间序列预测
  • navicat 如何导出数据库表 的这些信息 字段名 类型 描述
  • fota移植包合入后编译验证提示:File verification failed
  • Java线程池深度解析:从使用到原理全面掌握
  • KTOR for windows:無文件落地HTTP服务扫描工具
  • 【Bootstrap V4系列】学习入门教程之 组件-表单(Forms)高级用法(二)
  • 教育行业的 RAG 落地:个性化学习助手设计
  • 【Linux基础】网络相关命令
  • Client 和 Server 的关系理解
  • Yocto项目实战经验总结:从入门到高级的全面概览
  • 大模型Embedding模型介绍与使用
  • [CANN] 安装软件依赖
  • 数仓-可累计,半累加,不可累加指标,是什么,举例说明及解决方案
  • 前端面试题:说说你对 Vue 中异步组件的理解
  • jetson orin nano super AI模型部署之路(十)使用frp配置内网穿透,随时随地ssh到机器
  • 单词怎么记:以use一词为例
  • Java中Comparator排序原理详解
  • 3. 无重复字符的最长子串(滑动窗口)
  • 客户端建立一个连接需要占用客户端的端口吗
  • NHANES稀有指标推荐:HALP score
  • average per-pixel disparity error: EPE及不同距离值下的误差曲线
  • JavaScript基础-全局作用域
  • 《Python星球日记》 第53天:卷积神经网络(CNN)入门
  • DNS服务实验
  • 土耳其Koç大学指令驱动的智能综述,从文本表达到任务执行的系统探索
  • 王慧文产品课总结
  • @Transactional注解失效
  • 仿制药研发为何要上电子实验记录本?
  • 数据在内存中的存储