Search code examples
pythontkintertkinter-button

Why won't function run when I press tkinter button?


I'm currently finishing up a python programming bootcamp on Udemy, and I'm trying to make a typing speed test using tkinter. I think the issue I'm having is when I try to press the "start test" button, nothing seems to happen. I appreciate any input and thank you in advance!

I wanted to check my work so far to make sure what I'd put down was working, but when I tried running the program, nothing happened. The idea is once the user clicks the start button, a 'timer' starts counting down from 60, and a word from the word bank appears above the entry box; so far, when StartButton is clicked, nothing seems to happen in the window. Here's my code so far:

EDIT: The issue I'm having now is the correct_words variable only updates once when I check an answer; every other time, it just stays at 1. Also, the results pop-up shows correct_words still equalling 0 instead of the total number of correct entries.

import tkinter as tk
import random

wordbank = ['Lorem', 'ipsum', 'dolor', 'sit', 'amet,', 'consectetur', 'adipiscing', 'elit.', 'Nam', 'vitae', 'interdum', 'purus.', 'Mauris', 'pharetra', 'volutpat', 'augue,', 'id', 'elementum', 'enim', 'auctor', 'eget.', 'Praesent', 'diam', 'nulla,', 'condimentum', 'eget', 'cursus', 'sed,', 'imperdiet', 'vitae', 'arcu.', 'Quisque', 'lacus', 'enim,', 'finibus', 'eu', 'dolor', 'sit', 'amet,', 'pretium', 'pulvinar', 'libero.', 'In', 'maximus', 'elementum', 'varius.', 'Praesent', 'est', 'dui,', 'ultricies', 'vel', 'facilisis', 'non,', 'imperdiet', 'eget', 'eros.', 'Class', 'aptent', 'taciti', 'sociosqu', 'ad', 'litora', 'torquent', 'per', 'conubia', 'nostra,', 'per', 'inceptos', 'himenaeos.', 'Nunc', 'in', 'odio', 'nec', 'massa', 'faucibus', 'rhoncus', 'non', 'eu', 'libero.', 'Suspendisse', 'aliquam', 'iaculis', 'tellus,', 'ut', 'malesuada', 'purus', 'elementum', 'id.', 'Cras', 'ipsum', 'est,', 'sollicitudin', 'eu', 'ipsum', 'vehicula,', 'condimentum', 'volutpat', 'enim.', 'Fusce', 'massa', 'ipsum,', 'tempus', 'vel', 'dictum', 'sit', 'amet,', 'pretium', 'ut', 'nisl.', 'Pellentesque', 'vitae', 'convallis', 'neque,', 'eu', 'posuere', 'arcu.', 'Aenean', 'tempor', 'mi', 'risus,', 'aliquet', 'porta', 'metus', 'condimentum', 'ut.', 'Sed', 'sagittis', 'justo', 'magna,', 'sit', 'amet', 'suscipit', 'sem', 'pulvinar', 'hendrerit.', 'Integer', 'vitae', 'viverra', 'dui.', 'Vestibulum', 'ante', 'ipsum', 'primis', 'in', 'faucibus', 'orci', 'luctus', 'et', 'ultrices', 'posuere', 'cubilia', 'curae;', 'Aenean', 'pretium', 'augue', 'in', 'purus', 'tincidunt,', 'a', 'ornare', 'ligula', 'bibendum.', 'Aenean', 'condimentum', 'turpis', 'id', 'libero', 'pellentesque', 'rutrum.', 'Aliquam', 'scelerisque', 'vitae', 'massa', 'et', 'porttitor.', 'Etiam', 'erat', 'ex,', 'semper', 'at', 'faucibus', 'in,', 'semper', 'nec', 'turpis.', 'Donec', 'vel', 'tincidunt', 'justo,', 'sodales', 'posuere', 'nibh.', 'Duis', 'porttitor', 'risus', 'accumsan,', 'semper', 'nibh', 'nec,', 'malesuada', 'magna.', 'Integer', 'massa', 'arcu,', 'tincidunt', 'ut', 'interdum', 'ut,', 'auctor', 'quis', 'risus.', 'Nulla', 'facilisi.', 'Morbi', 'eleifend', 'massa', 'erat,', 'id', 'vestibulum', 'odio', 'sagittis', 'eu.', 'Sed', 'rhoncus,', 'ante', 'id', 'sollicitudin', 'imperdiet,', 'risus', 'lacus', 'mattis', 'lorem,', 'ut', 'fermentum', 'mi', 'dui', 'sit', 'amet', 'diam.', 'Fusce', 'vulputate', 'bibendum', 'lacinia.', 'Curabitur', 'iaculis', 'ex', 'sed', 'lectus', 'auctor,', 'quis', 'dapibus', 'odio', 'euismod.', 'Fusce', 'convallis', 'maximus', 'placerat.', 'Curabitur', 'non', 'ullamcorper', 'ligula,', 'elementum', 'consectetur', 'odio.', 'Phasellus', 'suscipit', 'lorem', 'pulvinar', 'porta', 'tincidunt.', 'In', 'vel', 'metus', 'neque.', 'Integer', 'tincidunt', 'laoreet', 'pharetra.', 'Integer', 'volutpat', 'elit', 'at', 'sollicitudin', 'laoreet.', 'Ut', 'aliquam', 'semper', 'tristique.', 'Phasellus', 'pretium', 'nisi', 'imperdiet', 'nunc', 'ornare', 'dictum.', 'Nunc', 'iaculis,', 'dolor', 'nec', 'faucibus', 'interdum,', 'nunc', 'tellus', 'maximus', 'leo,', 'nec', 'mollis', 'felis', 'lectus', 'in', 'quam.', 'Duis', 'enim', 'augue,', 'vestibulum', 'quis', 'sagittis', 'vitae,', 'fringilla', 'cursus', 'enim.', 'Phasellus', 'volutpat,', 'ante', 'in', 'rutrum', 'lacinia,', 'leo', 'urna', 'ornare', 'sem,', 'non', 'dictum', 'nisl', 'libero', 'vitae', 'libero.', 'Aliquam', 'ac', 'est', 'sed', 'arcu', 'interdum', 'elementum.', 'Nullam', 'tincidunt,', 'dolor', 'sed', 'pharetra', 'facilisis,', 'sapien', 'nunc', 'ultricies', 'justo,', 'sed', 'maximus', 'purus', 'turpis', 'in', 'ante.', 'Vestibulum', 'non', 'erat', 'molestie,', 'tincidunt', 'lectus', 'non,', 'tempor', 'enim.', 'Mauris', 'ligula', 'leo,', 'volutpat', 'in', 'vestibulum', 'et,', 'porttitor', 'sit', 'amet', 'diam.', 'Sed', 'vel', 'justo', 'dolor.', 'Duis', 'nec', 'felis', 'placerat,', 'sollicitudin', 'felis', 'id,', 'eleifend', 'purus.', 'Cras', 'non', 'porta', 'tellus.', 'Cras', 'et', 'sapien', 'feugiat,', 'aliquet', 'nibh', 'ac,', 'molestie', 'ex.', 'Aenean', 'vitae', 'scelerisque', 'lectus.', 'Proin', 'pulvinar', 'mollis', 'nulla,', 'nec', 'luctus', 'lacus', 'dapibus', 'quis.', 'Phasellus', 'scelerisque', 'eros', 'a', 'neque', 'pharetra', 'cursus.', 'Quisque', 'urna', 'est,', 'consequat', 'sed', 'ipsum', 'ut,', 'consequat', 'malesuada', 'odio.', 'Nunc', 'posuere', 'leo', 'nec', 'lacus', 'malesuada', 'efficitur.', 'Ut', 'fermentum', 'tincidunt', 'felis', 'vitae', 'sollicitudin.', 'Curabitur', 'sed', 'neque', 'bibendum,', 'fringilla', 'orci', 'nec,', 'consectetur', 'mauris.', 'Phasellus', 'ultrices', 'semper', 'mauris,', 'ultrices', 'mattis', 'lectus.', 'Nunc', 'sit', 'amet', 'auctor', 'neque.', 'Morbi', 'sed', 'neque', 'maximus,', 'egestas', 'sapien', 'et,', 'congue', 'augue.', 'Morbi', 'lacus', 'orci,', 'tincidunt', 'a', 'diam', 'sit', 'amet,', 'finibus', 'scelerisque', 'nisl.', 'Aenean', 'egestas', 'luctus', 'diam,', 'sit', 'amet', 'iaculis', 'urna', 'tempus', 'id.']

