Create Standalone Tkinter Apps by Converting to .exe with PyInstaller

Create standalone .exe for Calculator, Database etc. #python #tkinter #PythonGUI #application #app

Install PyInstaller: This tool converts Python scripts to executables
pip install pyinstaller
Generate the desktop App : Run PyInstaller on your Python file
pyinstaller --onefile your_script.py
PyInstaller D:\\testing\\test2.py
specifying the path to create .
pyinstaller --onefile --windowed --distpath /path/to/destination your_script.py

Without using any environment variables here we are giving full path to our Python file. The command also contains first the path to destination directory D:\\my_app then the path to my soruce file D:\\testing\\your_script.py
C:/Users/---Path here --/python3.11.exe -m PyInstaller --onefile --windowed --distpath D:\\my_app D:\\testing\\your_script.py

Displaying time

Source code for showing changing time in Tkinter window
Displaying Clock in Tkinter window

clock.py : Source code or our main file.
D:\\testing\\clock.py : Full Path to our source file.
D:\\my_app : Destination path where our executable file will be stored.
>pyinstaller --onefile --windowed --distpath D:\\my_app D:\\testing\\click.py
Check the table below for details of all commands used here .

Simple Calculator application

Simple Calculator to develop application

Source code for simple Calculator application
calculator.py : Source code or our main file.
D:\\testing\\calculator.py : Full Path to our source file.
D:\\my_app : Destination path where our executable file will be stored.

>pyinstaller --onefile --windowed --distpath D:\\my_app D:\\testing\\calculator.py

Creating Applications using Database

Using SQLite database

SQLite is a file based database so there is no need of an external JSON file to store user login details.

Creating Standalone Application using SQLite Database

Using MySQL database

To allow our main file mysql1.py application to access the data from the JSON file at runtime (so different users can update their own data), we should avoid bundling the JSON file inside the executable. Instead, we can place the JSON file in the same directory as the executable, so it is accessible and editable by the user ( to update user login details ) .

Source code for MySQL Paging application

Here’s how to achieve this:
  1. Ensure the JSON is external to the executable
    Instead of bundling the JSON file inside the app, keep it separate so the users can modify it directly.
  2. Modify our mysql1.py to look for the JSON file in the current working directory: Our code should now look like this:
    import os
    import sys
    import json
    from sqlalchemy import create_engine, text
    
    # Define the JSON file's relative path
    json_file = 'db_config.json'
    
    # Check if the JSON file exists in the current working directory
    if not os.path.exists(json_file):
        raise FileNotFoundError(f"Configuration file {json_file} not found!")
    
    # Load database configuration from JSON
    with open(json_file, 'r') as f:
        config = json.load(f)
    
    # Establishing database connection using config
    my_conn = create_engine(config['database_url']).connect()
    
    # Rest of your Tkinter app logic
  3. Use PyInstaller without bundling the JSON
    Generate our executable without the --add-data option, so that the JSON file stays external and can be modified by the user:
    PyInstaller --onefile  --windowed --distpath D:\\my_app D:\\testing\\mysql1.py
  4. Instructions for Users
    Tell your users to place the db_config.json file in the same directory as the executable. User can edit this file to use their own database credentials or settings.
db_config.json : Update your login details.
{
    "database_url": "mysql+mysqldb://id:pw@localhost/my_db"
}
mysql1.py : The main source file
import tkinter as tk
import os
import sys
import json
from sqlalchemy import create_engine, text

# Define the JSON file's relative path
json_file = 'db_config.json'

# Check if the JSON file exists in the current working directory
if not os.path.exists(json_file):
    raise FileNotFoundError(f"Configuration file {json_file} not found!")

# Load database configuration from JSON
with open(json_file, 'r') as f:
    config = json.load(f)

# Establishing database connection using config
my_conn = create_engine(config['database_url']).connect()

r_set = my_conn.execute(text("SELECT count(*) as no from STUDENT"))
data_row = r_set.fetchone()
no_rec = data_row[0]
limit = 8

# Tkinter window setup
my_w = tk.Tk()
my_w.geometry("350x200")

