ich habe vor Kurzem mein Python-Projekt mit PyInstaller in ein Onefile komprimiert. Das Projekt besteht aus zwei Hauptskripten: main.py und config_editor.py. Vor der Komprimierung konnte ich beide Skripte problemlos ausführen.
Mein Ziel ist es, eine GUI-Anwendung (gui.pyw) zu erstellen, die einen Login-Prozess enthält und nach erfolgreichem Login das Hauptskript main.py startet. Das GUI-Skript habe ich ebenfalls zu einem Onefile komprimiert.
Code: Alles auswählen
import tkinter as tk
from tkinter import messagebox
import subprocess
import os
import time
import requests
import ctypes
import sys
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
class LoginWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("Login")
self.geometry("200x150")
self.username_label = tk.Label(self, text="Username:")
self.username_label.pack()
self.username_entry = tk.Entry(self)
self.username_entry.pack()
self.password_label = tk.Label(self, text="Password:")
self.password_label.pack()
self.password_entry = tk.Entry(self, show="*")
self.password_entry.pack()
self.login_button = tk.Button(self, text="Login", command=self.login)
self.login_button.pack()
def login(self):
username = self.username_entry.get()
password = self.password_entry.get()
r = requests.get(f'/login/{username}/{password}/')
if 'Success' in r.text:
login_status_file = resource_path("login_status.txt")
with open(login_status_file, "w") as f:
f.write("True")
self.destroy()
MainWindow().start_main()
elif 'Wrong' in r.text:
messagebox.showerror("Login Failed", f"Wrong password for username {username}!")
elif 'existing' in r.text:
messagebox.showerror("Login Failed", "This account does not exist! Please register!")
class MainWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("Bra1nBot")
# Vollständiger Pfad zur Bilddatei
image_path = resource_path("hintergrundbild.png")
# Hintergrundbild
self.background_image = tk.PhotoImage(file=image_path)
self.background_label = tk.Label(self, image=self.background_image)
self.background_label.place(x=0, y=0, relwidth=1, relheight=1)
# Fenstergröße an Bildgröße anpassen
self.geometry("{}x{}".format(self.background_image.width(), self.background_image.height()))
# Status-Label
self.status_label = tk.Label(self, text="Status: Inaktiv", fg="red")
self.status_label.pack()
# Start-Button
self.start_button = tk.Button(self, text="Start", command=self.start_main)
self.start_button.pack()
# Config-Button
self.config_button = tk.Button(self, text="Config", command=self.open_config_editor)
self.config_button.pack()
# Exit-Button
self.exit_button = tk.Button(self, text="Exit", command=self.exit_program)
self.exit_button.pack()
# Beenden-Button für main.py
self.close_button = tk.Button(self, text="Beenden", command=self.close_main)
self.close_button.pack()
def start_main(self):
# Erstelle die login_status.txt-Datei
login_status_file = resource_path("login_status.txt")
with open(login_status_file, "w") as file:
file.write("True")
# Starte main.py im Hintergrund
main_path = resource_path("main.py")
subprocess.Popen(["python", main_path], creationflags=subprocess.DETACHED_PROCESS, close_fds=True)
# Rufe die update_status_label-Methode auf, um den Status zu aktualisieren
self.update_status_label()
def open_config_editor(self):
try:
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
config_editor_path = os.path.join(base_path, "config_editor.py")
subprocess.Popen(["pythonw", config_editor_path], creationflags=subprocess.DETACHED_PROCESS, close_fds=True)
except FileNotFoundError:
messagebox.showerror("Fehler", "config_editor.py not found!")
except Exception as e:
messagebox.showerror("Fehler", str(e))
def exit_program(self):
login_status_file = resource_path("login_status.txt")
if os.path.exists(login_status_file):
os.remove(login_status_file)
# Beende das Programm
self.destroy()
def close_main(self):
login_status_file = resource_path("login_status.txt")
if os.path.exists(login_status_file):
os.remove(login_status_file)
# Schließe die main.py
pid_file = resource_path("main_pid.txt")
try:
with open(pid_file, "r") as f:
pid = int(f.read().strip())
subprocess.Popen(["taskkill", "/F", "/PID", str(pid)], shell=True)
os.remove(pid_file)
self.update_status_label()
except FileNotFoundError:
messagebox.showerror("Fehler", "Bra1nBot not active!")
def update_status_label(self):
# Überprüfe, ob main.py aktiv ist und aktualisiere den Status
pid_file = resource_path("main_pid.txt")
if os.path.isfile(pid_file):
self.status_label.config(text="Status: Aktiv", fg="green")
else:
self.status_label.config(text="Status: Inaktiv", fg="red")
self.after(1000, self.update_status_label) # Überprüfe den Status alle 1 Sekunde
if __name__ == "__main__":
try:
r = requests.get('login url')
if 'Im online!' in r.text:
login_window = LoginWindow()
login_window.mainloop()
else:
ctypes.windll.user32.MessageBoxW(0, "Server is offline! Try again later!", "Server is offline!", 0)
except:
ctypes.windll.user32.MessageBoxW(0, "Couldn't connect to server!", "You are offline!", 0)
Beim Erstellen des Onefile mit PyInstaller wird der _MEIPASS-Ordner erstellt, der alle Dateien des Projekts enthält. Die Endgröße der gui.exe-Datei beträgt etwa 2 GB, was darauf hindeutet, dass alle Skripte und Ressourcen darin enthalten sind.
Meine Frage lautet nun: Wie kann ich das Hauptskript main.py über die gui.exe starten, nachdem der Login abgeschlossen ist?
Noch mal kurz

Alle Skripte, einschließlich gui.pyw, main.py und config_editor.py, sind im selben Verzeichnis. In der Python-Version funktionieren alle Skripte einwandfrei.
Um das Projekt auf anderen Computern auszuführen, habe ich versucht, sie in ausführbare .exe-Dateien umzuwandeln. Dabei wurden alle Abhängigkeiten, einschließlich der Konfigurationsdatei im JSON-Format, als separate Dateien mit aufgenommen. Die Erstellung der .exe-Dateien war erfolgreich, aber nach der Umwandlung kann ich weder das Hauptskript main.py noch den Konfigurationseditor über die GUI starten.
Ich habe versucht, die Pfade zu den Skripten in der GUI entsprechend anzupassen, indem ich den _MEIPASS-Ordner verwendet habe, um auf die Dateien zuzugreifen. Trotzdem bekomme ich beim Versuch, die Skripte über die GUI.exe zu starten, Fehlermeldungen oder es passiert einfach nichts.
Ich frage mich, ob es bestimmte Anpassungen gibt, die ich vornehmen muss, um die Skripte erfolgreich über die GUI.exe auszuführen. Gibt es möglicherweise Besonderheiten beim Umgang mit dem _MEIPASS-Ordner, die ich berücksichtigen muss?
Ich freue mich über Ihre Hilfe und bedanke mich im Voraus für Ihre Unterstützung.
Beste Grüße