Seite 1 von 2

Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 08:36
von Karthagos
Hallo,
ich nutze aus dem Windows Gadget Pack den Desktop Feed Reader, das Webradie-Gadegt und das Erinnerungsgadget DenkDran.
Leider finde ich in den Gadget-Packs keine Stoppuhr.
Ich suche eine kleine einfache Stoppuhr als Gadget, Widget oder Programm mit Desktop-Verknüpfung.
Z. Z. nutze ich "Eine Stopuhr 6.38" von SoftwareOK, da stört mich vor allem, dass die sofort beim Start "losrennt".
Hoffe, das jemand einen guten Tipp hat.

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 09:25
von Holgi
warum benutzt du nicht die Windows Clock, welche schon als App mit dem BS mitkommt? Die kann man AOT (alway on Top) stellen.
Windows Clock.JPG

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 10:29
von Karthagos
Hallo Holgi,
habe die Windows-Clock mangels Wissen nicht genutzt, ist nicht schlecht und werde mir die als Verknüpfung auf den Desktop legen. Allerdings habe ich auch hier wieder das Problem, obwohl die Verknüpfung als minimiert eingerichtet ist, das Programm im großen Modus ausgeführt wird und ich erst "Immer im Vordergrund" anklicken muss.
Den Screenshot habe ich etwas beschnitten.
Uhr.jpg
Hast Du dafür noch einen Tipp?

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 11:55
von Holgi
Hallo Günther,
für die Windows Clock müßte man wohl ein Autohotkey Script schreiben. Das ist jetzt nicht unbedingt Hexenwerk, aber für den Normalanwender auch nicht ganz so trivial.
Evtl. gibt es im MS Store etwas Brauchbares. Da müßte man dann nach Stoppuhr, Stopwatch o.ä. suchen. Leider alles sehr unübersichtlich.
Mit Hilfe von KI habe ich eben mal ein Python-Script schreiben lassen. Das Ergebnis mit den bunten Buttons siehst die auf der Hardcopy rechts im Bild. Ganz einfach gehalten: Start, Pause, Reset. Das läuft ebenfalls immer im Vordergrund und kann in der Position verändert werden.
Einzige Voraussetzung: es muss einmalig Python installiert werden. (Z.B: mit Winget: Winget install --id Python.Python.3.9).
Wenn du magst, teile ich dir hier den Code mit. Ist echt easy. Ich selbst habe auch keine Ahnung von der Programmiersprache Python. Muss man auch nicht haben.
PythonClock.JPG

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 12:40
von Karthagos
Hallo Holgi,
die Version mit dem Python Script sieht nicht schlecht aus. Habe Python 3.9 installiert, werde den Code gerne probieren, wenn Du ihn mir mitteilst.

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 13:04
von Holgi
here we go!
abspeichern z.B. als Stopwatch.pyw (egal wo)

Code: Alles auswählen

import tkinter as tk
import time
import sys