window = tk.Tk()
window.title('Typing Speed Test!')
    
correct_words = 0
seconds = 60
test_word = tk.StringVar(value=random.choice(wordbank))

scoreboard = tk.Label(window, text=f'Correct Words: {correct_words}')
scoreboard.grid(row=0, column=0)

timeclock = tk.Label(window, text=f'Seconds: {seconds}')
timeclock.grid(row=1, column=0)

def results_popup(correct_words):
    popup = tk.Toplevel(window)
    popup.geometry("300x100")
    popup.title("Results")
    tk.Label(popup, text= f"{correct_words} words per minute!", font=('Mistral 18 bold')).place(x=150,y=80)
    
def run_test(seconds):
    if seconds > 0:
        timeclock.config(text=f'Seconds: {seconds}')
        window.after(1000, lambda: run_test(seconds - 1))
    else:
        timeclock.config(text='Time\'s Up!')
        results_popup()
        

def check_word(test_word, correct_words):
    if TypeBox.get() == test_word.get():
        correct_words += 1
        scoreboard.config(text=f'Correct Words: {correct_words}')
    test_word.set(random.choice(wordbank))

WordDisplay = tk.Label(window, textvariable=test_word)
WordDisplay.grid(row=2, column=0)

TypeBox = tk.Entry(window)
TypeBox.grid(row=3, column=0)

