1

I am creating a flashcard app to help with my language studies. The basic idea of the app is to loop through a list of words randomly while I give the answers. As I answer the flash cards the program brings up information for the word on the card, translation, example sentences, etc. Each time a new card comes a 'question_frame' is created and an 'answer_frame' is created for the card, the loop continue until all cards have been answered correctly. I have a feeling that this loop is somehow interfering with the bind as when I try to bind a button to the main window I get an error response in my command window, while nothing happens in the command window if I try to bind to the question or answer frame.

I've tried many of the answers to this kind of problem I have found on this website, binding to a function, using a lambda expression, etc. But nothing has been successful.

import tkinter as tk
import random

def get_random_deck():

    new_deck = to_study
    r = random.SystemRandom()
    r.shuffle(to_study)

    return new_deck


def question_page(deck):


    question_frame = tk.Frame(window, width = 600, height = 600)
    question_frame.grid(row = 0, column = 0, sticky = 'news')

    question_label = tk.Label(question_frame, text = deck[0][0])
    question_label.grid(row = 1, column = 1, columnspan = 2)
    question_entry = tk.Entry(question_frame)
    question_entry.grid(row = 2, column = 1, columnspan = 2)

    var = tk.BooleanVar(False)

    check_button = tk.Button(question_frame, text = 'Check Answer', command = set_value(var))
    check_button.grid(row = 3, column = 1, columnspan = 2)

    question_frame.bind('<Return>', (lambda event: check_button.invoke()))

    check_button.wait_variable(var)

    answer = question_entry.get()

    return answer

def answer_page(deck,color): 

    answer_frame = tk.Frame(window, width = 600, height = 600)

    answer_frame.grid(row = 0, column = 0, sticky = 'news')

    var = tk.BooleanVar(False)

    next_button = tk.Button(answer_frame, text = 'Next', command = set_value(var))
    next_button.grid(row = 3, column = 1, sticky = 'n')

    answer_frame.bind('<Return>', (lambda event: next_button.invoke()))

    next_button.wait_variable(var)

def set_value(var): 

    value  = lambda: var.set(True)
    return value    

def study_loop():

    deck = get_random_deck()

    while len(deck) > 0:

        r = random.SystemRandom()

        r.shuffle(deck)

        answer = question_page(deck)

        if answer in deck[0][1]:

            answer_page(deck, 'chartreuse2')


to_study = [['Big', 'small'], ['small', 'big']]

window = tk.Tk()

window.geometry('600x600')

study_loop()


window.mainloop()

I am using a BooleanVar to help move the loop along, perhaps there is a better way to do this but with my limited knowledge and experience this is the only way I could make it work.

So In summary I would like to be able to bind the enter key to input the flashcard answer on the question frame and then to advance from the answer page.

Rhys Flook
  • 185
  • 8
  • 1
    Read [Why is Button parameter “command” executed when declared?](https://stackoverflow.com/questions/5767228/why-is-button-parameter-command-executed-when-declared) – stovfl Oct 16 '19 at 12:21
  • Please try to reduce this code down to a [mcve]. There's a lot of code that's not directly related to the question being asked. – Bryan Oakley Oct 16 '19 at 14:29
  • Okay, I have added a reproducible example, I think I have cut out all the unnecessary code. I will also check out the 'Why is Button parameter “command” executed when declared?' answer page. – Rhys Flook Oct 16 '19 at 21:01
  • I have tried many things but no matter what I do I can't seem to invoke the button or change var using a bound key. There must be a way to do this that I am not seeing. – Rhys Flook Oct 17 '19 at 11:42

1 Answers1

0

So the solution turned out to be that I need to set the focus to the correct widget as I go through the study_loop.

I set focus on the Entry widget on the question frame and then bound the button invoke to that widget also.

question_entry.focus_set()
question_entry.bind('<Return>', lambda event: check_button.invoke())

and for the answer frame I set the focus and the key bind to the frame itself.

answer_frame.focus_set()
answer_frame.bind('<Return>', lambda event: check_button.invoke())

Now when I hit the enter key on each frame the loop continues on to the next frame.

Rhys Flook
  • 185
  • 8