class StoppuhrWidget:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Stoppuhr Widget")
        self.root.configure(bg='#2b2b2b')
        self.root.attributes('-topmost', True)  # Immer im Vordergrund
        self.root.overrideredirect(True)  # Entfernt Titelleiste
        self.root.resizable(False, False)
        
        # Positioniere das Fenster in der oberen rechten Ecke
        self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() - 220, 50))
        
        # Variablen initialisieren
        self.laufend = False
        self.startzeit = 0
        self.verstrichene_zeit = 0
        
        # Titel-Leiste
        title_bar = tk.Frame(self.root, bg='#3b3b3b', relief='raised', bd=0)
        title_bar.pack(fill=tk.X)
        
        title_label = tk.Label(title_bar, text="Stoppuhr", bg='#3b3b3b', fg='white')
        title_label.pack(side=tk.LEFT, padx=5, pady=2)
        
        close_button = tk.Button(title_bar, text="×", command=self.schliessen, 
                                bg='#3b3b3b', fg='white', bd=0, font=("Arial", 12), 
                                activebackground='#ff5555', activeforeground='white')
        close_button.pack(side=tk.RIGHT, padx=2, pady=0)
        
        # Zeit-Anzeige
        self.zeit_anzeige = tk.Label(self.root, text="00:00:00", font=("Arial", 24, "bold"), 
                                    fg="#00ffaa", bg="#2b2b2b", pady=10)
        self.zeit_anzeige.pack(fill=tk.X, padx=10)
        
        # Button-Frame
        button_frame = tk.Frame(self.root, bg="#2b2b2b")
        button_frame.pack(pady=(0, 10))
        
        # Buttons
        self.start_button = tk.Button(button_frame, text="Start", command=self.start, 
                                     bg="#4CAF50", fg="white", font=("Arial", 10), 
                                     width=6, relief=tk.FLAT)
        self.start_button.pack(side=tk.LEFT, padx=5)
        
        self.pause_button = tk.Button(button_frame, text="Pause", command=self.pause, 
                                     bg="#FF9800", fg="white", font=("Arial", 10), 
                                     width=6, relief=tk.FLAT)
        self.pause_button.pack(side=tk.LEFT, padx=5)
        
        self.reset_button = tk.Button(button_frame, text="Reset", command=self.reset, 
                                     bg="#F44336", fg="white", font=("Arial", 10), 
                                     width=6, relief=tk.FLAT)
        self.reset_button.pack(side=tk.LEFT, padx=5)
        
        # Variablen für das Ziehen des Fensters
        self.x = 0
        self.y = 0
        
        # Ermöglicht das Ziehen des Fensters über die Titelleiste
        title_bar.bind("<ButtonPress-1>", self.start_ziehen)
        title_bar.bind("<B1-Motion>", self.ziehen)
        
        self.root.mainloop()
    
    def start_ziehen(self, event):
        self.x = event.x
        self.y = event.y
    
    def ziehen(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.root.winfo_x() + deltax
        y = self.root.winfo_y() + deltay
        self.root.geometry(f"+{x}+{y}")
    
    def schliessen(self):
        self.root.destroy()
        sys.exit()
    
    def start(self):
        if not self.laufend:
            self.laufend = True
            self.startzeit = time.time() - self.verstrichene_zeit
            self.aktualisiere_zeit()
            self.start_button.config(state=tk.DISABLED)
            self.pause_button.config(state=tk.NORMAL)
    
    def pause(self):
        if self.laufend:
            self.laufend = False
            self.verstrichene_zeit = time.time() - self.startzeit
            self.start_button.config(state=tk.NORMAL)
            self.pause_button.config(state=tk.DISABLED)
    
    def reset(self):
        self.laufend = False
        self.verstrichene_zeit = 0
        self.zeit_anzeige.config(text="00:00:00")
        self.start_button.config(state=tk.NORMAL)
        self.pause_button.config(state=tk.NORMAL)
    
    def aktualisiere_zeit(self):
        if self.laufend:
            self.verstrichene_zeit = time.time() - self.startzeit
            stunden = int(self.verstrichene_zeit // 3600)
            minuten = int((self.verstrichene_zeit % 3600) // 60)
            sekunden = int(self.verstrichene_zeit % 60)
            zeit_string = f"{stunden:02d}:{minuten:02d}:{sekunden:02d}"
            self.zeit_anzeige.config(text=zeit_string)
            self.root.after(100, self.aktualisiere_zeit)

# Widget starten
if __name__ == "__main__":
    StoppuhrWidget()
Dann einfach mit Doppelklick starten. (Kann man später auch mal automatisieren > Stichwort Autostart)

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 13:47
von Holgi
jo, die StopUhr mit dem Python-Script gefällt mir selbst sehr gut. Gleich mal abgespeichert. Kann man immer mal gebrauchen.
in der Windows Sandbox (mit installiertem Winget) muss der Befehl zum Installieren von Python etwas abgewandelt werden. Liegt wohl daran, dass die Sandbox keinen Store hat. Sieht dann so aus:

Code: Alles auswählen

Winget install --id Python.Python.3.9 --source winget
Autostart geht ebenfalls:
z.B. eine Verknüpfung von Stopwatch.pyw anlegen (lassen) und dann in

Code: Alles auswählen

"%AppData%\Microsoft\Windows\Start Menu\Programs\Startup\
legen.
Registry > run etc. ginge wohl auch.

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 14:36
von Karthagos
Hallo Holgi,
da bin ich ja platt, was mit KI und Python alles möglich ist.
Habe mir eine Verknüpfung mit einem hübschen Icon gemacht um das Tool aufzurufen.
Ich brauche es ja nicht immer. Aber das ist wirklich genial, einfach, reduziert und trotzdem mit allem, was man braucht.
Die Verknüpfung startet das Tool immer in der rechten oberen Ecke, weißt Du, wie man ihm eine bestimmte Position zuweisen kann?
Position.jpg

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 15:02
von Holgi
Karthagos hat geschrieben: 12.09.2025, 14:36 weißt Du, wie man ihm eine bestimmte Position zuweisen kann?
Natürlich! Man muss nur das Python Script abändern und dazu die Werte, in denen die Position gespeichert ist, ändern.

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 15:04
von Holgi
kleiner Gag! :D
hier werden die Werte gespeichert:

Code: Alles auswählen

        # Positioniere das Fenster in der oberen rechten Ecke
        self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() - 220, 50))
# Weit oben rechts (Standard)
self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() - 220, 50))