StartButton = tk.Button(window, text='Start Test! >:)', command=lambda: run_test(seconds))
StartButton.grid(row=2, column=1)

CheckAnswer = tk.Button(window, text='Check Answer!', command=lambda: check_word(test_word, correct_words))
CheckAnswer.grid(row=3, column=1)

window.mainloop()

Solution

  • Description:

    There were two issues in your code first issue was that you are creating the variables too early which is causing RuntimeError: Too early to create variables to avoid this error its a good practice to first create the tkinter window and then create variables.

    The second error is that inside the run_test() function you have a while loop which is taking seconds > 0 as a condition but seconds is not defined inside the function. in-order to make seconds variable accessible inside the function you can add seconds as a positional argument for the run_test() function.

    Improved Solution:

    This is an improved solution of the code you provided, if you observe I didn't use any for or while loop and neither the sleep() function which cause the tkinter window to hang.

    import tkinter as tk
    import random
    
    window = tk.Tk()
    window.title('Typing Speed Test!')
    
    wordbank = ['Lorem', 'ipsum', 'dolor', 'sit', 'amet,', 'consectetur', 'adipiscing', 'elit.', 'Nam', 'vitae', 'interdum', 'purus.', 'Mauris', 'pharetra', 'volutpat', 'augue,', 'id', 'elementum', 'enim', 'auctor', 'eget.', 'Praesent', 'diam', 'nulla,', 'condimentum', 'eget', 'cursus', 'sed,', 'imperdiet', 'vitae', 'arcu.', 'Quisque', 'lacus', 'enim,', 'finibus', 'eu', 'dolor', 'sit', 'amet,', 'pretium', 'pulvinar', 'libero.', 'In', 'maximus', 'elementum', 'varius.', 'Praesent', 'est', 'dui,', 'ultricies', 'vel', 'facilisis', 'non,', 'imperdiet', 'eget', 'eros.']
    
    correct_words = 0
    seconds = 60
    test_word = tk.StringVar(value=random.choice(wordbank))
    
    scoreboard = tk.Label(window, text=f'Correct Words: {correct_words}')
    scoreboard.grid(row=0, column=0)
    
    timeclock = tk.Label(window, text=f'Seconds: {seconds}')
    timeclock.grid(row=1, column=0)
    
    def run_test(seconds):
        if seconds >= 0:
            timeclock.config(text=f'Seconds: {seconds}')
            window.after(1000, lambda: run_test(seconds - 1))
        else:
            timeclock.config(text='Time\'s Up!')
    
    def check_word(test_word, correct_words):
        if TypeBox.get() == test_word.get():
            correct_words += 1
            scoreboard.config(text=f'Correct Words: {correct_words}')
            WordDisplay.config(text='Correct!')
        else:
            WordDisplay.config(text='Try Again!')
            
        test_word.set(random.choice(wordbank))
        return correct_words
    
    WordDisplay = tk.Label(window, textvariable=test_word)
    WordDisplay.grid(row=2, column=0)
    
    TypeBox = tk.Entry(window)
    TypeBox.grid(row=3, column=0)
    
    StartButton = tk.Button(window, text='Start Test! >:)', command=lambda: run_test(seconds))
    StartButton.grid(row=2, column=1)
    
    CheckAnswer = tk.Button(window, text='Check Answer!', command=lambda: update_score())
    CheckAnswer.grid(row=3, column=1)
    
    def update_score():
        global correct_words
        correct_words = check_word(test_word, correct_words)
    
    window.mainloop()
    
    
    

    Solution:

    Here's your code with fixed error:

    import tkinter as tk
    from tkinter import ttk, StringVar
    import random
    from time import *
    
    window = tk.Tk()
    window.title('Typing Speed Test!')
    
    wordbank = ['Lorem', 'ipsum', 'dolor', 'sit', 'amet,', 'consectetur', 'adipiscing', 'elit.', 'Nam', 'vitae', 'interdum', 'purus.', 'Mauris', 'pharetra', 'volutpat', 'augue,', 'id', 'elementum', 'enim', 'auctor', 'eget.', 'Praesent', 'diam', 'nulla,', 'condimentum', 'eget', 'cursus', 'sed,', 'imperdiet', 'vitae', 'arcu.', 'Quisque', 'lacus', 'enim,', 'finibus', 'eu', 'dolor', 'sit', 'amet,', 'pretium', 'pulvinar', 'libero.', 'In', 'maximus', 'elementum', 'varius.', 'Praesent', 'est', 'dui,', 'ultricies', 'vel', 'facilisis', 'non,', 'imperdiet', 'eget', 'eros.']
    
    correct_words = 0
    seconds = 60
    test_word = tk.StringVar(value=random.choice(wordbank))
    
    scoreboard = tk.Label(window, text=f'Correct Words: {correct_words}')
    scoreboard.grid(row=0, column=0)
    
    timeclock = tk.Label(window, text=f'Seconds: {seconds}')
    timeclock.grid(row=1, column=0)
    
    def run_test(seconds):
        while seconds > 0:
            seconds -= 1
            timeclock.configure(text=f'Seconds: {seconds}')
            sleep(1)
            window.update()
        timeclock.text = 'Time\'s Up!'
        window.update()
    
    def check_word():
        if TypeBox.get() == test_word:
            correct_words += 1
        else:
            WordDisplay.text = 'Try Again!'
            sleep(1)
        test_word = random.choice(wordbank)
        window.update()
    
    WordDisplay = tk.Label(window, textvariable=test_word)
    WordDisplay.grid(row=2, column=0)
    
    TypeBox = tk.Entry(window, textvariable=StringVar)
    TypeBox.grid(row=3, column=0)
    
    StartButton = tk.Button(window, text='Start Test! >:)', command=lambda: run_test(seconds))
    StartButton.grid(row=2, column=1)
    
    CheckAnswer = tk.Button(window, text='Check Answer!', command=check_word)
    CheckAnswer.grid(row=3, column=1)
    
    window.mainloop()
    

    Note:

    Your code had many mistakes, try to upload a code that doesn't have this many errors.

    Using for or while loop inside of tkinter window is not a good practice. Since, tkinter window keeps itself displaying by using a loop function called mainloop() which repeatedly opens the window after it's closed, adding another loop inside the window causes discontinuity in the mainloop() function.