鱼C论坛

 找回密码
 立即注册
查看: 195|回复: 14

[作品展示] 写了一个简单的pyinstaller把py打包成exe的GUI程序

[复制链接]
回帖奖励 16 鱼币 回复本帖可获得 4 鱼币奖励! 每人限 1 次(中奖概率 50%)
发表于 2025-7-22 15:13:56 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x

源代码:


                               
登录/注册后可看大图


感觉我写的总是有点像屎山
  1. from tkinter import *
  2. from tkinter import filedialog, messagebox, ttk
  3. import os
  4. import subprocess
  5. import sys
  6. import shutil
  7. import glob



  8. class App(Tk):
  9.     def __init__(self):
  10.         super().__init__()
  11.         self.title("Pytoexe")
  12.         self.top = None
  13.         self.cmd = ""
  14.         self.run()
  15.         
  16.     def initialize(self):
  17.         self.os_type = sys.platform
  18.         self.label1 = Label(self, text="请输入Python文件路径")
  19.         self.label1.grid(row=0, column=0, padx=5, pady=5, sticky='nsew')

  20.         self.entry1 = Entry(self, width=40)
  21.         self.entry1.grid(row=0, column=1, padx=5, pady=5, sticky='nsew')

  22.         self.button1 = Button(self, text="选择文件", command=lambda :self.select_file(self.entry1))
  23.         self.button1.grid(row=1, column=0, padx=5, pady=5, sticky='w')

  24.         self.button2 = Button(self, text="进行打包", command=self.package)
  25.         self.button2.grid(row=1, column=1, padx=5, pady=5, sticky='e')

  26.         yesno = messagebox.askyesno(title="提示", message="是否已配置Python环境?")
  27.         if not yesno:
  28.             messagebox.showinfo(title="提示", message="使用该程序请先配置Python环境!")
  29.             self.destroy()
  30.         else:
  31.             messagebox.showinfo(title="提示", message="请继续使用。")
  32.         
  33.     def package(self):
  34.         if not self.top:
  35.             if os.path.exists(self.entry1.get()):
  36.                 self.cmd = f"pyinstaller --clean "{self.entry1.get()}""
  37.                 self.create_toplevel()
  38.             else:
  39.                 messagebox.showwarning(title="警告", message="请输入正确的Python文件路径!!!")
  40.         else:
  41.             messagebox.showwarning(title="警告", message="请先关闭当前窗口!!!")

  42.     def create_toplevel(self):
  43.         self.top = Toplevel(master=self)
  44.         self.tlb1 = Label(self.top, text="请输入exe文件名")
  45.         self.tlb1.grid(row=0, column=0, padx=5, pady=5, sticky='nsew')

  46.         self.tentry1 = Entry(self.top, width=30)
  47.         self.tentry1.grid(row=0, column=1, padx=5, pady=5, sticky='nsew')

  48.         self.tlb2 = Label(self.top, text="请输入exe文件路径")
  49.         self.tlb2.grid(row=1, column=0, padx=5, pady=5, sticky='nsew')

  50.         self.tentry2 = Entry(self.top, width=30)
  51.         self.tentry2.grid(row=1, column=1, padx=5, pady=5, sticky='nsew')

  52.         self.tbutton1 = Button(self.top, text="选择路径", command=self.tbutton1_callback)
  53.         self.tbutton1.grid(row=1, column=2, padx=5, pady=5, sticky='nsew')

  54.         self.tlb3 = Label(self.top, text="请输入依赖文件路径")
  55.         self.tlb3.grid(row=2, column=0, padx=5, pady=5, sticky='nsew')

  56.         self.tentry3 = Entry(self.top, width=30)
  57.         self.tentry3.grid(row=2, column=1, padx=5, pady=5, sticky='nsew')

  58.         self.tbutton2 = Button(self.top, text="选择路径", command=self.tbutton2_callback)
  59.         self.tbutton2.grid(row=2, column=2, padx=5, pady=5, sticky='nsew')

  60.         self.tlb4 = Label(self.top, text="请输入图标路径")
  61.         self.tlb4.grid(row=3, column=0, padx=5, pady=5, sticky='nsew')

  62.         self.tentry4 = Entry(self.top, width=30)
  63.         self.tentry4.grid(row=3, column=1, padx=5, pady=5, sticky='nsew')

  64.         self.tbutton3 = Button(self.top, text="添加图标", command=self.tbutton3_callback)
  65.         self.tbutton3.grid(row=3, column=2, padx=5, pady=5, sticky='nsew')

  66.         self.tlb5 = Label(self.top, text="请选择需要资源的模块名称")
  67.         self.tlb5.grid(row=4, column=0, padx=5, pady=5, sticky='nsew')

  68.         choices = ['tkinter', 'PyQt5', 'PyQt6', 'PySide2', 'PySide6', 'mmatplotlib', 'skimage', 'pandas', 'babel']
  69.         self.tcombox = ttk.Combobox(self.top, values=choices, state="readonly", width=30)
  70.         self.tcombox.set("请选择模块")
  71.         self.tcombox.bind("<<ComboboxSelected>>", self.cb_on_select)
  72.         self.tcombox.grid(row=4, column=1, padx=5, pady=5, sticky='nsew')

  73.         self.tframe = Frame(self.top)
  74.         self.tframe.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky='nsew')

  75.         self.tcheck1 = Checkbutton(self.tframe, text="是否单个文件", command=self.check1_callback)
  76.         self.tcheck1.grid(row=0, column=0, padx=5, pady=5, sticky='nsew')

  77.         self.tcheck2 = Checkbutton(self.tframe, text="是否更改文件名", command=self.check2_callback)
  78.         self.tcheck2.grid(row=0, column=1, padx=5, pady=5, sticky='nsew')

  79.         self.var1 = IntVar()
  80.         self.tcheck3 = Checkbutton(self.tframe, text="是否更改文件路径", variable=self.var1, command=self.check3_callback)
  81.         self.tcheck3.grid(row=0, column=2, padx=5, pady=5, sticky='nsew')

  82.         self.tcheck4 = Checkbutton(self.tframe, text="是否为GUI程序", command=self.check4_callback)
  83.         self.tcheck4.grid(row=1, column=0, padx=5, pady=5, sticky='nsew')

  84.         self.var2 = IntVar()
  85.         self.tcheck5 = Checkbutton(self.tframe, text="是否有依赖文件", variable=self.var2, command=self.check5_callback)
  86.         self.tcheck5.grid(row=1, column=1, padx=5, pady=5, sticky='nsew')

  87.         self.var3 = IntVar()
  88.         self.tcheck6 = Checkbutton(self.tframe, text="是否需要模块资源", variable=self.var3, command=self.check6_callback)
  89.         self.tcheck6.grid(row=1, column=2, padx=5, pady=5, sticky='nsew')

  90.         self.tbutton_package = Button(self.top, text="运行", command=self.run_cmd)
  91.         self.tbutton_package.grid(row=5, column=2, padx=5, pady=5, sticky='nsew')

  92.     def tbutton1_callback(self):
  93.         self.select_file(self.tentry2)
  94.         if self.tentry2.get():
  95.             self.var1.set(1)
  96.             self.check3_callback()
  97.    
  98.     def tbutton2_callback(self):
  99.         self.select_file(self.tentry3)
  100.         if self.tentry3.get():
  101.             self.var2.set(1)
  102.             self.check5_callback()

  103.     def tbutton3_callback(self):
  104.         self.select_file(self.tentry4)
  105.         if self.tentry4.get():
  106.             self.ico_callback()
  107.    
  108.     def ico_callback(self):
  109.         if "--icon" in self.cmd:
  110.             self.cmd = self.cmd.replace(f'--icon "{self.tentry4.get()}" ', '')
  111.         else:
  112.             if self.tentry4.get():
  113.                 self.cmd = self.cmd.replace("pyinstaller", f"pyinstaller --icon "{self.tentry4.get()}"")

  114.     def del_callback(self):
  115.         for path in ['build', '__pycache__']:
  116.             shutil.rmtree(path, ignore_errors=True)
  117.         for f in glob.glob('*.spec'):
  118.             os.remove(f)

  119.     def run_cmd(self):
  120.         """执行程序"""
  121.         if not os.path.exists(self.tentry2.get()):
  122.             messagebox.showwarning(title="警告", message="请输入正确的exe文件路径!!!")
  123.             return
  124.         
  125.         if self.cmd:
  126.             subprocess.run('python -m pip install --upgrade pip', shell=True)
  127.             subprocess.run('python -m pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple', shell=True)
  128.             subprocess.run('python -m pip install -U pyinstaller', shell=True)
  129.             subprocess.run(self.cmd, shell=True)

  130.         self.del_callback()
  131.         rt = messagebox.askokcancel("提示", "打包完成!!!\n是否关闭程序")
  132.         if rt:
  133.             exit()
  134.         else:
  135.             self.top.destroy()
  136.             self.top = None

  137.     def check1_callback(self):
  138.         if "--onefile" in self.cmd:
  139.             _ = self.cmd.replace("--onefile ", "")
  140.         else:
  141.             _ = self.cmd.replace("pyinstaller", "pyinstaller --onefile")
  142.         self.cmd = _
  143.         
  144.     def check2_callback(self):
  145.         if "--name" in self.cmd:
  146.             self.cmd = self.cmd.replace(f"--name {self.tentry1.get()} ", "")
  147.         else:
  148.             if self.tentry1.get():
  149.                 self.cmd = self.cmd.replace("pyinstaller", f"pyinstaller --name "{self.tentry1.get()}"")

  150.     def check3_callback(self):
  151.         if "--distpath" in self.cmd:
  152.             self.cmd = self.cmd.replace(f"pyinstaller --distpath="{self.tentry2.get()}" ", "")
  153.         else:
  154.             if self.tentry2.get():
  155.                 self.cmd = self.cmd.replace("pyinstaller", f"pyinstaller --distpath="{self.tentry2.get()}"")
  156.         
  157.     def check4_callback(self):
  158.         if "--windowed" in self.cmd:
  159.             _ = self.cmd.replace("--windowed ", "")
  160.         else:
  161.             _ = self.cmd.replace("pyinstaller", "pyinstaller --windowed")
  162.         self.cmd = _

  163.     def check5_callback(self):
  164.         self.datas = self.getdatas()
  165.         if "--add-data" in self.cmd:
  166.             self.cmd = self.cmd.replace(f'--add-data="{self.datas}" ', '')
  167.         else:
  168.             if self.tentry3.get():
  169.                 self.cmd = self.cmd.replace("pyinstaller", f"pyinstaller --add-data="{self.datas}"")
  170.         print(self.cmd)

  171.     def check6_callback(self):
  172.         if "--collect-data" in self.cmd:
  173.             self.cmd = self.cmd.replace(f"--collect-data {self.tcombox.get()}", "")
  174.         else:
  175.             if self.tcombox.get() != "请选择模块":
  176.                 self.cmd = self.cmd.replace("pyinstaller", f"pyinstaller --collect-data {self.tcombox.get()}")

  177.     def cb_on_select(self, event):
  178.         if self.tcombox.get() != "请选择模块":
  179.             self.var3.set(1)
  180.             self.check6_callback()

  181.     def getdatas(self):
  182.         datas = ""
  183.         file_path = self.tentry3.get()
  184.         relative_path = file_path.replace(os.path.dirname(self.entry1.get()), "").replace("/", "")
  185.         if self.os_type == "win32":
  186.             datas = f"{file_path}/*;{relative_path}"
  187.         else:
  188.             datas = f"{file_path}/*:{relative_path}"
  189.         return datas

  190.     def select_file(self, entry=None):
  191.         if entry == self.entry1:
  192.             if self.top:
  193.                 messagebox.showwarning(title="警告", message="请先关闭当前窗口!!!")
  194.                 return
  195.             file_path = filedialog.askopenfilename(filetypes=[("Python Files", "*.py")])
  196.         elif entry == self.tentry4:
  197.             file_path = filedialog.askopenfilename(filetypes=[("icon Files", "*.ico")])
  198.         else:
  199.             file_path = filedialog.askdirectory()
  200.         entry.delete(0, END)
  201.         entry.insert(0, file_path)

  202.     def run(self):
  203.         self.initialize()
  204.         self.mainloop()

  205. if __name__ == "__main__":
  206.     app = App()
  207.    