# Weiter unten
self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() - 220, 150))

# Weiter links
self.root.geometry("+%d+%d" % (self.root.winfo_screenwidth() - 320, 50))

# Andere Ecke (z.B. unten links)
self.root.geometry("+%d+%d" % (50, self.root.winfo_screenheight() - 200))

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 15:12
von Holgi
dieses Script merkt sich die letzte Position:
Stopwatch_last_position.pyw

Code: Alles auswählen

import tkinter as tk
import time
import sys
import json
import os

class StoppuhrWidget:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Stoppuhr Widget")
        self.root.configure(bg='#2b2b2b')
        self.root.attributes('-topmost', True)
        self.root.overrideredirect(True)
        self.root.resizable(False, False)
        
        # Konfiguration laden oder Standardposition verwenden
        self.config_datei = "stoppuhr_config.json"
        self.position = self.lade_konfiguration()
        
        # Fensterposition setzen
        self.root.geometry(f"+{self.position['x']}+{self.position['y']}")
        
        # Variablen initialisieren
        self.laufend = False
        self.startzeit = 0
        self.verstrichene_zeit = 0
        
        # Titel-Leiste
        title_bar = tk.Frame(self.root, bg='#3b3b3b', relief='raised', bd=0)
        title_bar.pack(fill=tk.X)
        
        title_label = tk.Label(title_bar, text="Stoppuhr", bg='#3b3b3b', fg='white')
        title_label.pack(side=tk.LEFT, padx=5, pady=2)
        
        close_button = tk.Button(title_bar, text="×", command=self.beenden, 
                                bg='#3b3b3b', fg='white', bd=0, font=("Arial", 12), 
                                activebackground='#ff5555', activeforeground='white')
        close_button.pack(side=tk.RIGHT, padx=2, pady=0)
        
        # Zeit-Anzeige
        self.zeit_anzeige = tk.Label(self.root, text="00:00:00", font=("Arial", 24, "bold"), 
                                    fg="#00ffaa", bg="#2b2b2b", pady=10)
        self.zeit_anzeige.pack(fill=tk.X, padx=10)
        
        # Button-Frame
        button_frame = tk.Frame(self.root, bg="#2b2b2b")
        button_frame.pack(pady=(0, 10))
        
        # Buttons
        self.start_button = tk.Button(button_frame, text="Start", command=self.start, 
                                     bg="#4CAF50", fg="white", font=("Arial", 10), 
                                     width=6, relief=tk.FLAT)
        self.start_button.pack(side=tk.LEFT, padx=5)
        
        self.pause_button = tk.Button(button_frame, text="Pause", command=self.pause, 
                                     bg="#FF9800", fg="white", font=("Arial", 10), 
                                     width=6, relief=tk.FLAT)
        self.pause_button.pack(side=tk.LEFT, padx=5)
        self.pause_button.config(state=tk.DISABLED)
        
        self.reset_button = tk.Button(button_frame, text="Reset", command=self.reset, 
                                     bg="#F44336", fg="white", font=("Arial", 10), 
                                     width=6, relief=tk.FLAT)
        self.reset_button.pack(side=tk.LEFT, padx=5)
        
        # Variablen für das Ziehen des Fensters
        self.x = 0
        self.y = 0
        
        # Ermöglicht das Ziehen des Fensters über die Titelleiste
        title_bar.bind("<ButtonPress-1>", self.start_ziehen)
        title_bar.bind("<B1-Motion>", self.ziehen)
        
        # Bindungen für das Speichern der Position beim Schließen
        self.root.protocol("WM_DELETE_WINDOW", self.beenden)
        
        self.root.mainloop()
    
    def lade_konfiguration(self):
        standard_position = {
            'x': self.root.winfo_screenwidth() - 220,
            'y': 50
        }
        
        if os.path.exists(self.config_datei):
            try:
                with open(self.config_datei, 'r') as f:
                    return json.load(f)
            except:
                return standard_position
        return standard_position
    
    def speichere_konfiguration(self):
        with open(self.config_datei, 'w') as f:
            json.dump(self.position, f)
    
    def start_ziehen(self, event):
        self.x = event.x
        self.y = event.y
    
    def ziehen(self, event):
        deltax = event.x - self.x
        deltay = event.y - self.y
        x = self.root.winfo_x() + deltax
        y = self.root.winfo_y() + deltay
        self.root.geometry(f"+{x}+{y}")
        self.position = {'x': x, 'y': y}
    
    def beenden(self):
        self.speichere_konfiguration()
        self.root.destroy()
        sys.exit()
    
    def start(self):
        if not self.laufend:
            self.laufend = True
            self.startzeit = time.time() - self.verstrichene_zeit
            self.aktualisiere_zeit()
            self.start_button.config(state=tk.DISABLED)
            self.pause_button.config(state=tk.NORMAL)
    
    def pause(self):
        if self.laufend:
            self.laufend = False
            self.verstrichene_zeit = time.time() - self.startzeit
            self.start_button.config(state=tk.NORMAL)
            self.pause_button.config(state=tk.DISABLED)
    
    def reset(self):
        self.laufend = False
        self.verstrichene_zeit = 0
        self.zeit_anzeige.config(text="00:00:00")
        self.start_button.config(state=tk.NORMAL)
        self.pause_button.config(state=tk.DISABLED)
    
    def aktualisiere_zeit(self):
        if self.laufend:
            self.verstrichene_zeit = time.time() - self.startzeit
            stunden = int(self.verstrichene_zeit // 3600)
            minuten = int((self.verstrichene_zeit % 3600) // 60)
            sekunden = int(self.verstrichene_zeit % 60)
            zeit_string = f"{stunden:02d}:{minuten:02d}:{sekunden:02d}"
            self.zeit_anzeige.config(text=zeit_string)
            self.root.after(100, self.aktualisiere_zeit)

# Widget starten
if __name__ == "__main__":
    StoppuhrWidget()

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 15:36
von Karthagos
Hallo Holgi,
Du bist wirklich genial, vielen Dank :anstossen:
Jetzt ist es für mich perfekt, nur...
Holgi hat geschrieben: 12.09.2025, 15:04 kleiner Gag! :D
Den Gag habe ich leider nicht verstanden, stehe auf dem Schlauch :-?

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 15:44
von Holgi
Karthagos hat geschrieben: 12.09.2025, 15:36 Den Gag habe ich leider nicht verstanden, stehe auf dem Schlauch :-?
ok, hat nicht gezündet.
F: Weißt du wie ....
A: ja

F: können Sie mir sagen, wie spät es ist?
A: ja.
... war so gemeint.

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 15:55
von Karthagos
OK, ach ist mir das peinlich :-D

Re: Stoppuhr als Gadget, Widget oder Programm

Verfasst: 12.09.2025, 16:16
von Karthagos
Hallo Holgi,
jetzt endlich hab ich den Gag verstanden :muahah:
Ich habe mir die Beiträge in einem Word-Dokument zusammengeschrieben um das später wegen meiner "partiellen Amnesie" :) ggf. nachvollziehen zu können. Dabei ist mir aufgefallen, dass ich Deinen "Gagbeitrag" 15:02 h überlesen hatte. Da konnte ich den Joke natürlich nicht verstehen. Jetzt bin ich wieder beruhigt. :dafür: