Untitled
Anonymous
plain_text
01/26/2026 5:23 AM
14.6 KB
15
Indexable
#!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk, messagebox
import subprocess
import os
import sys
import threading
import psutil
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
os.chdir(BASE_DIR)
# ================== HIDE TERMINAL ==================
def hide_terminal():
"""Hide terminal window"""
if sys.platform.startswith('linux'):
try:
# Try to hide terminal
subprocess.run(['xdotool', 'search', '--pid', str(os.getpid()),
'windowminimize'], capture_output=True)
except:
pass
# Call hide terminal function
if __name__ == "__main__":
# Wait a moment then hide terminal
import time
time.sleep(1)
hide_terminal()
class ProgramLauncher:
def __init__(self, root):
self.root = root
self.root.title("UCC Scale Program Launcher")
self.root.geometry("400x300")
self.root.configure(bg='#f0f0f0')
self.launcher_hidden = False
self.monitoring_process = None
# Setup keyboard bindings
self.setup_keyboard_bindings()
self.center_window_on_primary_monitor()
self.root.resizable(False, False)
self.setup_ui()
# Handle window close - HIDE not quit
self.root.protocol("WM_DELETE_WINDOW", self.hide_to_tray)
# Auto-focus
self.root.after(100, self.root.lift)
self.root.after(100, self.root.focus_force())
def setup_keyboard_bindings(self):
self.root.bind_all('<F12>', self.show_from_tray)
self.root.bind_all('<h>', self.hide_to_tray)
self.root.bind_all('<H>', self.hide_to_tray)
# Tambah binding untuk Ctrl+H
self.root.bind_all('<Control-h>', self.hide_to_tray)
self.root.bind_all('<Control-H>', self.hide_to_tray)
def center_window_on_primary_monitor(self):
"""Center window on primary monitor (not all monitors combined)"""
self.root.update_idletasks()
# Get window dimensions
width = self.root.winfo_width()
height = self.root.winfo_height()
# Get screen dimensions of primary monitor
# Method 1: Use screen width/height (should give primary monitor)
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
# Method 2: Alternative approach - place window at position relative to mouse
# This tends to place it on the monitor where mouse currently is
pointer_x = self.root.winfo_pointerx()
pointer_y = self.root.winfo_pointery()
# Calculate position to center on screen where mouse is
# If mouse is on primary monitor (usually x < screen_width), use primary monitor
# Otherwise adjust for secondary monitor
if pointer_x < screen_width: # Primary monitor
x = (screen_width - width) // 2
y = (screen_height - height) // 2
else: # Secondary monitor (assuming horizontal setup)
# Calculate position for secondary monitor
x = pointer_x - (width // 2)
y = (screen_height - height) // 2
# Ensure window doesn't go off screen
if x + width > screen_width * 2: # Assuming two monitors of same width
x = screen_width + (screen_width - width) // 2
if y + height > screen_height:
y = (screen_height - height) // 2
# OR simpler: Always place on primary monitor
# Uncomment the following lines for simpler approach
x = (screen_width - width) // 2
y = (screen_height - height) // 2
self.root.geometry(f'{width}x{height}+{x}+{y}')
def setup_ui(self):
# Title
title_label = tk.Label(
self.root,
text="PROGRAM LAUNCHER",
font=("Arial", 18, "bold"),
bg='#f0f0f0',
fg='#2c3e50'
)
title_label.pack(pady=20)
# Subtitle
subtitle_label = tk.Label(
self.root,
text="Select UCC type to Scan:",
font=("Arial", 11),
bg='#f0f0f0',
fg='#34495e'
)
subtitle_label.pack(pady=5)
# Frame for buttons
button_frame = tk.Frame(self.root, bg='#f0f0f0')
button_frame.pack(pady=30)
# Button Program 1
self.btn_program1 = tk.Button(
button_frame,
text="UCC Shipping",
command=self.run_program1,
bg='#3498db',
fg='white',
font=("Arial", 12, "bold"),
width=15,
height=2,
relief=tk.RAISED,
cursor="hand2"
)
self.btn_program1.grid(row=0, column=0, padx=20, pady=10)
# Button Program 2
self.btn_program2 = tk.Button(
button_frame,
text="UCC Non Shipping",
command=self.run_program2,
bg='#2ecc71',
fg='white',
font=("Arial", 12, "bold"),
width=15,
height=2,
relief=tk.RAISED,
cursor="hand2"
)
self.btn_program2.grid(row=0, column=1, padx=20, pady=10)
# Hide/Show Button
self.btn_toggle = tk.Button(
self.root,
text="⇲ Hide to Tray",
command=self.toggle_window,
bg='#f39c12',
fg='white',
font=("Arial", 10, "bold"),
width=15,
height=1
)
self.btn_toggle.pack(pady=10)
# Hotkey info
hotkey_label = tk.Label(
self.root,
text="F12 = Show Window | Ctrl+H = Hide",
font=("Arial", 9),
bg='#f0f0f0',
fg='#7f8c8d'
)
hotkey_label.pack()
# Quit Button
self.btn_quit = tk.Button(
self.root,
text="QUIT",
command=self.quit_program,
bg='#e74c3c',
fg='white',
font=("Arial", 12, "bold"),
width=15,
height=2,
relief=tk.RAISED,
cursor="hand2"
)
self.btn_quit.pack(pady=20)
# Status bar
self.status_label = tk.Label(
self.root,
text="Status: Ready (Press F12 if window hidden)",
font=("Arial", 9),
bg='#f0f0f0',
fg='#7f8c8d',
bd=1,
relief=tk.SUNKEN,
anchor=tk.W
)
self.status_label.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
def hide_to_tray(self, event=None):
if not self.launcher_hidden:
self.launcher_hidden = True
# Move window off-screen (NOT minimize)
self.root.geometry("1x1+-1000+-1000") # Changed to -1000 to ensure off-screen
self.btn_toggle.config(text="⇱ Show Window (F12)")
self.status_label.config(text="Status: Hidden - Press F12")
def show_from_tray(self, event=None):
if self.launcher_hidden:
self.launcher_hidden = False
# Reset to normal size and position on primary monitor
self.root.geometry("400x300")
self.center_window_on_primary_monitor()
self.root.lift()
self.root.focus_force()
self.btn_toggle.config(text="⇲ Hide to Tray")
self.status_label.config(text="Status: Ready")
def toggle_window(self):
"""Toggle hide/show window"""
if self.launcher_hidden:
self.show_from_tray()
else:
self.hide_to_tray()
def hide_launcher(self):
"""Hide launcher (when another program is running)"""
if not self.launcher_hidden:
self.hide_to_tray()
def show_launcher(self):
"""Show launcher again"""
if self.launcher_hidden:
self.show_from_tray()
def monitor_program(self, pid, program_name):
"""Monitor if program is still running"""
try:
process = psutil.Process(pid)
process.wait() # Wait until process finishes
# Program has been closed, show launcher again
self.root.after(100, self.show_launcher)
self.status_label.config(text="Status: Program finished")
except psutil.NoSuchProcess:
self.root.after(100, self.show_launcher)
self.status_label.config(text="Status: Program finished")
except Exception as e:
self.root.after(100, self.show_launcher)
def run_program(self, filename, program_name):
try:
if not os.path.exists(filename):
messagebox.showerror("Error", f"File {filename} not found!")
self.status_label.config(text=f"Status: File {filename} not found")
return
self.status_label.config(text=f"Status: Running {program_name}...")
self.root.update()
process = subprocess.Popen(
[sys.executable, filename],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
start_new_session=True
)
self.hide_launcher()
self.status_label.config(text=f"Status: {program_name} is running...")
monitor_thread = threading.Thread(
target=self.monitor_program,
args=(process.pid, program_name),
daemon=True
)
monitor_thread.start()
except Exception as e:
messagebox.showerror("Error", f"Failed to run {program_name}: {str(e)}")
self.status_label.config(text=f"Status: Error - {str(e)}")
def run_program1(self):
self.run_program("shipping.py", "UCC Shipping")
def run_program2(self):
self.run_program("non_shipping.py", "UCC Non Shipping")
def quit_program(self):
if messagebox.askyesno("Confirmation", "Are you sure you want to quit?"):
self.status_label.config(text="Status: Exiting...")
self.root.quit()
self.root.destroy()
sys.exit()
def main():
# Check if psutil is installed
try:
import psutil
except ImportError:
print("psutil not found. Installing...")
subprocess.run([sys.executable, "-m", "pip", "install", "psutil", "--break-system-packages"])
import psutil
root = tk.Tk()
app = ProgramLauncher(root)
root.mainloop()
if __name__ == "__main__":
main()Editor is loading...
Leave a Comment