Stoppuhr Tkinter

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
l3_12
User
Beiträge: 6
Registriert: Donnerstag 10. Oktober 2019, 10:58

Hallo zusammen,

ich habe eine Gui programmiert, in der man verschiedene Parameter eingeben kann. Anhand der Parameter wird die Geschwindigkeit alle n Sekunden erhöht und als akustisches Feedback ausgegeben. Nun würde ich gerne eine Zeitanzeige hinzufügen, welche startet sobald der Start Button gedrückt wird und stoppt, sobald die while Schleife beendet ist. Das ganze soll ähnlich wie eine Stoppuhr (HH:MM:SS) aussehen.

Ich weiß, dass dies theoretisch mit time.clock() gehen sollte, aber mir ist nicht so ganz klar, wie ich das mit der bestehenden GUI kombinieren muss, damit alles richtig abläuft, da die Stoppuhr unabhängig von der Aktualisierung der Geschwindigkeit kontinuierlich weiterlaufen soll.

Code: Alles auswählen

from tkinter import *
import socket
import numpy as np
from time import sleep
import time
import tkinter as tk
import pythoncom
import win32com.client as wincl
import threading

############################ Conconi Protocol ################################ 
#The protocol increases the speed by x km/h after a certain distance 
#until a maximum speed is reached.   
def conconi():
    global speed
    global interval
    global distance
    global stopp
    
    feedback(speed, distance)
    speed = speed + inc_speed
    if choseParameter == 'Distanz pro Stufe [m]':
        interval = level_distance/speed
        distance = distance + level_distance
    elif choseParameter == 'Zeit pro Stufe [m]':
        interval = float(entryLevel_Parameter.get())
        distance = speed*interval

############################    Timer     ################################  
#Calls certain function every n seconds. The program can perform other tasks 
#during this time.
    
