Reputation: 5
I am working on a typing speed app. typing speed application GUI
Until now my app can:
After changing background of first word from Base text, I want my app to wait until user will type first word in Type here and press space key. When user presses space, my loop must go forward, change background of second word, wait again for typing text in Type here and so on until it reaches the end of Base text. I can do this if I create a click button and associate it with a command that changes a value when user clicks this button. After that I can use .wait_variable() in for loop. This way, for loop will stop and wait until user types in Type here and presses button, but this is not a good design for my app.
Can someone give me a hint or another solution? Maybe my for loop is not the best approach. Thank you!
This is my code:
main.py
from typingspeed import TypingSpeedApp
my_app = TypingSpeedApp()
my_app.read_text_file()
my_app.find_space_intervals()
my_app.type_and_check()
my_app.main_loop()
typingspeed.py
import tkinter
from tkinter import *
import time
import keyboard
class TypingSpeedApp:
def __init__(self):
self.typing_speed_app = Tk()
self.typing_speed_app.title("Typing Speed Application")
self.typing_speed_app.minsize(1200, 700)
self.typing_speed_app.resizable(False, False)
# define background image
self.background_image = PhotoImage(file="background_image.PNG")
# create canvas
self.canvas = Canvas(self.typing_speed_app, width=1200, height=700)
self.canvas.pack(fill="both", expand=True)
# set image in canvas
self.canvas.create_image(0, 0, image=self.background_image, anchor="nw")
# add a label
self.canvas.create_text(590, 50, text="Welcome to typing speed application", font=("Helvetica", 30),
fill="white")
# add a label
self.canvas.create_text(130, 90, text="Base text:", font=("Helvetica", 20), fill="white", state=DISABLED)
# Define Entry Boxes
self.base_text = Text(self.typing_speed_app, font=("Helvetica", 24), width=60, height=2, bd=0,
wrap=tkinter.WORD)
self.base_text_window = self.canvas.create_window(70, 120, anchor="nw", window=self.base_text)
# add a label
self.canvas.create_text(130, 220, text="Type here:", font=("Helvetica", 20), fill="white")
# Define Entry Boxes
self.type_text = Text(self.typing_speed_app, font=("Helvetica", 24), width=20, height=1, bd=0,
wrap=tkinter.WORD)
self.type_text_window = self.canvas.create_window(70, 250, anchor="nw", window=self.type_text)
# add a label
self.canvas.create_text(510, 220, text="Timer:", font=("Helvetica", 20), fill="white")
# Define Entry Boxes
self.time_text = Text(self.typing_speed_app, font=("Helvetica", 24), width=5, height=1, bd=0,
background="green")
self.time_text_window = self.canvas.create_window(470, 250, anchor="nw", window=self.time_text)
# text get from base_text
self.base_text_get_test = ""
# this list contain indexes of spaces
self.space_indexes = ["1.0"]
self.space_is_not_press = tkinter.StringVar()
self.text_from_type_text = ""
# show gui
def main_loop(self):
self.typing_speed_app.mainloop()
def read_text_file(self):
with open('text_1.txt') as text_file:
lines = str(text_file.readlines())
self.base_text.insert(tkinter.END, lines[2:-2] + " ")
self.base_text.configure(state=DISABLED)
self.base_text_get_test = self.base_text.get(0.1, tkinter.END)
def find_space_intervals(self):
idx = '1.0'
while 1:
idx = self.base_text.search(" ", idx, stopindex=END)
if not idx:
break
last_idx = '%s+%dc' % (idx, 1)
self.space_indexes.append(idx)
self.space_indexes.append(last_idx)
idx = last_idx
def wait_until_space_is_pressed(self):
pass
def type_and_check(self):
for index in range(0, len(self.space_indexes) - 1, 2):
self.base_text.tag_add("select", self.space_indexes[index], self.space_indexes[index + 1])
self.base_text.tag_configure("select", background="gray")
self.base_text.see(f"{self.space_indexes[index]}")
self.typing_speed_app.update()
time.sleep(0.02)
#self.typing_speed_app.wait_variable(self.space_is_not_press)
# ???????????
# stop for loop and wait until user press space key
# ???????????
self.base_text.tag_remove("select", self.space_indexes[index], self.space_indexes[index + 1])
and background_image enter image description here
Upvotes: 0
Views: 88
Reputation: 385980
GUI programs are event-based. That means that you don't normally write application code that waits for something since the GUI framework is always waiting for all events. In tkinter this happens when you call mainloop()
. Instead, you configure the GUI to respond to specific events. In your case, the event is when the space key has been pressed.
In tkinter you do this with the bind
method. You call it on a widget and you specify an event and a function, and tkinter will wait for that event and then call that function.
So, sometime after creating self.type_text
you need to add something like following code:
self.type_text.bind("<space>", self.space_detected)
Tkinter will call self.space_detected
whenever the user types a space. You then need to define the space_detected
method. It will be passed an event, though you won't need the information in this object.
Within that function, you can put any logic you want. For example, this is where you would want to unhighlight the current word and highlight the next.
Due to how tkinter processes events, note that this function will be called before the space is actually inserted into the widget. This is by design, and is actually a very powerful feature of tkinter. For more information, see this answer which explains it in a bit more detail.
Upvotes: 0