复制代码
没有把代码打包成exe文件了,不知道为什么打包成exe之后运行打包py文件总是出问题,用代码运行又没问题,不知道还有没有什么隐藏的bug,一些简单的py程序应该还是能打包的


                               
登录/注册后可看大图



屏幕截图 2025-07-22 150405.png        屏幕截图 2025-07-22 150537.png       打包的过程可能会有点久,
屏幕截图 2025-07-22 150715.png      注意这里点击确定没有关闭的话就是打包出错了
没有鱼币了,发完了

评分

参与人数 2荣誉 +7 鱼币 +8 贡献 +8 C币 +8 收起 理由
小甲鱼 + 5 + 5 + 5 + 5 无条件支持楼主!
不二如是 + 2 + 3 + 3 + 3 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2025-7-22 15:34:12 | 显示全部楼层

回帖奖励 +4 鱼币

这年头还自己写代码,羡慕
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-7-22 16:04:08 | 显示全部楼层

回帖奖励 +4 鱼币

不错不错~~
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-7-22 17:30:30 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2025-7-22 17:40:41 | 显示全部楼层

回帖奖励 +4 鱼币

真正的石山还得看我,6层If你顶的住吗

点评

我很赞同!: 3.0
我很赞同!: 3
哈哈  发表于 2025-7-22 18:35
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-7-22 18:50:45 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2025-7-22 22:47:10 | 显示全部楼层

回帖奖励 +4 鱼币

666
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2025-7-23 02:59:09 | 显示全部楼层
挺实用的哈哈
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-7-23 07:14:35 From FishC Mobile | 显示全部楼层
看不懂看不懂
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2025-7-23 11:03:55 | 显示全部楼层

回帖奖励 +4 鱼币

膜拜一下
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
膜拜膜拜
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 4 天前 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层

回帖奖励 +4 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 4 天前 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-7-31 10:19

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表