Python實現(xiàn)將文件打包為exe的完整指南
軟件介紹
因為我最近一直在用Python制作程序,每次都在cmd界面進行打包,每次都要輸出py文件路徑,感覺效率比較低,所以就做了這么一個小工具。

軟件功能
Python文件路徑
這里是輸入你要打包的py文件,路徑是可以有中文的。
ico路徑
這個是你打包的exe程序的圖標,默認沒有,當然你也可以直接輸入其路徑。
輸出程序路徑
這個就是你打包好的可執(zhí)行程序路徑,默認路徑是:C:\Users\Administrator\dist
不過我這個增加了可以自定義輸出路徑,也是支持中文路徑的,然后打包完成之后會彈窗提醒你是否打開文件路徑。

目前不支持輸出程序路徑名字自定義,后面有時間再加進去吧。
是否運行程序時出現(xiàn)cmd界面
這個一般是建議不用出現(xiàn)

要不然會額外多一個cmd界面,看著也不舒服,沒必要。
源碼提供
下面是我提供的源碼,你們可以直接用,然后就是我文末也提供了打包好了的成品,有需要也可以獲取。
import sys
import os
import subprocess
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QLineEdit,
QPushButton, QVBoxLayout, QHBoxLayout, QWidget,
QFileDialog, QTextEdit, QMessageBox, QProgressBar,
QCheckBox) # 新增QCheckBox導(dǎo)入
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QIcon
class PackagerThread(QThread):
"""打包進程的線程類,避免UI卡頓"""
log_signal = pyqtSignal(str)
progress_signal = pyqtSignal(int)
finished_signal = pyqtSignal(bool, str)
def __init__(self, python_file, icon_file=None, no_console=False, output_dir=None):
super().__init__()
self.python_file = python_file
self.icon_file = icon_file
self.no_console = no_console # 是否不顯示CMD界面
self.output_dir = output_dir # 自定義輸出目錄
def run(self):
try:
# 檢查文件是否存在
if not os.path.exists(self.python_file):
self.log_signal.emit(f"錯誤:文件 {self.python_file} 不存在")
self.finished_signal.emit(False, "文件不存在")
return
# 檢查是否安裝了pyinstaller
try:
subprocess.check_output(["pyinstaller", "--version"],
stderr=subprocess.STDOUT,
text=True)
except (subprocess.CalledProcessError, FileNotFoundError):
self.log_signal.emit("錯誤:未安裝pyinstaller,請先安裝:pip install pyinstaller")
self.finished_signal.emit(False, "未安裝pyinstaller")
return
# 構(gòu)建pyinstaller命令
cmd = ["pyinstaller", "--onefile", "--name", os.path.splitext(os.path.basename(self.python_file))[0]]
# 添加無控制臺參數(shù)(-w)
if self.no_console:
cmd.append("--windowed") # 等價于-w,不顯示控制臺
self.log_signal.emit("已啟用:運行時不顯示CMD界面")
# 添加自定義輸出目錄(--distpath)
if self.output_dir and os.path.isdir(self.output_dir):
cmd.extend(["--distpath", self.output_dir])
self.log_signal.emit(f"自定義輸出目錄:{self.output_dir}")
else:
self.log_signal.emit("使用默認輸出目錄(當前目錄下的dist文件夾)")
# 如果提供了圖標文件,則添加圖標參數(shù)
if self.icon_file and os.path.exists(self.icon_file):
cmd.extend(["--icon", self.icon_file])
self.log_signal.emit(f"使用圖標文件:{self.icon_file}")
# 添加要打包的Python文件
cmd.append(self.python_file)
self.log_signal.emit(f"開始打包,命令:{' '.join(cmd)}")
self.progress_signal.emit(20)
# 執(zhí)行打包命令
process = subprocess.Popen(cmd, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1)
# 實時輸出日志
while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break
if output:
self.log_signal.emit(output.strip())
self.progress_signal.emit(80)
# 檢查執(zhí)行結(jié)果
exit_code = process.poll()
if exit_code == 0:
# 確定最終輸出目錄(優(yōu)先使用自定義目錄)
dist_dir = self.output_dir if (self.output_dir and os.path.isdir(self.output_dir)) else os.path.join(os.getcwd(), "dist")
exe_path = os.path.join(dist_dir, os.path.splitext(os.path.basename(self.python_file))[0] + ".exe")
self.log_signal.emit(f"打包成功!可執(zhí)行文件位于:{exe_path}")
self.progress_signal.emit(100)
self.finished_signal.emit(True, exe_path)
else:
self.log_signal.emit(f"打包失敗,返回代碼:{exit_code}")
self.finished_signal.emit(False, f"打包失敗,返回代碼:{exit_code}")
except Exception as e:
self.log_signal.emit(f"發(fā)生錯誤:{str(e)}")
self.finished_signal.emit(False, str(e))
class PyToExeConverter(QMainWindow):
"""主窗口類"""
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
# 設(shè)置窗口標題和大小
self.setWindowTitle("Python轉(zhuǎn)EXE工具@阿幸")
self.setGeometry(100, 100, 800, 650) # 適當增加高度容納新控件
# 創(chuàng)建中心部件
central_widget = QWidget()
self.setCentralWidget(central_widget)
# 主布局
main_layout = QVBoxLayout(central_widget)
main_layout.setSpacing(10)
main_layout.setContentsMargins(20, 20, 20, 20)
# Python文件路徑選擇
python_file_layout = QHBoxLayout()
self.python_file_label = QLabel("Python文件路徑:")
self.python_file_edit = QLineEdit()
self.python_file_btn = QPushButton("瀏覽...")
self.python_file_btn.clicked.connect(self.select_python_file)
python_file_layout.addWidget(self.python_file_label)
python_file_layout.addWidget(self.python_file_edit)
python_file_layout.addWidget(self.python_file_btn)
# 圖標文件路徑選擇
icon_file_layout = QHBoxLayout()
self.icon_file_label = QLabel("圖標文件路徑(可選):")
self.icon_file_edit = QLineEdit()
self.icon_file_btn = QPushButton("瀏覽...")
self.icon_file_btn.clicked.connect(self.select_icon_file)
icon_file_layout.addWidget(self.icon_file_label)
icon_file_layout.addWidget(self.icon_file_edit)
icon_file_layout.addWidget(self.icon_file_btn)
# 輸出目錄選擇(新增)
output_dir_layout = QHBoxLayout()
self.output_dir_label = QLabel("輸出目錄(可選):")
self.output_dir_edit = QLineEdit()
self.output_dir_btn = QPushButton("瀏覽...")
self.output_dir_btn.clicked.connect(self.select_output_dir)
output_dir_layout.addWidget(self.output_dir_label)
output_dir_layout.addWidget(self.output_dir_edit)
output_dir_layout.addWidget(self.output_dir_btn)
# 無控制臺選項(新增)
self.no_console_check = QCheckBox("運行EXE時不顯示CMD界面")
self.no_console_check.setChecked(True) # 默認勾選
# 打包按鈕
self.pack_btn = QPushButton("開始打包")
self.pack_btn.clicked.connect(self.start_packaging)
self.pack_btn.setStyleSheet("font-size: 14px; padding: 8px;")
# 進度條
self.progress_bar = QProgressBar()
self.progress_bar.setVisible(False)
# 日志輸出區(qū)域
self.log_label = QLabel("打包日志:")
self.log_edit = QTextEdit()
self.log_edit.setReadOnly(True)
self.log_edit.setStyleSheet("background-color: #f0f0f0;")
# 添加所有部件到主布局(新增了輸出目錄和復(fù)選框)
main_layout.addLayout(python_file_layout)
main_layout.addLayout(icon_file_layout)
main_layout.addLayout(output_dir_layout)
main_layout.addWidget(self.no_console_check)
main_layout.addWidget(self.pack_btn, alignment=Qt.AlignCenter)
main_layout.addWidget(self.progress_bar)
main_layout.addWidget(self.log_label)
main_layout.addWidget(self.log_edit)
# 狀態(tài)提示
self.statusBar().showMessage("就緒")
# 新增:選擇輸出目錄
def select_output_dir(self):
dir_path = QFileDialog.getExistingDirectory(
self, "選擇輸出目錄", os.getcwd()
)
if dir_path:
self.output_dir_edit.setText(dir_path)
def select_python_file(self):
"""選擇Python文件"""
file_path, _ = QFileDialog.getOpenFileName(
self, "選擇Python文件", "", "Python Files (*.py);;All Files (*)"
)
if file_path:
self.python_file_edit.setText(file_path)
def select_icon_file(self):
"""選擇圖標文件"""
file_path, _ = QFileDialog.getOpenFileName(
self, "選擇圖標文件", "", "Icon Files (*.ico);;All Files (*)"
)
if file_path:
self.icon_file_edit.setText(file_path)
def append_log(self, text):
"""添加日志到日志區(qū)域"""
self.log_edit.append(text)
# 自動滾動到底部
self.log_edit.verticalScrollBar().setValue(
self.log_edit.verticalScrollBar().maximum()
)
def update_progress(self, value):
"""更新進度條"""
self.progress_bar.setValue(value)
def start_packaging(self):
"""開始打包過程"""
python_file = self.python_file_edit.text().strip()
icon_file = self.icon_file_edit.text().strip() if self.icon_file_edit.text().strip() else None
no_console = self.no_console_check.isChecked() # 獲取復(fù)選框狀態(tài)
output_dir = self.output_dir_edit.text().strip() if self.output_dir_edit.text().strip() else None # 獲取輸出目錄
# 驗證輸入
if not python_file:
QMessageBox.warning(self, "輸入錯誤", "請選擇要打包的Python文件")
return
if not python_file.endswith(".py"):
QMessageBox.warning(self, "文件錯誤", "請選擇擴展名為.py的Python文件")
return
# 檢查圖標文件是否存在(如果提供了的話)
if icon_file and not os.path.exists(icon_file):
QMessageBox.warning(self, "文件錯誤", f"圖標文件不存在:{icon_file}")
return
# 檢查輸出目錄是否存在(如果提供了的話)
if output_dir and not os.path.isdir(output_dir):
QMessageBox.warning(self, "目錄錯誤", f"輸出目錄不存在:{output_dir}")
return
# 準備打包
self.log_edit.clear()
self.pack_btn.setEnabled(False)
self.progress_bar.setVisible(True)
self.progress_bar.setValue(0)
self.statusBar().showMessage("正在打包...")
# 創(chuàng)建并啟動打包線程(傳入新參數(shù))
self.packager_thread = PackagerThread(
python_file,
icon_file,
no_console=no_console,
output_dir=output_dir
)
self.packager_thread.log_signal.connect(self.append_log)
self.packager_thread.progress_signal.connect(self.update_progress)
self.packager_thread.finished_signal.connect(self.on_packaging_finished)
self.packager_thread.start()
def on_packaging_finished(self, success, message):
"""打包完成后的處理"""
self.pack_btn.setEnabled(True)
self.statusBar().showMessage("打包完成" if success else "打包失敗")
if success:
QMessageBox.information(self, "成功", f"打包成功!\n可執(zhí)行文件位于:\n{message}")
# 詢問是否打開輸出目錄
if QMessageBox.question(self, "打開目錄", "是否打開輸出目錄?",
QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
output_dir = os.path.dirname(message)
if os.name == 'nt': # Windows系統(tǒng)
os.startfile(output_dir)
elif os.name == 'posix': # Linux或macOS
subprocess.run(['open' if sys.platform == 'darwin' else 'xdg-open', output_dir])
else:
QMessageBox.critical(self, "失敗", f"打包失?。篭n{message}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = PyToExeConverter()
window.show()
sys.exit(app.exec_())
到此這篇關(guān)于Python實現(xiàn)將文件打包為exe的完整指南的文章就介紹到這了,更多相關(guān)Python文件打包為exe內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Python中__new__和__init__的區(qū)別與聯(lián)系
在Python中,每個對象都有兩個特殊的方法:__new__和__init__,本文將詳細介紹這兩個方法的不同之處以及它們之間的聯(lián)系,具有一定的參考價值,感興趣的可以了解一下2023-12-12
Python實現(xiàn)將mp3音頻格式轉(zhuǎn)換為wav格式
這篇文章主要介紹了利用python寫了這個小工具,可以批量進行mp3音頻格式轉(zhuǎn)換為wav格式,文中的示例代碼講解詳細,感興趣的可以學(xué)習(xí)一下2022-01-01
Python使用擴展庫pywin32實現(xiàn)批量文檔打印實例
這篇文章主要介紹了Python使用擴展庫pywin32實現(xiàn)批量文檔打印實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
python ceiling divide 除法向上取整(或小數(shù)向上取整)的實例
今天小編就為大家分享一篇python ceiling divide 除法向上取整 (或小數(shù)向上取整)的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12