class TimerClass(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.event = threading.Event()
        self.count = 1

    def run(self):
        
        while self.count <= number_of_levels and stop == 0:
            counter = str(self.count)
            labelCounter.config(text=counter)
            
            if choseProtocol == 'Conconi Protokoll':
                conconi()
            self.count += 1
            self.event.wait(interval)
    
    def stop(self):
        self.event.set()
    
###########################    accustic feedback  ###########################
#Acoustic feedback for Conconi protocol. Output of distance covered and 
#current speed. Is called after every increase of the speed. 
def feedback(speed, distance):
    pythoncom.CoInitialize()
    speed = speed*3600/1000
    speed = float(round(speed,1))
    
    speedAnzeige = str(speed)
    labelCurrent_Speed.config(text=speedAnzeige)
    
    distanceAnzeige = str(distance)
    labelDistance_Run.config(text=distanceAnzeige)
    
    speak = wincl.Dispatch("SAPI.SpVoice")
    text = "Die Geschwindigkeit beträgt" + str(speed) + "Kilometer die Stunde"
    text2 = str(distance)+"Meter zurückgelegt"
    if speed == 0:
        text = "Messung beendet!"
        speak.Speak(text)
    else:
        speak.Speak(text)
        speak.Speak(text2)

########################## Gui ############################################
def buttonBerechnenClick():
    global speed
    global accel
    global incline
    global level_parameter
    global number_of_levels
    global inc_speed
    
    # Übernahme der Daten
    buttonVerarbeitenClick()
    speed_start = float(entrySpeed_Start.get())*1000/3600
    speed_end = float(entrySpeed_End.get())*1000/3600
    inc_speed = float(entryInc_Speed.get())*1000/3600
    accel = float(entryAccel.get())
    incline = float(entryIncline.get())
    level_parameter =  float(entryLevel_Parameter.get())
    number_of_levels = (speed_end-speed_start)/inc_speed
    n_o_lAnzeige = str(number_of_levels)
    labelNumber_of_Levels.config(text=n_o_lAnzeige)
    speed = speed_start
    if choseParameter == 'Distanz pro Stufe [m]':
        interval = level_distance/speed
    elif choseParameter == 'Zeit pro Stufe [m]':
        interval = float(entryLevel_Parameter.get())
    
    tmr = TimerClass()
    tmr.start()
    labelTimer.config(text=clk)

def buttonVerarbeitenClick():
    global choseProtocol
    global choseParameter
    
    choseList = listboxProtocol.curselection()
    choseItem = choseList[0]
    choseProtocol = listboxProtocol.get(choseItem)
    
    choseList2 = listboxParameter.curselection()
    choseItem2 = choseList2[0]
    choseParameter = listboxParameter.get(choseItem2)
    
    
    
def buttonZeroClick():   
    global speed
    global stop
    
    stop = 1
    speed = 0
    feedback(speed, distance)
    
# Fenster
tkFenster = Tk()
tkFenster.title('Startwerte')
tkFenster.geometry('700x495')
# Label mit Aufschrift Startgeschwindigkeit
labelSpeed_Start = Label(master=tkFenster, bg='#FFCFC9', text='Startgeschwindigkeit [km/h]:')
labelSpeed_Start.place(x=54, y=24, width=200, height=27)
# Entry für die Startgeschwindigkeit
entrySpeed_Start = Entry(master=tkFenster, bg='white')
entrySpeed_Start.place(x=264, y=24, width=40, height=27)
# Label mit Aufschrift Endgeschwindigkeit
labelSpeed_End = Label(master=tkFenster, bg='#FFCFC9', text='Endgeschwindigkeit [km/h]:')
labelSpeed_End.place(x=54, y=64, width=200, height=27)
# Entry für die Endeschwindigkeit
entrySpeed_End = Entry(master=tkFenster, bg='white')
entrySpeed_End.place(x=264, y=64, width=40, height=27)
# Label mit Aufschrift Erhöhung Geschwindigkeit
labelInc_Speed = Label(master=tkFenster, bg='#FFCFC9', text='Erhöhung Geschwindigkeit [km/h]:')
labelInc_Speed.place(x=54, y=104, width=200, height=27)
# Entry für die Erhöhung Geschwindigkeit
entryInc_Speed = Entry(master=tkFenster, bg='white')
entryInc_Speed.place(x=264, y=104, width=40, height=27)
# Label mit Aufschrift Beschleunigung
labelAccel = Label(master=tkFenster, bg='#FFCFC9', text='Beschleunigung [m/s]:')
labelAccel.place(x=54, y=144, width=200, height=27)
# Entry für die Beschleunigung
entryAccel = Entry(master=tkFenster, bg='white')
entryAccel.place(x=264, y=144, width=40, height=27)
# Label mit Aufschrift Incline
labelIncline = Label(master=tkFenster, bg='#FFCFC9', text='Incline:')
labelIncline.place(x=54, y=184, width=200, height=27)
# Entry für die Incline
entryIncline = Entry(master=tkFenster, bg='white')
entryIncline.place(x=264, y=184, width=40, height=27)
# Listbox zur Auswahl von Parameter
listboxParameter = Listbox(master=tkFenster, bg='#FFCFC9', exportselection=0, selectmode='browse')
listboxParameter.insert('end', 'Distanz pro Stufe [m]')
listboxParameter.insert('end', 'Zeit pro Stufe [s]')
listboxParameter.place(x=54, y=224, width=200, height=37)
# Entry für die Distanz pro Stufe
entryLevel_Parameter = Entry(master=tkFenster, bg='white')
entryLevel_Parameter.place(x=264, y=224, width=40, height=37)
# Button zum Berechnen
buttonBerechnen = Button(master=tkFenster, bg='#FBD975', text='Start', command=buttonBerechnenClick)
buttonBerechnen.place(x=54, y=314, width=100, height=27)
# Button zum Abbrechen
buttonZero = Button(master=tkFenster, bg='#FBD975', text='Zero', command=buttonZeroClick)
buttonZero.place(x=194, y=314, width=100, height=27)
# Label mit Aufschrift  Auswahl Protokoll
labeln_o_l = Label(master=tkFenster, bg='#D5E88F', text='Auswahl Protokoll:')
labeln_o_l.place(x=54, y=354, width=150, height=27)
# Listbox zur Auswahl von Protokollen
listboxProtocol = Listbox(master=tkFenster, bg='white', exportselection=0, selectmode='browse')
listboxProtocol.insert('end', 'Conconi Protokoll')
listboxProtocol.insert('end', 'Protokoll X')
listboxProtocol.insert('end', 'Protokoll Y')
listboxProtocol.place(x=54, y=394, width=110, height=57)
# Label mit Aufschrift Anzahl Stufen:
labeln_o_l = Label(master=tkFenster, bg='#FFCFC9', text='Anzahl Stufen:')
labeln_o_l.place(x=54, y=274, width=200, height=27)
# Label für den Anzahl Stufen:
labelNumber_of_Levels = Label(master=tkFenster, bg='gray', text='')
labelNumber_of_Levels.place(x=264, y=274, width=40, height=27)
# Label mit Aufschrift aktuelle Geschwindigkeit:
labeln_o_l = Label(master=tkFenster, bg='#D5E88F', text='aktuelle Geschwindigkeit [km/h]:')
labeln_o_l.place(x=324, y=64, width=200, height=27)
# Label für aktuelle Geschwindigkeit:
labelCurrent_Speed = Label(master=tkFenster, bg='gray', text='')
labelCurrent_Speed.place(x=550, y=64, width=60, height=27)
# Label mit Aufschrift zurückgelegte Distanz:
labeln_o_l = Label(master=tkFenster, bg='#D5E88F', text='zurückgelegte Distanz [m]:')
labeln_o_l.place(x=324, y=104, width=200, height=27)
# Label für zurückgelegte Distanz:
labelDistance_Run = Label(master=tkFenster, bg='gray', text='')
labelDistance_Run.place(x=550, y=104, width=60, height=27)
# Label mit Aufschrift aktuelle Stufe:
labelcounter = Label(master=tkFenster, bg='#D5E88F', text='aktuelle Stufe:')
labelcounter.place(x=324, y=144, width=200, height=27)
# Label für aktuelle Stufe:
labelCounter = Label(master=tkFenster, bg='gray', text='')
labelCounter.place(x=550, y=144, width=60, height=27)
# Label mit Aufschrift Zeit:
labeltime = Label(master=tkFenster, bg='#D5E88F', text='Zeit:')
labeltime.place(x=324, y=144, width=200, height=27)
# Label für aktuelle Stufe:
labelTimer = Label(master=tkFenster, bg='gray', text='')
labelTimer.place(x=550, y=144, width=60, height=27)
# Aktivierung des Fensters
distance = 0 
clk = '0.000000'
total = 0
stop = 0
tkFenster.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@l3_12: Bevor man da etwas weiteres dazu bastelt, sollte das Fundament erst einmal belastbar sein. Da sind Fehler drin und ganz viel was man so nicht macht, sowohl allgemeine Sachen, als auch in Python im besonderen.

Sternchen-Importe sind Böse™. Gerade bei `tkinter` holt man sich unmengen an Namen ins Modul von denen nur wenige benutzt werden. Und nicht nur welche die im `tkinter`-Modul definiert werden, sondern auch alles was das `tkinter`-Modul seinerseits importiert. Üblich ist ``import tkinter as tk`` und dann der Zugriff über `tk.Button`, `tk.Label`, und so weiter. Der Import wird ja bereits (zusätzlich) so gemacht, dann aber nicht genutzt.

Ebenfalls nicht benutzt werden `socket`, `sleep`, und `np`.

``global`` und globale Variablen haben in einem sauberen Programm nichts zu suchen. Auf Modulebene sollte nur Code stehen, der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst. Alles was Funktionen und Methoden ausser Konstanten benötigen sollte als Argument(e) übergeben werden.

Die GUI darf nicht aus anderen Threads manipuliert werden als dem Thread in dem die `mainloop()` läuft. Das mag scheinbar funktionieren, aber das geht nur solange gut bis es dann doch mal kracht, weil es eben nicht garantiert ist, dass das so funktioniert.

Durch die vielen globalen Variablen hängt ja alles irgendwie mit allem anderen ziemlich undurchsichtig zusammen. Wenn man die globalen Variablen beseitigt, kann man auch gleich mal eine saubere Trennung von GUI und Programmlogik vornehmen. Wobei GUI hier auch für andere Formen der Benutzerineraktion steht, also beispielsweise Sprachausgaben. Die haben in der Programmlogik auch nichts verloren.

Namenskonvention in Python ist klein_mit_unterstrichen für alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase). Vermeiden sollte man Abkürzungen und nummerierte Namen. Bei nummerierten Namen will man entweder aussagekräftigere Namen wählen oder gar keine Einzelwerte sondern eine Datenstruktur. Oft eine Liste.

Funktions und Methodennamen beschreiben üblicherweise die Tätigkeit die sie durchführen. So etwas wie `conconi()` oder `feedback()` sind keine Tätigkeiten.

Beim Layout von GUIs verwendet man kein `place()`.

Edit: Der GUI-Code sieht den Programmen bei https://www.inf-schule.de/ sehr ähnlich – falls das die Quelle der Inspiration sein sollte, vergiss am besten alles was Du da gelesen hast. Das ist extrem gruselig und zeigt was man nicht machen sollte.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Antworten