Hello to all and thanks for coming to my topic.
I am trying to learn on how to create applications using python, I have run into an issue where I am trying to add a background image, fav icon and button images to an auto-clicker application that I am doing (for fun).
Currently I am running into some issues which are frustrating as hell to be honest, one of the issue is that the images do not load and the second is because the images do not load the application itself does not start.
Below you can see the code clean:
import os
import sys
import time
import threading
import tkinter as tk
from pynput.mouse import Button, Controller
from pynput.keyboard import Key, Listener
import logging
from pynput import keyboard
# Define the base path of the script
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
class AutoClickerApp:
def __init__(self, root):
self.root = root
self.root.title("Auto Clicker")
self.root.geometry("761x335") # Set a specific window size for my desired background image.
# Set application icon
self.root.iconbitmap(os.path.join(BASE_DIR, "images/app_icon.ico"))
# Added logging.
self.init_logging()
# Initialize variables.
self.click_speed = tk.DoubleVar(value=5)
self.auto_clicking_active = False
self.auto_click_timer = None
# Try to load and display background image.
self.background_image = self.load_background_image()
self.background_label = tk.Label(root, image=self.background_image)
self.background_label.place(x=0, y=0, relwidth=1, relheight=1)
# Creating the UI elements.
self.label = tk.Label(root, text="Auto Clicker", font=("Verdana", 16))
self.label.pack()
# Commented out the welcome label
self.welcome_label = tk.Label(root, text="Welcome to Auto Clicker!", font=("Verdana", 14))
self.welcome_label.pack()
self.speed_label = tk.Label(root, text="Clicks per second:", font=("Verdana", 12))
self.speed_label.pack()
self.speed_slider = tk.Scale(root, from_=5, to=999, orient="horizontal", variable=self.click_speed)
self.speed_slider.pack()
# Load button images
self.start_button_image = tk.PhotoImage(file=os.path.join(BASE_DIR, "images/start_button.png"))
self.stop_button_image = tk.PhotoImage(file=os.path.join(BASE_DIR, "images/stop_button.png"))
# The buttons to start and stop auto-clicking process.
self.start_button = tk.Button(root, image=self.start_button_image, command=self.toggle_auto_click)
self.start_button.pack()
self.stop_button = tk.Button(root, image=self.stop_button_image, command=self.stop_auto_click)
self.stop_button.pack()
# Mouse controller and keyboard listener
self.mouse = Controller()
self.keyboard_listener = None
def init_logging(self):
# Starting the logging for recording events
self.logger = logging.getLogger("AutoClicker")
self.logger.setLevel(logging.DEBUG)
log_format = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
file_handler = logging.FileHandler("autoclicker.log.txt")
file_handler.setFormatter(log_format)
self.logger.addHandler(file_handler)
def load_background_image(self):
# Hopefully load the background image for the UI
image_path = os.path.join(BASE_DIR, "images/background_image.png")
try:
return tk.PhotoImage(file=image_path)
except tk.TclError:
self.logger.error("Background image not found: %s", image_path)
return None
def on_press(self, key):
# Event handler for key press
if key == Key.f1:
if not self.auto_clicking_active:
self.logger.info("Auto Clicker Started")
self.toggle_auto_click()
def on_release(self, key):
# Event handler for key release
if key == Key.f2:
self.logger.info("Auto Clicker Stopped")
self.stop_auto_click()
def auto_click(self):
# Auto-clicking logic
start_time = time.time()
while self.auto_clicking_active and time.time() - start_time < 30:
self.mouse.click(Button.left)
time.sleep(1 / self.click_speed.get())
self.auto_clicking_active = False
if self.keyboard_listener:
self.keyboard_listener.stop()
def toggle_auto_click(self):
# Toggle auto-clicking on/off
if not self.auto_clicking_active:
self.auto_clicking_active = True
self.keyboard_listener = Listener(on_press=self.on_press, on_release=self.on_release)
self.keyboard_listener.start()
self.auto_click_thread = threading.Thread(target=self.auto_click)
self.auto_click_thread.start()
else:
self.stop_auto_click()
def stop_auto_click(self):
# Stop auto-clicking and cleanup
self.auto_clicking_active = False
if self.auto_click_thread and self.auto_click_thread.is_alive():
self.auto_click_thread.join()
if self.keyboard_listener:
self.keyboard_listener.stop()
if __name__ == "__main__":
root = tk.Tk()
app = AutoClickerApp(root)
root.mainloop()
As I want to make the application for Windows 10. I am running the following command (example with the background only) to try and add the background image:
pyinstaller --onefile --add-data "background_image.png;." --add-data "images/background_image.png;." auto-clicker.py
But when I start the application it tries to find the background in the temporary files instead of the same directory as the python script.
File structure before running the pyinstaller is as follow -> Folder/auto-clicker.py , Folder/background_image.png , Folder/images/background_image.png
.
Upon running the pyinstaller command it creates "Folder/build" folder and "Folder/dist" where the exe is located and the "Folder/auto-clicker.spec" file that contains the following:
block_cipher = None
a = Analysis(
['auto-clicker.py'],
pathex=[],
binaries=[],
datas=[('background_image.png', '.'), ('images/background_image.png', '.')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False,
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='auto-clicker',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
And two additional issues I encounter while meddling with the code, which are:
- When pressing F1 the clicker does not start (if I press it with the mouse it works including the F2 to stop it);
- When stopping it with F2 I cannot start it again giving "RuntimeError: threads can only be started once".
Tried few different approaches to resolve it with the 'base_dir' defining but the application would load without a background image and giving the following error in the log file:
ERROR - Background image not found: C:\Users\SomeName\AppData\Local\Temp\_MEI464682\images/background_image.png
For the other issues I have tried adding "threading.Thread", which upon starting the application freezes (not responding), tried to change the "pynput" and to add "time.sleep" but does not resolve it.