so I'm trying to make a timer (like cstimer.net) and I got this problem
I have binded the spacebar to start the timer, and then, once you started the timer, hitting it again would stop it. The problem is that when I hit the spacebar, it starts and finishes the timer. And the time, would not reset, it would just add the elapsed time to the last time.
Here's what I've done:
import pyglet
import os
import time
from tkinter import *
# Import scripts
import sys
sys.path.insert(1, './scripts')
import scrambler
import timer
import saver
class Application():
def __init__(self, app):
self.app = app
pyglet.font.add_file('./data/fonts/DS-DIGIB.TTF') # Add the time font
# Add the body (used for scramble and more elements) font
pyglet.font.add_file('./data/fonts/OverPassMono-Light.ttf')
# Create side panel
self.sidepanel = Frame(self.app, bg='red', width=200, height=800)
# Generate scramble
self.scramble_output = scrambler.gen_333scramble()
#Bind spacebar to start timer
self.app.bind('<Key>', self.updater_start)
# Define button, start time and scramble Widget and show them
self.display = Label(self.app, text='0.00', bg='#232931', fg='white', anchor=CENTER, font=('DS-DIGITAL', 64), pady=100)
self.scramble = Label(self.app, text=self.scramble_output, bg='#232931', fg='white', font=('Overpass Mono Light', 12), anchor=NW)
self.start_button = Button(self.app, text='Start', fg='white', bg='#4ecca3', command=self.start, anchor=CENTER)
#Show in grid
self.display.grid(row=1, column=1, sticky=EW, padx=275, pady=150)
self.start_button.grid(row=2, column=1, columnspan=2, padx=275, sticky=N, ipadx=20)
self.scramble.grid(row=0, column=1, sticky=EW, padx=275)
def start(self):
# Unshow last time or starting time
self.display.grid_remove()
# Start counting time
self.start_time = timer.start()
#Bind spacebar to stop timer
self.app.bind('<Key>', self.updater_stop)
# Create widgets to show the timer is running and finish button
self.state = Label(self.app, text='.', bg='#232931', fg='white', font=('DS-DIGITAL', 32))
self.state.grid(row=1, column=1, sticky=EW, padx=560, pady=300)
self.finish_button = Button(self.app, text='FINISH', fg='white', bg='#4ecca3', command=self.finish)
self.finish_button.grid(row=2, column=1, columnspan=2, padx=275, sticky=N, ipadx=20)
# Unshow start button and scramble widgets
self.start_button.grid_remove()
self.scramble.grid_remove()
def updater_start(self, e):
if e.keysym=='space':
print('Hitted spacebar')
self.start()
def updater_stop(self, e):
if e.keysym=='space':
print('Hitted spacebar')
self.finish()
def finish(self):
self.message = timer.finish(self.start_time)
# Display formatted time
self.display = Label(self.app, text=self.message, bg='#232931', fg='white', font=('DS-DIGITAL', 64), pady=100)
#Save time on times.json
saver.save_time(self.message, self.scramble_output)
# Unshow state and finish button widgets
self.finish_button.grid_remove()
self.state.grid_remove()
# Redefine widgets
self.start_button = Button(self.app, text='Start', fg='white', bg='#4ecca3', command=self.start)
self.scramble_output = scrambler.gen_333scramble()
self.scramble = Label(self.app, text=self.scramble_output, bg='#232931', fg='white', font=('Overpass Mono Light', 12), anchor=NW)
# Show widgets on screen and formatted time
self.display.grid(row=1, column=1, sticky=EW, padx=275, pady=150)
self.start_button.grid(row=2, column=1, columnspan=2, padx=275, sticky=N, ipadx=20)
self.scramble.grid(row=0, column=1, sticky=EW, padx=275)
Just so you can know, saver , timer and scrambler modules are scripts I made so I can slice the code. Timer script just takes the time.time() variable at the start and subtracts it with the current time, and then it format its as hours:seconds:minutes.
I recommend making a variable for the number of space bar presses. When you bind the space bar, check if it is even (0, 2, 4, etc.). That means it should start . Otherwise, it should end .
from tkinter import *
root = Tk()
NUM_SPACE_PRESS = 0
def space_press(e):
global NUM_SPACE_PRESS
if NUM_SPACE_PRESS % 2 == 0:
Label(text='<start here>').pack()
NUM_SPACE_PRESS += 1
else:
Label(text='<end here>').pack()
NUM_SPACE_PRESS += 1
root.bind("<space>", space_press)
root.mainloop()
You should use one function with variable ie. running
with True/False
to inform what to do - stop or start timer.
import tkinter as tk
def space_press(event):
global running
if running:
l['text'] = 'timer stoped'
else:
l['text'] = 'timer started'
# switch state
running = not running
# --- main ---
running = False
root = tk.Tk()
l = tk.Label(root, text='press space')
l.pack()
root.bind("<space>", space_press)
root.mainloop()
You need to reset the "<space>"
binding in finish()
function.
Below is a modified example based on yours:
class Application():
def __init__(self, app):
...
self.bind(self.start) # replace self.app.bind("<Key>", self.updater_start)
...
# added function
def bind(self, callback=None):
self.app.bind("<space>", callback)
def start(self, event=None):
self.bind() # disable space binding when busy
...
# removed self.app.bind("<Key>", self.updater_stop)
...
self.bind(self.finish)
def finish(self, event=None):
self.bind() # disable space binding when busy
...
self.bind(self.start)
Note that I have removed updater_start()
and updater_stop()
functions.
Rather than create new widgets, update the values of the existing ones. I used a tk.after to update the timer and a True/False to start/stop the timer. Note certain imports are commented out for me to run it.
# import pyglet
# import os
import time
from datetime import timedelta
from tkinter import *
# Import scripts
# import sys
# sys.path.insert(1, './scripts')
# import scrambler
# import timer
# import saver
class Application():
def __init__(self, app):
self.app = app
# pyglet.font.add_file('./data/fonts/DS-DIGIB.TTF') # Add the time font
# Add the body (used for scramble and more elements) font
# pyglet.font.add_file('./data/fonts/OverPassMono-Light.ttf')
# Create side panel
self.sidepanel = Frame(self.app, bg='red', width=200, height=800)
# Generate scramble
self.scramble_output = 'scramble_output goes here' # scrambler.gen_333scramble()
#Bind spacebar to start timer
self.app.bind('<space>', self.toggle_timer_running)
# Define button, start time and scramble Widget and show them
self.display = Label(self.app, text='0.00', bg='#232931', fg='white', anchor=CENTER, font=('DS-DIGITAL', 64), pady=100)
self.scramble = Label(self.app, text=self.scramble_output, bg='#232931', fg='white', font=('Overpass Mono Light', 12), anchor=NW)
self.start_button = Button(self.app, text='Start', fg='white', bg='#4ecca3', command=self.toggle_timer_running, anchor=CENTER)
#Show in grid
self.display.grid(row=1, column=1, sticky=EW, padx=275, pady=150)
self.start_button.grid(row=2, column=1, columnspan=2, padx=275, sticky=N, ipadx=20)
self.scramble.grid(row=0, column=1, sticky=EW, padx=275)
self._timer_running = False
self.start_time = self.end_time = time.time()
self.update()
def toggle_timer_running(self, event=None):
self._timer_running = not self._timer_running
if self._timer_running:
self.start_time = time.time()
self.start_button.config(text='Finish')
else:
self.start_button.config(text='Start')
def update(self):
if self._timer_running:
self.end_time = time.time()
duration = self.end_time - self.start_time
self.display.configure(text=timedelta(seconds= duration))
self.app.after(100, self.update)
if __name__ == '__main__':
app = Tk()
Application(app)
app.mainloop()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.