def my_display(offset):
    global my_conn
    my_conn.close()
    my_conn = create_engine(config['database_url']).connect()

    q = "SELECT * from student LIMIT " + str(offset) + "," + str(limit)
    r_set = my_conn.execute(text(q))

    for widget in my_w.grid_slaves():
        widget.grid_forget()

    i = 0
    for student in r_set:
        for j in range(len(student)):
            e = tk.Entry(my_w, width=10, fg='blue')
            e.grid(row=i, column=j)
            e.insert(tk.END, student[j])
        i += 1

    while i < limit:
        for j in range(len(student)):
            e = tk.Entry(my_w, width=10, fg='blue')
            e.grid(row=i, column=j)
            e.insert(tk.END, "")
        i += 1

    back = offset - limit
    next = offset + limit
    b1 = tk.Button(my_w, text='Next >', command=lambda: my_display(next))
    b1.grid(row=12, column=4)
    b2 = tk.Button(my_w, text='< Prev', command=lambda: my_display(back))
    b2.grid(row=12, column=1)

    if no_rec <= next:
        b1["state"] = "disabled"
    else:
        b1["state"] = "active"

    if back >= 0:
        b2["state"] = "active"
    else:
        b2["state"] = "disabled"

my_display(0)
my_w.mainloop()
Benefits:
Users can easily modify their own JSON file to change settings.
The app dynamically reads the configuration at runtime, meaning no recompilation is needed for different user

Bundling a JSON Configuration File with PyInstaller

When creating a standalone executable using PyInstaller, you may encounter an issue where external files, such as a JSON configuration file, are not found by the bundled application. This typically occurs because PyInstaller runs the executable from a temporary directory, and files like the JSON are not automatically included. The Problem
By default, PyInstaller doesn’t bundle files like .json unless specified. When using a database connection file in JSON format, the app may try to access the file from a temporary directory, leading to file-not-found errors.

The Solution: Using --add-data
To resolve this, you can explicitly tell PyInstaller to bundle the JSON file with the executable using the --add-data option. Here's the step-by-step approach:
  1. Structuring Your Project
    You will need two files:
    main.py: The main application script.
    db_config.json: The JSON file containing your database connection details.
    Make sure both files are in the same directory.
  2. Modify Your Python Script to Handle Bundling
    In your main.py, ensure the script can locate the JSON file when the application is run as an executable by PyInstaller:
    import os
    import sys
    import json
    from sqlalchemy import create_engine, text
    
    # Check if the application is running as an executable or script
    if getattr(sys, 'frozen', False):
        base_dir = sys._MEIPASS  # Temporary folder when running PyInstaller executable
    else:
        base_dir = os.path.dirname(os.path.abspath(__file__))
    
    # Load JSON file
    with open(os.path.join(base_dir, 'db_config.json'), 'r') as f:
        config = json.load(f)
    
    # Establishing database connection using config
    my_conn = create_engine(config['database_url']).connect()
    
    # Rest of your Tkinter app logic
    This modification ensures that the path to the JSON file works both when running the script directly and when it's bundled into an executable by PyInstaller.
  3. Use the PyInstaller --add-data Option
    Now, you need to tell PyInstaller to bundle the JSON file into the final executable:
    pyinstaller --onefile --add-data "db_config.json;." main.py
    Explanation:
    --onefile: Combines everything into a single executable file.
    --add-data "db_config.json;.": This tells PyInstaller to include the db_config.json file in the same directory as the executable. On Windows, the semicolon (;) is used to separate the source path and destination path. For Linux/macOS, use a colon (:) instead.
  4. Run the Executable
    Once PyInstaller finishes, the resulting .exe file will include the db_config.json and will be able to access it without searching the temporary directory.
Conclusion
By using the --add-data option with PyInstaller and making small adjustments to how the file is loaded, you can ensure that external configuration files like JSON are correctly bundled and accessed, solving the issue of missing files during runtime. This approach is essential for packaging Tkinter applications or any Python app that relies on external data files.

Table of common PyInstaller commands with descriptions:

Command Description
pyinstaller your_script.py Creates a bundled application from the Python script with the default settings.
--onefile Packages the application into a single executable file.
--windowed Generates an application without a console window (for GUI applications).
--add-data "source;destination" Adds non-Python files (like images or config files) to the bundle.
--icon=myicon.ico Includes a custom icon for the generated executable.
--clean Removes temporary files from previous builds before creating the executable.
--name my_app_name Sets a custom name for the output executable.
--noconfirm Automatically overwrites existing output files without prompting for confirmation.

Subscribe to our YouTube Channel here


Subscribe

* indicates required
Subscribe to plus2net

    plus2net.com







    Python Video Tutorials
    Python SQLite Video Tutorials
    Python MySQL Video Tutorials
    Python Tkinter Video Tutorials
    We use cookies to improve your browsing experience. . Learn more
    HTML MySQL PHP JavaScript ASP Photoshop Articles FORUM . Contact us
    ©2000-2024 plus2net.com All rights reserved worldwide Privacy Policy Disclaimer