Solución:
Hay varias cosas mal en su código. Primero que nada, no deberías usar time.sleep()
en un programa de Tkinter porque interfiere con el mainloop()
. En su lugar, normalmente se usa el método de widget universal .after()
para programar una función para que se ejecute después de un retraso específico.
En segundo lugar, no está utilizando las variables globales correctamente. Cuando asigna un valor a una variable nombrada en una función, creará una variable local a menos que ese nombre haya sido declarado previamente global
. Entonces, por ejemplo, tu stop()
la función está creando una variable local llamada running
y estableciendo su valor en 0, no cambiando el valor de la variable global con el mismo nombre.
La regla anterior no se aplica solo a hacer referencia (leer) al valor actual de una variable. Por eso estaba bien no haber declarado Freq
y Dur
globales en start()
.
Otro problema es con el sec % 1 == 0
en tus start()
función. Algún valor % 1
es 0
. Para comprobar el uso impar / uniforme sec % 2
.
Aquí hay una versión funcional que también ha sido reformateada para seguir más de cerca la Guía de estilo de PEP 8 para código Python.
import Tkinter
import tkMessageBox
import time
import winsound
FREQ = 2500
DUR = 150
after_id = None
secs = 0
def beeper():
global after_id
global secs
secs += 1
if secs % 2 == 0: # every other second
winsound.Beep(FREQ, DUR)
after_id = top.after(1000, beeper) # check again in 1 second
def start():
global secs
secs = 0
beeper() # start repeated checking
def stop():
global after_id
if after_id:
top.after_cancel(after_id)
after_id = None
top = Tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100')
startButton = Tkinter.Button(top, height=2, width=20, text="Start",
command=start)
stopButton = Tkinter.Button(top, height=2, width=20, text="Stop",
command=stop)
startButton.pack()
stopButton.pack()
top.mainloop()
Tu código tiene top.mainloop()
que tiene un while
bucle que se ejecuta dentro de él y, además de eso, también tiene un bucle while dentro def start():
. Entonces es como un bucle dentro del bucle.
Puede crear una función que haga lo que quiera para el cuerpo del bucle. Debería hacer exactamente una iteración del ciclo. Una vez hecho esto, necesita arreglarse para ser llamado nuevamente en el futuro usando after
. Qué tan lejos en el futuro define qué tan rápido se ejecuta su ciclo.
Y luego puedes usar after_cancel
para cancelar el evento. El siguiente código funcionó para mí
import Tkinter, tkMessageBox, time, winsound, msvcrt
Freq = 2500
Dur = 150
top = tkinter.Tk()
top.title('MapAwareness')
top.geometry('200x100') # Size 200, 200
def start():
global job1
if running == True:
winsound.Beep(Freq, Dur)
job1 = top.after(1000, start) # reschedule event in 1 seconds
def stop():
global job1
top.after_cancel(job1)
startButton = tkinter.Button(top, height=2, width=20, text ="Start", command = start)
stopButton = tkinter.Button(top, height=2, width=20, text ="Stop", command = stop)
startButton.pack()
stopButton.pack()
#top.after(1000, start)
top.mainloop()