Python Tkinter Entry return value

86 Views Asked by At

I'm trying to create an application and I'm stuck on a probably trivial, but for me permanent problem. I want Entry to return the user's input, but only after the user enters the answer and presses Enter. for a while. I get either that it returns the value before I press Enter. Or that it first returns None, so in the next iteration I get a returned answer to the previous question. The idea is to generate a question and the user enters the answer that I need to keep so that I can further check etc...

# Entry for entering answers within the quest_frame, within this frame I have another label for printing questions.

self.answer_entry = ttk.Entry(self.quest_frame)
self.answer_entry.pack(side=tk.LEFT,padx=10)
self.answer_entry["textvariable"] = self.answer_var
self.answer_entry.bind('<Key-Return>',      self.run_level)
# the rest of the code      
def run_level(self, event=None):
    self.answer_entry.focus() 
    #      user_answer = self.check_answer()      
    question = f"{first_num[0]} * {second_num[0]}"
    print(question)
    self.quest_label.config(text=question)
    self.answer_entry.delete(0,tk.END)`

I fell into some kind of loop because when I clear the input field, the run_level() method is restarted and the question is generated again and I can enter the answer again ....

I'm trying to write a program that will help children learn multiplication through games and competitions. I wrote the upper part but I'm stuck because I want the user's input to be forwarded to me only when the user presses Enter. For that I used the event in Entry.

self.answer_entry.bind('<Key-Return>',      self.run_level)

I tried to save the value in a variable that is an attribute of the class. self.answer_var = tk.StringVar()

In the end, after much persuasion, I got the order that the user enters back in the run_level method. But I have a problem that I get stuck and everything repeats itself endlessly. And the first time the question is asked self.answer_var return "None" to me, and then return the answer to the previous question on the next question.

1

There are 1 best solutions below

0
Suramuthu R On

Since the complete code is not available, it's bit difficult to comment. What I assume from your available code is:

  1. I'm not sure whether '< Key-Return >' is a valid argument for binding function. Generally I use just '< Return >'.
  2. As told in comments there may be some indentation issues

I try to help you in another way.

I had created a questioner-project for my daughter to revise sin, cos, tan values of known angles. I've just modified that for your requirement and posting here.(For multiplication table from 2 to 12). If your requirement is for higher values, you can change accordingly.

The main window has just a 'start session' button. If the kids the button,a pop-up window appears. The pop-up window will ask 10 questions one by one. Each right answer gives 10 points. Same-button meant for submitting and to ask next question. But, the text in button will change either 'submit' or 'next question' accordingly. After submitting, the text-entry widget disappears. For every question, score will be displayed. If the entry is blank or if you enter str instead of number, It gives you error text and wait for the correct input.After completing all the 10 questions, It will give you a Final score and the same button will ask you whether to ask another session. During the entire session, the start button in the main window will be disabled. And this will be re-enabled after the session is over.

In fact, I've typed the above paragraph because I couldn't add comments. Or I've to go thru the entire code once again.

After modifying, I checked and it is working alright. Please trace the functions one by one. Except the styling part, Everything i've written

Changing this to OOPS structure is not a big deal. When you yourself try to do that, You'll understand the entire concept.

from tkinter import *
import random as rd

root_width, root_height = 300, 200
popup_width, popup_height = 500, 400

def end(*evnt):
    global score, count
    score, count = 0, -1
    start_btn['state']=NORMAL
    root.bind('<Return>', start)
    top.destroy()

def get_ans(*evnt):
    global score, count
    global got_ans
    global score_board
    global got_ans
   
    answer_label.delete(0, END)
    answer_label['state']=DISABLED
    question_label.configure(text='')
    if count != 10:
        ans_btn.configure(text='Next Question', command=mult)
        top.bind('<Return>', mult) 
        
        if prod == got_ans:
            score = score + 10
            score_board.configure(text=f'''Good! You are correct!
Your Presenr Score is {score}/100''')
        else:
            ans_btn.configure(text='Next Question', command=mult)
            score_board.configure(text=f'''Sorry! the answer is {prod}.
Your Score is {score}/100''')
        
    else:
        if got_ans == prod: score_board.configure(text=f'Very Good! \nYour Total Score is {score+10}/100')
        else: score_board.configure(text=f'''Sorry! The answer is {prod}.
    Your Total Score is {score}/100''')
        ans_btn.unbind('<Button-1>')
        ans_btn.configure(text='Start Another Session or Close', width=30, command=end)
        top.bind('<Return>', end)
        
def start(*ee):
    global score, count
    score, count = 0, -1
    start_btn['state'] = DISABLED
    root.bind('<Return>', lambda e:'break')
    mult()
    mult()
    
def pop_up():
    global score, count
    global top
    global question
    global prod
    global count
    global answer_label
    global score_board
    global ans_btn
    global question_label
    global error_label
    global got_ans
    top = Toplevel()
    top.geometry(f'{popup_width}x{popup_height}')
    top.title('Multiplication Table')
    error_frame = Frame(top, width=popup_width, height=20)
    error_frame.pack(side='top')
    error_label = Label(error_frame, text='')
    error_label.pack(side='top')
    score_frm = Frame(top)
    score_frm.pack(side='top')
    Label(score_frm, text='Score Board').pack(side='top')
    score_board = Label(score_frm, text='')
    score_board.pack(side='top')
    question_frm = Frame(top)
    question_frm.pack(side='bottom')
    ans_btn = Button(question_frm, width=15, text='')
    ans_btn.pack(side='bottom')
    answer_label = Entry(question_frm, text= '')
    answer_label.pack(side='bottom')
    question_label = Label(question_frm, text='')
    question_label.pack(side='bottom')
    
    
def mult(*event):
    global score, count
    global prod
    global first_num
    global second_num
    global question_label
    global top
    global question
    global ans_btn
    if count >=1 :
        ans_btn.unbind('<Button-1>')
        top.bind('<Return>', lambda e:'break')
        score_board.configure(text=f'Your Presenr Score is {score}/100')
    
    count = count + 1
    if count==0: pop_up()
    else:
        lst = [x for x in range(2, 13)]
        first_num = rd.choice(lst)
        second_num = rd.choice(lst)
        prod = first_num*second_num
        answer_label.focus_set()
        question = f'Q.{count} : {first_num} x {second_num}'
        question_label.configure(text=question)
        answer_label['state']=NORMAL
        answer_label.bind('<Return>', buffer)
        ans_btn.configure(text='check Answer', command = buffer)
        
def buffer(*e):
    global score, count
    global answer_label
    global top
    global prod
    global got_ans
    ans_btn.unbind('<Button-1>')
    answer_label.bind('<Return>', lambda e:'break')
    error_label.configure(text='')
    top.focus_set()
    got_ans = answer_label.get()
    if got_ans.isdigit():
        got_ans = int(float(got_ans))
        get_ans()
    else:
        answer_label.focus_set()
        error_label.configure(text='Your Answer shoulb be a Number', fg='red')
        answer_label.bind('<Return>', buffer)
        ans_btn.configure(text='check Answer', command = buffer)
        
root = Tk()
root.geometry(f'{root_width}x{root_height}')
root.title('Multiplication')

# A Button in main window to start the session containing 10 questions
start_btn = Button(root, text='Start Session', command=start)
start_btn.pack(side='bottom')
root.bind('<Return>', start)
root.mainloop()