Background
Recently, I have worked on a demo program that works on the Windows OS. However, most of my recent works are based on the python language. I really like the simplicity of the language, and don’t want to go back to use the C++ and MFC. Therefore, in this post, I will present how to use PyInstaller and Python to build an executable python program as the "*.exe" format in Windows.
Environment Preparation
- OS: Windows (currently, the PyInstaller does not support cross-platform compiling)
- IDE: PyCharm (optional)
- Python Virtual Environment Control: Anaconda or Miniconda
The following steps will prepare the required environment for the project. To ensure the compatibility of the program, please be as consistent as possible with my suggested versions.
- Python: 3.6.5
- NumPy: 1.16.4
- OpenCV: 3.4.5.20
- pillow: 8.0.1
- PyInstaller: 4.1
- pypiwin32
# run in the anaconda Prompt
conda create --name py36 python=3.6.5
conda activate py36
pip install numpy==1.16.4 opencv-python==3.4.5.20 pillow==8.0.1 pillow==4.1 pypiwin32
Create a simple GUI with tkinter
tkinter is a build-in Python interface package to build simple GUI of python.
Save the following code as "demo.py" and run it in the prepared python environment.
print("Python Code starting... (it may cost a few seconds)")
import tkinter
from PIL import ImageTk, Image
import cv2
print("Initialized, the program is now started!")
class DemoApp:
def __init__(self):
# create a window
self.window = tkinter.Tk()
# to rename the title of the window
self.window.title("Demo Application")
# add some text to our GUI
self.label = tkinter.Label(self.window, text="This is our first GUI!")
self.label.pack() # pack is used to show the object in the window
# add a button
self.button = tkinter.Button(self.window, text="Show Image", command=self.showImg)
self.button.pack() # pack is used to show the object in the window
# add an image area that will display an image
self.img_canvas = tkinter.Canvas(self.window, width=481, height=193)
self.img_canvas.pack()
# mainloop() tells Python to run the Tkinter event loop. This method listens for events, such as button clicks or keypresses
self.window.mainloop()
def showImg(self):
# Load an color image
img_cv = cv2.imread('img.jpg')
img_pil = Image.fromarray(cv2.cvtColor(img_cv, cv2.COLOR_BGR2RGB)) # from opencv to PIL image
self.imgtk = ImageTk.PhotoImage(image=img_pil) # Convert the Image object into a TkPhoto object, must use self. to ensure the image data does not be removed when leave the function
# Put it in the display window
# anchor "nw" means when creating the image for the coordinates (0,0) to represent the upper-left corner of the image
self.img_Area = self.img_canvas.create_image(0, 0, anchor="nw",image=self.imgtk)
#self.img_canvas.itemconfig(self.img_Area, image=self.imgtk)
# change the button text and action
self.button.config(text = "Close Image", command=self.clearImg)
return
def clearImg(self):
self.img_canvas.delete(self.img_Area) # empty image
# change the button text and action
self.button.config(text="Show Image", command=self.showImg)
return
if __name__ == '__main__':
# download an image for test
import urllib.request
urllib.request.urlretrieve("https://i.loli.net/2020/12/14/3dLYfJFhIlyQ2Vo.png", "img.jpg")
# start the app
app = DemoApp()
By running the above code, it can display a simple Demo application as:
Compile it to "*.exe" format
Simply using the pyinstaller to automatically finds all dependent files.
# ! bash command
pyinstaller main.py
You may use "–noconsole" to hide console window, and "–onefile" to combine all files to a single exe file. However, I strongly suggest you to use default "-D" that creates a one-folder bundle containing an executable exe, which is faster than "–onefile".
For the use of PyInstaller, more information can be obtained at https://pyinstaller.readthedocs.io/en/latest/usage.html
Then you can fin your executable at ".dist" folder!
Play with your .exe file
It will open a terminal first to startup your python script. Then, the GUI will be displayed. If you want to hide the console window, just use "–noconsole" command when you compiling your exe file (last step).
To share your program, just share the whole "./dist/demo" folder to others. Then, run the ".exe" file.