Skip to content

Commit f4a8651

Browse files
authored
Create Stopwatch.py
1 parent fa1c621 commit f4a8651

1 file changed

Lines changed: 235 additions & 0 deletions

File tree

27-Stopwatch/Stopwatch.py

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import sys
2+
import os
3+
import time
4+
import threading
5+
import tkinter as tk
6+
from tkinter import ttk, messagebox
7+
import sv_ttk
8+
9+
# =========================
10+
# Helpers
11+
# =========================
12+
def resource_path(file_name):
13+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
14+
return os.path.join(base_path, file_name)
15+
16+
def set_status(msg):
17+
status_var.set(msg)
18+
root.update_idletasks()
19+
20+
# =========================
21+
# App Setup
22+
# =========================
23+
root = tk.Tk()
24+
root.title("Stopwatch Pro")
25+
root.geometry("640x540")
26+
27+
sv_ttk.set_theme("light")
28+
29+
# =========================
30+
# Globals
31+
# =========================
32+
dark_mode_var = tk.BooleanVar(value=False)
33+
countdown_mode = tk.BooleanVar(value=False)
34+
35+
running = False
36+
start_time = None
37+
elapsed_time = 0.0
38+
39+
countdown_seconds = tk.IntVar(value=60)
40+
41+
laps = []
42+
43+
time_var = tk.StringVar(value="00:00:00.000")
44+
45+
# =========================
46+
# Theme Toggle
47+
# =========================
48+
def toggle_theme():
49+
bg = "#2E2E2E" if dark_mode_var.get() else "#FFFFFF"
50+
fg = "white" if dark_mode_var.get() else "black"
51+
52+
root.configure(bg=bg)
53+
for w in ["TFrame", "TLabel", "TLabelframe", "TLabelframe.Label", "TCheckbutton"]:
54+
style.configure(w, background=bg, foreground=fg)
55+
56+
time_label.configure(background=bg, foreground="#00FFAA" if dark_mode_var.get() else fg)
57+
set_status(f"Theme switched to {'Dark' if dark_mode_var.get() else 'Light'} mode")
58+
59+
# =========================
60+
# Core Logic
61+
# =========================
62+
def format_time(seconds):
63+
ms = int((seconds - int(seconds)) * 1000)
64+
s = int(seconds) % 60
65+
m = (int(seconds) // 60) % 60
66+
h = int(seconds) // 3600
67+
return f"{h:02}:{m:02}:{s:02}.{ms:03}"
68+
69+
def timer_loop():
70+
global elapsed_time, running
71+
while running:
72+
now = time.perf_counter()
73+
74+
if countdown_mode.get():
75+
remaining = countdown_seconds.get() - (now - start_time)
76+
if remaining <= 0:
77+
running = False
78+
time_var.set("00:00:00.000")
79+
messagebox.showinfo("⏰ Time's up", "Countdown finished!")
80+
set_status("Countdown completed")
81+
return
82+
time_var.set(format_time(remaining))
83+
else:
84+
elapsed_time = now - start_time
85+
time_var.set(format_time(elapsed_time))
86+
87+
time.sleep(0.01)
88+
89+
def start():
90+
global running, start_time
91+
if running:
92+
return
93+
94+
running = True
95+
start_time = time.perf_counter() - elapsed_time
96+
threading.Thread(target=timer_loop, daemon=True).start()
97+
set_status("Timer started")
98+
99+
def stop():
100+
global running
101+
running = False
102+
set_status("Timer stopped")
103+
104+
def reset():
105+
global running, elapsed_time, start_time, laps
106+
running = False
107+
elapsed_time = 0.0
108+
start_time = None
109+
laps.clear()
110+
lap_list.delete(0, tk.END)
111+
time_var.set("00:00:00.000")
112+
set_status("Timer reset")
113+
114+
def add_lap():
115+
if not running or countdown_mode.get():
116+
return
117+
118+
lap_time = format_time(elapsed_time)
119+
laps.append(elapsed_time)
120+
lap_list.insert(tk.END, f"Lap {len(laps)}{lap_time}")
121+
set_status(f"Lap {len(laps)} recorded")
122+
123+
# =========================
124+
# Styles
125+
# =========================
126+
style = ttk.Style()
127+
style.theme_use("clam")
128+
style.configure(
129+
"Action.TButton",
130+
font=("Segoe UI", 11, "bold"),
131+
foreground="white",
132+
background="#4CAF50",
133+
padding=8
134+
)
135+
style.map("Action.TButton", background=[("active", "#45a049")])
136+
137+
# =========================
138+
# Status Bar
139+
# =========================
140+
status_var = tk.StringVar(value="Ready")
141+
ttk.Label(root, textvariable=status_var, anchor="w").pack(side=tk.BOTTOM, fill="x")
142+
143+
# =========================
144+
# Main UI
145+
# =========================
146+
main = ttk.Frame(root, padding=20)
147+
main.pack(expand=True, fill="both")
148+
149+
ttk.Label(main, text="Stopwatch Pro",
150+
font=("Segoe UI", 22, "bold")).pack()
151+
152+
ttk.Label(main, text="Stopwatch • Countdown • Lap Timer",
153+
font=("Segoe UI", 11)).pack(pady=(0, 10))
154+
155+
# =========================
156+
# Timer Display
157+
# =========================
158+
time_label = ttk.Label(
159+
main,
160+
textvariable=time_var,
161+
font=("Segoe UI", 36, "bold"),
162+
anchor="center"
163+
)
164+
time_label.pack(pady=12)
165+
166+
# =========================
167+
# Controls
168+
# =========================
169+
controls = ttk.Frame(main)
170+
controls.pack(pady=8)
171+
172+
ttk.Button(controls, text="▶ Start", command=start,
173+
style="Action.TButton").pack(side="left", padx=4)
174+
175+
ttk.Button(controls, text="⏸ Stop", command=stop,
176+
style="Action.TButton").pack(side="left", padx=4)
177+
178+
ttk.Button(controls, text="⟲ Reset", command=reset,
179+
style="Action.TButton").pack(side="left", padx=4)
180+
181+
ttk.Button(controls, text="🏁 Lap", command=add_lap,
182+
style="Action.TButton").pack(side="left", padx=4)
183+
184+
# =========================
185+
# Countdown
186+
# =========================
187+
countdown_frame = ttk.LabelFrame(main, text="Countdown Mode", padding=10)
188+
countdown_frame.pack(fill="x", pady=8)
189+
190+
ttk.Checkbutton(
191+
countdown_frame,
192+
text="Enable Countdown",
193+
variable=countdown_mode
194+
).pack(side="left", padx=6)
195+
196+
ttk.Label(countdown_frame, text="Seconds:").pack(side="left", padx=6)
197+
198+
ttk.Spinbox(
199+
countdown_frame,
200+
from_=1,
201+
to=86400,
202+
textvariable=countdown_seconds,
203+
width=8
204+
).pack(side="left")
205+
206+
# =========================
207+
# Laps
208+
# =========================
209+
laps_frame = ttk.LabelFrame(main, text="Lap Times", padding=10)
210+
laps_frame.pack(fill="both", expand=True, pady=8)
211+
212+
lap_list = tk.Listbox(
213+
laps_frame,
214+
height=7,
215+
font=("Segoe UI", 10)
216+
)
217+
lap_list.pack(fill="both", expand=True)
218+
219+
# =========================
220+
# Options
221+
# =========================
222+
options = ttk.Frame(main)
223+
options.pack(pady=10)
224+
225+
ttk.Checkbutton(
226+
options,
227+
text="Dark Mode",
228+
variable=dark_mode_var,
229+
command=toggle_theme
230+
).pack()
231+
232+
# =========================
233+
# Run App
234+
# =========================
235+
root.mainloop()

0 commit comments

Comments
 (0)