Skip to content

Commit 53690e7

Browse files
committed
add type speed tester tutorial
1 parent 15f9e33 commit 53690e7

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,5 +217,6 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
217217
- [How to Make a Drawing Program in Python](https://www.thepythoncode.com/article/make-a-drawing-program-with-python). ([code](gui-programming/drawing-tool-in-pygame))
218218
- [How to Make a File Explorer using Tkinter in Python](https://www.thepythoncode.com/article/create-a-simple-file-explorer-using-tkinter-in-python). ([code](gui-programming/file-explorer))
219219
- [How to Make a Calculator with Tkinter in Python](https://www.thepythoncode.com/article/make-a-calculator-app-using-tkinter-in-python). ([code](gui-programming/calculator-app))
220+
- [How to Make a Typing Speed Tester with Tkinter in Python](https://www.thepythoncode.com/article/how-to-make-typing-speed-tester-in-python-using-tkinter). ([code](gui-programming/type-speed-tester))
220221

221222
For any feedback, please consider pulling requests.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [How to Make a Typing Speed Tester with Tkinter in Python](https://www.thepythoncode.com/article/how-to-make-typing-speed-tester-in-python-using-tkinter)
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
from tkinter import *
2+
import ctypes
3+
import random
4+
import tkinter
5+
6+
# For a sharper window
7+
ctypes.windll.shcore.SetProcessDpiAwareness(1)
8+
9+
# Setup
10+
root = Tk()
11+
root.title('Type Speed Test')
12+
13+
# Setting the starting window dimensions
14+
root.geometry('700x700')
15+
16+
# Setting the Font for all Labels and Buttons
17+
root.option_add("*Label.Font", "consolas 30")
18+
root.option_add("*Button.Font", "consolas 30")
19+
20+
21+
# functions
22+
def keyPress(event=None):
23+
try:
24+
if event.char.lower() == labelRight.cget('text')[0].lower():
25+
# Deleting one from the right side.
26+
labelRight.configure(text=labelRight.cget('text')[1:])
27+
# Deleting one from the right side.
28+
labelLeft.configure(text=labelLeft.cget('text') + event.char.lower())
29+
#set the next Letter Lavbel
30+
currentLetterLabel.configure(text=labelRight.cget('text')[0])
31+
except tkinter.TclError:
32+
pass
33+
34+
35+
def resetWritingLabels():
36+
# Text List
37+
possibleTexts = [
38+
'For writers, a random sentence can help them get their creative juices flowing. Since the topic of the sentence is completely unknown, it forces the writer to be creative when the sentence appears. There are a number of different ways a writer can use the random sentence for creativity. The most common way to use the sentence is to begin a story. Another option is to include it somewhere in the story. A much more difficult challenge is to use it to end a story. In any of these cases, it forces the writer to think creatively since they have no idea what sentence will appear from the tool.',
39+
'The goal of Python Code is to provide Python tutorials, recipes, problem fixes and articles to beginner and intermediate Python programmers, as well as sharing knowledge to the world. Python Code aims for making everyone in the world be able to learn how to code for free. Python is a high-level, interpreted, general-purpose programming language. Its design philosophy emphasizes code readability with the use of significant indentation. Python is dynamically-typed and garbage-collected. It supports multiple programming paradigms, including structured (particularly procedural), object-oriented and functional programming. It is often described as a "batteries included" language due to its comprehensive standard library.',
40+
'As always, we start with the imports. Because we make the UI with tkinter, we need to import it. We also import the font module from tkinter to change the fonts on our elements later. We continue by getting the partial function from functools, it is a genius function that excepts another function as a first argument and some args and kwargs and it will return a reference to this function with those arguments. This is especially useful when we want to insert one of our functions to a command argument of a button or a key binding.'
41+
]
42+
# Chosing one of the texts randomly with the choice function
43+
text = random.choice(possibleTexts).lower()
44+
# defining where the text is split
45+
splitPoint = 0
46+
# This is where the text is that is already written
47+
global labelLeft
48+
labelLeft = Label(root, text=text[0:splitPoint], fg='grey')
49+
labelLeft.place(relx=0.5, rely=0.5, anchor=E)
50+
51+
# Here is the text which will be written
52+
global labelRight
53+
labelRight = Label(root, text=text[splitPoint:])
54+
labelRight.place(relx=0.5, rely=0.5, anchor=W)
55+
56+
# This label shows the user which letter he now has to press
57+
global currentLetterLabel
58+
currentLetterLabel = Label(root, text=text[splitPoint], fg='grey')
59+
currentLetterLabel.place(relx=0.5, rely=0.6, anchor=N)
60+
61+
# this label shows the user how much time has gone by
62+
global timeleftLabel
63+
timeleftLabel = Label(root, text=f'0 Seconds', fg='grey')
64+
timeleftLabel.place(relx=0.5, rely=0.4, anchor=S)
65+
66+
global writeAble
67+
writeAble = True
68+
root.bind('<Key>', keyPress)
69+
70+
global passedSeconds
71+
passedSeconds = 0
72+
73+
# Binding callbacks to functions after a certain amount of time.
74+
root.after(60000, stopTest)
75+
root.after(1000, addSecond)
76+
77+
def stopTest():
78+
global writeAble
79+
writeAble = False
80+
81+
# Calculating the amount of words
82+
amountWords = len(labelLeft.cget('text').split(' '))
83+
84+
# Destroy all unwanted widgets.
85+
timeleftLabel.destroy()
86+
currentLetterLabel.destroy()
87+
labelRight.destroy()
88+
labelLeft.destroy()
89+
90+
# Display the test results with a formatted string
91+
global ResultLabel
92+
ResultLabel = Label(root, text=f'Words per Minute: {amountWords}', fg='black')
93+
ResultLabel.place(relx=0.5, rely=0.4, anchor=CENTER)
94+
95+
# Display a button to restart the game
96+
global ResultButton
97+
ResultButton = Button(root, text=f'Retry', command=restart)
98+
ResultButton.place(relx=0.5, rely=0.6, anchor=CENTER)
99+
100+
def restart():
101+
# Destry result widgets
102+
ResultLabel.destroy()
103+
ResultButton.destroy()
104+
105+
# re-setup writing labels.
106+
resetWritingLabels()
107+
108+
def addSecond():
109+
# Add a second to the counter.
110+
111+
global passedSeconds
112+
passedSeconds += 1
113+
timeleftLabel.configure(text=f'{passedSeconds} Seconds')
114+
115+
# call this function again after one second if the time is not over.
116+
if writeAble:
117+
root.after(1000, addSecond)
118+
119+
# This will start the Test
120+
resetWritingLabels()
121+
122+
# Start the mainloop
123+
root.mainloop()

0 commit comments

Comments
 (0)