Python2-py转exe(附GUI界面)

 有时候写了一个脚本,但是换到另外一台电脑上的时候,发现并没有Python的解析环境,这时候将py文件转成exe,再将其换到另外一台Windows电脑运行,是一个很好的选择。

准备

 py转exe有:py2exe、pyinstaller等多种选择。这两种我都用过,我更倾向于pyinstaller。本文使用的就是pyinstaller。

pyinstaller

 使用pip快捷安装pyinstaller。如果对pyinstaller感兴趣,可以参考文档

1
pip install pyinstaller

 如果无法使用pip安装,可以在官网下载源码安装。
 成功安装可以输出对应版本信息。
pyinstaller version.png

py文件

 将py文件转exe,那么必备的就是py文件了。本文采用我以前写的RSA加密文件脚本,可以在这里下载

转换Exe

 有了pyinstaller之后,将py文件转成exe只需要一条命令即可完成。该条命令会生成两个文件夹:build、dist。生成的exe在dist文件夹中。

1
pyinstaller Encryptiong.py

exe转换.png

单文件生成

 刚刚转换出来的exe有许多依赖的文件在dist文件夹下。就是说想要运行这个exe,那么整个dist文件夹下所有文件都需要存在。
 pyinstaller提供了将py文件转换成单exe模式,只需要在转换命令加上-F参数即可。

1
pyinstaller Encryptiong.py -F

压缩

 如果转换出来的exe大小很大,pyinstaller也支持压缩。压缩需要下载upx,并加上对应参数即可。

1
pyinstaller Encryptiong.py -F --upx-dir D:\Code\Python27\upx394w

图标

 现在已经成功生成了exe,但是现在的exe图标很”大众”。这是pyinstaller默认图标,如果想自定义图标的话,pyinstaller也提供了对应参数-i。但是需要提供多种尺寸的ico图标,因为不同情况下需要不一样尺寸的图标。可以使用**png2ico**工具转换,使用png2ico需要使用对应的命令。

1
png2ico myicon.ico icon_128x128.png icon_64x64.png icon_48x48.png icon_32x32.png icon_16x16.png

 也可以使用在线转换工具**ConvertIcon!**,导出的时候需要勾对应尺寸。
converticon.png
 有了图标之后,使用对应命令即可。

1
pyinstaller Encryptiong.py -F --upx-dir D:\Code\Python27\upx394w -i ico.ico

GUI界面

 现在生成的exe文件,打开之后连GUI界面都没有。没有GUI界面的exe就是耍流氓。(Ps:来源某位小伙伴)我这么正经的人,怎么可能耍流氓!
 Python想要生成GUI界面,需要安装PyQt。我安装的是PyQt4。由于最新版的PyQt已经不提供Windows二进制安装程序,大家可以安装4.11.4版本。找到合适自己的版本,下载、安装即可。

UI生成

 安装完PyQt4之后,大家可以在Python27\Lib\site-packages\PyQt4文件夹找到designer.exe用来构建GUI界面的UI。
 打开designer.exe新建一个窗体,通过左边拖拽控件,将控件按照自己喜欢的位置布局到窗体里面。设计好了保存成ui文件即可。
 最后可以Python27\Lib\site-packages\PyQt4\pyuic4.bat来生成对应的布局代码。

1
pyuic4.bat -o EncryptiongUi.py EncryptiongUi.ui

 生成的布局代码文件有一个Ui类,其中包含了setupUi、retranslateUi函数。

GUI生成

 用了UI布局,现在新建一个脚本(Encry.py)通过代码生成一个窗体即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4 import QtGui
from PyQt4.QtCore import *
import sys
import EncryptiongUi


class TestDlg(QDialog, EncryptiongUi.Ui_RSA): # 继承EncryptiongUI.UI_RSA
def __init__(self, parent=None):
super(TestDlg, self).__init__(parent)
self.setupUi(self)
# self.setWindowIcon(QtGui.QIcon('./ico.ico')) # 设置icon

def main():
app = QApplication(sys.argv)
dialog = TestDlg()
dialog.show()
sys.exit(app.exec_())

if __name__ == '__main__':
main()

 运行Encry.py即可生成一个GUI界面。
GUI.png

控件功能配置

 我设计了一个包含两个line、三个button的窗体。根据button来执行Encryptiong.py的不同功能,根据line的值进行传参。
 首先对Encryptiong.py脚本进行改造。只需要把180、181注释,让其不运行即可。

1
2
# if __name__ == '__main__':
# main()

 其次对EncryptiongUI.py进行改造。导入Encryptiong的Encryptiong,用来执行加密、解密等功能。

1
from Encryptiong import Encryptiong

 接下来将按钮的单击属性打开。一共需要打开三个按钮的属性,pushButton是按钮的自定义名称,根据命名进行修改。

1
2
self.pushButton.setCheckable(True)
self.pushButton.setChecked(True)

 然后在UI类中,编写工作的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def work(self, Ctype):
try:
if Ctype == 1:
Encryptiong().encryp()
QtGui.QMessageBox.about(self, u'提醒', u"成功生成公、私钥文件!") # 设置提醒消息框
elif Ctype == 2:
public = str(self.lineEdit.text()) # 获取line的文本
filepath = str(self.lineEdit_2.text()) # 获取line2的文本
Encryptiong(public=public, filepath=filepath).encryption()
QtGui.QMessageBox.about(self, u'提醒', u"完成加密!")
elif Ctype == 3:
private = str(self.lineEdit.text())
filepath = str(self.lineEdit_2.text())
Encryptiong(private=private,decrypt=filepath).decrypted()
QtGui.QMessageBox.about(self, u'提醒', u"完成解密!")
except:
QtGui.QMessageBox.about(self, u'警告', u"输入有误,请重新输入!")

 回到Ui类的setupUi函数,设置按钮单击执行工作函数。

1
2
3
self.pushButton.clicked.connect(lambda : self.work(1))  # 单击调用work函数
self.pushButton_2.clicked.connect(lambda : self.work(2))
self.pushButton_3.clicked.connect(lambda : self.work(3))

 现在已经成功让Encryotiong脚本的功能通过GUI界面来执行、实现。最后通过pyinstaller进行打包成exe。

1
pyinstaller -F -w -i ico.ico --upx-dir D:\Code\Python27\upx394w Encryptiong.py

总结

 在编写使用pyinstaller、PyQt4生成GUI界面的exe时,遇到几个问题,在此记录一下。

  1. pyinstaller -i加载图标的时候,图标需要是多种尺寸的图标。要不然某些情况是无法显示的;
  2. pyinstaller -w生成无终端窗口需要脚本有GUI界面;
  3. PyQt4的Button执行函数,需要使用lambda生成匿名函数;
  4. PyQt4的QMessageBox进行弹框提示需要将字符串转成Unicode编码,要不然会乱码。

完整代码

 完整代码已经上传到我的GiHub。如果有兴趣,不妨移步到Github上一观!**Code**。