I have created a table in Tkinter by repetition of widgets following the importation of a text file (which therefore creates new rows depending on the containing information).
The following image shows that I need to be able to create from column '7' onwards a separate area of entry boxes depending on the OptionMenu choice.
For an option list the user is asked how many entry boxes they wish to fill in (therefore 'n' boxes created). For a 'Fixed' value there should be no boxes and any before deleted. For two other options in the OptionMenu there is always a Min and Max value (2 boxes). Each value in these boxes needs to be collected following their input via the user.
I have previously had help with the possibility of create a new frame each time but if possible would like to use the same one. I have the following code for the choice:
if choice == "Fixed":
for i in xrange(self.number_boxes):
self.box[i].grid_remove()
self.choice_title.grid_remove()
self.frame_table.grid_columnconfigure(7, weight=0)
tkMessageBox.showinfo("Message", "Value fixed.")
elif choice == "List":
self.win2 = tk.Toplevel(self.root)
self.win2.title("List")
self.list_text = Label(self.win2, text="Please enter number of values to be used:")
self.list_text.grid(row=0, column=0, sticky="nsew", padx=1, pady=1)
self.value = StringVar()
self.list_values = Entry(self.win2, textvariable=self.value, justify="center")
self.list_values.grid(row=1, column=1, sticky="nsew", padx=1, pady=1)
list_button = ttk.Button(self.win2, text="Enter", command=self.ValueBox)
list_button.grid(row=2, column=1, sticky="nsew", padx=1, pady=1)
self.win2.mainloop()
column = 7
self.number_boxes = int(self.number_boxes)
self.numbers = [StringVar() for i in xrange(self.number_boxes) ]
self.box = []
for i in xrange(self.number_boxes):
self.clicked.append(False)
self.choice_title = Label(self.frame_table, bg=self.mycolour, borderwidth=0, width=10)
self.choice_title.grid(row=1, column=self.column, columnspan=self.number_boxes, sticky="nsew", padx=1, pady=1)
self.box.append(Entry(self.frame_table,bg='white',borderwidth=0, width=10, justify="center", textvariable=self.numbers[i], fg='grey'))
self.box[i].grid(row=self.row_list,column=self.column+i, sticky='nsew', padx=1, pady=1)
self.box[i].insert(0, "Value %g" % float(i+1))
self.box[i].bind("<Button-1>", lambda event : self.callback(event))
self.total_boxes = self.number_boxes * ( rows - 2 )
self.boxes=[]
self.boxes.append(self.box[i])
tkMessageBox.showinfo("Message", "Please fill in list values.")
for i in self.numbers:
i.trace('w',lambda : self.numberwritten() )
elif choice == "Min" or "Max":
self.numbers = [StringVar() for i in xrange(2) ] #Name available in global scope.
self.number_boxes = 2
self.box = []
for i in xrange(2):
self.clicked.append(False)
self.choice_title = Label(self.frame_table, bg=self.mycolour, borderwidth=0)
self.choice_title.grid(row=1, column=self.column, columnspan=2, sticky="nsew", padx=1, pady=1)
self.box.append(Entry(self.frame_table,bg='white',borderwidth=0,textvariable=self.numbers[i], justify='center', fg='grey'))
self.box[i].grid(row=self.row_list, column=self.column+i, sticky='nsew', padx=1, pady=1)
if i == 0:
self.box[0].insert(0, "Min value")
elif i == 1:
self.box[1].insert(0, "Max value")
self.box[i].bind("<Button-1>", lambda event : self.callback(event))
self.boxes=[]
self.boxes.append(self.box[i])
tkMessageBox.showinfo("Message", "Enter Min/Max values.")
for i in self.numbers:
i.trace('w',lambda a,b,n=i: self.numberwritten(n) )
UPDATE section
def numberwritten(self): # where the above code block is usually all indented differently in comparision to this.
self.numbers.get()
def callback(self, event, index):
if (self.clicked[index] == False):
self.box[index].delete(0, END)
self.box[index].config(fg='black')
self.clicked[index] = True
I don't want to bombard this question with code but if any other functions such as numberwritten are needed I can provide them. I would very much appreciate some help as I'm nearing the end of it but am struggling with the 'final touches'.
There are a few things fishy in the following loop (I'll add comments at the fishy spots).
for i in xrange(self.number_boxes):
self.clicked.append(False)
self.choice_title = Label(self.frame_table, bg=self.mycolour, borderwidth=0, width=10) #Fishy
self.choice_title.grid(row=1, column=self.column, columnspan=self.number_boxes, sticky="nsew", padx=1, pady=1)
self.box.append(Entry(self.frame_table,bg='white',borderwidth=0, width=10, justify="center", textvariable=self.numbers[i], fg='grey'))
self.box[i].grid(row=self.row_list,column=self.column+i, sticky='nsew', padx=1, pady=1)
self.box[i].insert(0, "Value %g" % float(i+1))
self.box[i].bind("<Button-1>", lambda event, index=i : self.callback(event, index))
self.total_boxes = self.number_boxes * ( rows - 2 ) #fishy
self.boxes=[] #fishy
self.boxes.append(self.box[i])
tkMessageBox.showinfo("Message", "Please fill in list values.") #fishy
First, you're creating the choice_title labels, but you're only keeping a reference to one of them that you're creating. perhaps you should change that to a list and append to it like you do with the box list.
Second, self.total_boxes doesn't need to be calculated every time through the loop. It can be calculated at the end (I think).
Third, self.boxes=[] should be moved before the loop. What you're doing is equivalent to: self.boxes=[self.box[i]] at every step of the loop. When you're done, you only have one box in your boxes list (the last one).
Fourth, you prompt the user with a message box at every iteration of the loop. Is that really what you want? Or is it an indentation error?
There may be more stuff here that is a little weird, but these give you a place to start. Here's how I think it should look:
self.box=[]
self.boxes=[]
self.choice_title=[]
for i in xrange(self.number_boxes):
self.clicked.append(False)
choice_title = Label(self.frame_table, bg=self.mycolour, borderwidth=0, width=10) #Fishy
choice_title.grid(row=1, column=self.column, columnspan=self.number_boxes, sticky="nsew", padx=1, pady=1)
self.choice_title.append(choice_title)
box=Entry(self.frame_table,bg='white',borderwidth=0, width=10, justify="center", textvariable=self.numbers[i], fg='grey')
self.box.append(box)
box.grid(row=self.row_list,column=self.column+i, sticky='nsew', padx=1, pady=1)
box.insert(0, "Value %g" % float(i+1))
box.bind("<Button-1>", lambda event, index=i : self.callback(event, index))
self.boxes.append(box) #This is still a little weird since self.box and self.boxes are essentially the same information.
self.total_boxes = self.number_boxes * ( rows - 2 ) #fishy
tkMessageBox.showinfo("Message", "Please fill in list values.")
Related
This may be a newbie problem, but I am trying to step through items in a listbox using a for loop and change colour on the items depending on some results. It works in a way that all items change to correct colour at the same time once the function "run_tc_all" is finished.
But I would like it to update the colours directly when the result is available.
Any ideas how I could implement this?
Below are the code related to the issue.
def line_color(item, color):
lb_tc.itemconfig(item, {'bg': color})
lb_tc.itemconfig(item, {'selectbackground': color})
def run_tc_all():
tc_pass = False
i = 0
#lb_tc.selection_set(0)
for tc_id in tc_list:
tc_id_next = tc_id.split(': ')
print(tc_id_next[0])
tc_pass=run_one_tc(str(tc_id_next[0]), i)
if not(tc_pass):
#print('Fail')
line_color(i, 'Red')
break:
else:
print(tc_pass)
tc_pass=True
#print('Pass')
line_color(i, 'Green')
i += 1
time.sleep(1)
lb_tc = Listbox(lb_frame, width=50, height=10, activestyle='none')
lb_tc.grid(row=0, column=0, padx=0, pady=0)
#lb_tc.pack(side=LEFT, expand=1, fill=BOTH)
lb_scrollbar = Scrollbar(lb_frame)
lb_scrollbar.grid(row=0, column=1, padx=0, pady=0, sticky=NS)
#lb_scrollbar.pack(side=RIGHT, fill=Y)
lb_tc.config(yscrollcommand=lb_scrollbar.set)
lb_scrollbar.config(command=lb_tc.yview)
# Add buttons in frame
run_button_frame = LabelFrame(test_run_frame, text="Run commands")
run_button_frame.pack(fill=X, expand=1, padx=20, pady=10)
run_all_btn = Button(run_button_frame, text='Run All', width=10, font=('bold', 10), command=run_tc_all)
run_all_btn.grid(padx=20, pady=10, row=0, column=0)
update_tc_list()
lb_tc.bind('<<ListboxSelect>>',tc_select)
I'm making a DBMS in Tkinter and I want to have a button that will delete the corresponding entry (the entry to the right of it). How would the computer know what button is sending the command or is linked to what entry (or how do I link them)
Take a look at the following code
def edit_db():
for i in root.winfo_children():
i.grid_remove()
back_btn = Button(root, text='<--', command=home)
back_btn.place(height=30, width=30, x=4, y=4)
row_count = 1
for i in cur.execute("SELECT * FROM students").fetchall():
save_btn = Button(root, text='Save', font=("Calbri", 9))
if row_count == 1: save_btn.grid(row=row_count, column=1, pady=(45, 3), padx=(5, 10))
else: save_btn.grid(row=row_count, column=1, pady=3, padx=(5, 10))
del_btn = Button(root, text="X", font=("Calbri", 9), command=del_entry)
if row_count == 1: del_btn.grid(row=row_count, column=0, pady=(45, 3), padx=5)
else: del_btn.grid(row=row_count, column=0, pady=3, padx=(5))
As you can see their are multiple del_btn (and save_btn) and their variable names will no longer correspond, but I want do something like
del_btn = Button(root, text="X", font=("Calbri", 9), command=del_entry(**self/this/me**))
Is there something I can do? Do I have to do this all in a class (I'm not very good a OOP so I don't know what difference it would make)? Or am I missing something and their is way to link each button with the entries in the database.
Here is my picture of my app, if it will help
Here is the solution (includes 3 options):
from tkinter import Tk, Button, Label
label_list = []
def destroy_widget(index):
label_list[index].destroy()
root = Tk()
for i in range(10):
lbl = Label(root, text=f'Label {i}')
lbl.grid(row=i, column=0, sticky='nsew')
label_list.append(lbl)
Button(root, text=f'Destroy {i}',
command=lambda index=i: destroy_widget(index)).grid(row=i, column=1, sticky='nsew')
# option using partial (place import at the top)
# from functools import partial
# Button(root, text=f'Destroy {i}',
# command=lambda: partial(destroy_widget, i).grid(row=i, column=1, sticky='nsew')
# option defining function here (if so then the one at the top isn't needed)
# def destroy_widget(index=i):
# label_list[index].destroy()
# Button(root, text=f'Destroy {i}',
# command=destroy_widget).grid(row=i, column=1, sticky='nsew')
root.mainloop()
As I said, put the widgets in a list, then save index (probably better use a dictionary and save the key so that they can be deleted altogether with their instance, otherwise you can't delete them from the list because that should change other indexes which is gonna mess things up) to the function you are passing to the button so that they "remember" it, I provided 3 different (slightly) ways to do this, one is using anonymous functions, one is using partial, one is using normal functions
I am making a program that lets a user input a flower type, and it will make a new row with row#, name, and days remaining before it dies. At the moment the UI is a bit messy and code could be improved a lot but that's not the point. I would like to know how I would go about making multiple new labels that I can change the days remaining with the click of a button.
Here is my code so far:
It runs ok but only the lastest made row can be changed, this is because every time one is made, the last one can't be edited anymore, and that's what I want to change.
from tkinter import *
#Flower Types
flowers_days = {
"peony": 1,
"rose": 2,
"daffodil": 3,
"dandelion": 4,
"lavender": 5
}
day_change = {}
#Variables
day = 1
days_left = 5
row_Num = 0
name = ""
#Commands
def new_flower():
#make a new line with the new flower
global row_Num
global days_left
global name
global new_row
row_Num += 1
name = str(clicked.get())
print("Test:" + name)
days_left = flowers_days[clicked.get()]
day_change[days_left] = int(row_Num)
new_row = Label(main_Frame, text=str(row_Num)+" "+name+" " + str(days_left))
new_row.pack()
return new_row
def next_day():
global days_left
global name
days_left -= 1
new_row.config(text=str(row_Num)+" "+name+" " + str(days_left))
root = Tk()
new_row = Label()
clicked = StringVar()
clicked.set("No option Selected")
#FLOWER TYPE
flower_Type_Frame = LabelFrame(root, text="New Flowers", padx=5, pady=5)
flower_Type_Frame.grid(row=0, rowspan=4, column=0, columnspan=2, padx=10, pady=10)
flower_Type_Label = Label(flower_Type_Frame, text="Flower Type:")
flower_Type_Label.grid(row=0, column=0, columnspan=2, padx=5, pady=5)
flower_Type_Drop = OptionMenu(flower_Type_Frame, clicked, """
No option Selected
""", "peony", "rose", "daffodil", "dandelion", "lavender")
flower_Type_Drop.grid(row=1, column=0, columnspan=2, pady=5, padx=5)
flower_Type_Submit = Button(flower_Type_Frame, text="Submit", padx=10, pady=10, command=new_flower)
flower_Type_Submit.grid(row=2, column=0, columnspan=2, rowspan=2)
#Empty slot
space_Frame = LabelFrame(root, text="Empty", padx=5, pady=5)
space_Frame.grid(row=0, rowspan=4, column=3, columnspan=2, padx=10, pady=10)
space_Fill = Label(space_Frame, text="Space ").grid(row=0, column=0)
#Day Pass
day_Pass_Frame = LabelFrame(root, text="Day Pass", padx=5, pady=5)
day_Pass_Frame.grid(row=0, rowspan=2, column=6, columnspan=4, padx=10, pady=10)
day_Pass = Button(day_Pass_Frame, text="Next Day", padx=10, pady=10, command=next_day)
day_Pass.grid(row=0, rowspan=2, column=3, columnspan=2)
#Row Delete
#Main stuff
main_Frame = LabelFrame(root, text="Flowers In Stock", padx=5, pady=5)
main_Frame.grid(row=5, column=0, columnspan=7, padx=10, pady=10)
header = Label(main_Frame, text=" Row # / Flower Type / Days Remaining ", padx=5, pady=5)
header.pack(padx=5, pady=5)
root.mainloop()
Once this is sorted I also plan on making it to have a remove row button, so the row numbers need to be able to be changed too if possible.
Thanks for any help.
You're keeping only one 'days_left' information (in a global variable), but you
need to keep one for each flower. So your main data structure needs to be a
list of flowers, and you should remove the 'global' statements for days_left,
name, new_row, as that information needs to be secific to each flower.
Add this to the global scope (just before the new_flower() definition):
# List of [name, days_left, label], one per flower
flowers = []
In the new_flower() function, add the newly-created flower to the list with 'append':
new_row = Label(main_Frame, text=str(row_Num)+" "+name+" " + str(days_left))
new_row.pack()
flowers.append([name, days_left, new_row])
The next_day function should look like this:
def next_day():
for i, f in enumerate(flowers):
# f is a 3-element list [name, days_left, label]
f[1] -= 1
name, days_left, label = f
label.config(text=str(i+1)+" "+name+" " + str(days_left))
The 'enumerate' call iterates over a list, returning both the current index in
the list (in 'i') and the current list item (in 'f'). The index gives you the
row number.
Hello im having python learning project. I want to insert in GUI two numbers, which are defining range for program to generate random number from.
I am really having problems with calling function with press of the button. And constantly getting error ValueError: invalid literal for int() with base 10: '', when trying to convert string from entry in GUI to int and then inserting them into random.randint.
Thx for Help!
from tkinter import *
import random
root = Tk()
root.title("Generator custom random number")
#function that gets number from entry converts string to int and defines target number in stevilo
def function():
string_answer1 = prvo_stevilo.get()
int1 = int(string_answer1)
string_answer2 = drugo_stevilo.get()
int2 = int(string_answer2)
stevilo = random.randint(int1, int2)
#Defining GUI
navodilo = Label(root, text="Choose custom lower and upper number to chose random number from", width=60)
navodilo2 = Label(root, text="From", width=20, borderwidth=3)
navodilo3 = Label(root, text="To", width=20, borderwidth=3)
prvo_stevilo = Entry(root, width=20, borderwidth=3)
drugo_stevilo = Entry(root, width=20, borderwidth=3)
gumb = Button(root, text="Generate number", width=17, height=2, command=function)
praznavrstica = Label(root, text="")
izpis = Label(root, text="Random number is: ", width=20)
izpis_stevila = Label(root, text="" + stevilo)
#Showcase of gui
navodilo.grid(row=0, column=0, columnspan=1)
navodilo2.grid(row=1, column=0, columnspan=1)
navodilo3.grid(row=3, column=0, columnspan=1)
prvo_stevilo.grid(row=2, column=0, columnspan=1)
drugo_stevilo.grid(row=4, column=0, columnspan=1)
praznavrstica.grid(row=5, column=0, columnspan=1)
gumb.grid(row=6, column=0, columnspan=1)
praznavrstica.grid(row=7, column=0, columnspan=1)
izpis.grid(row=8, column=0, columnspan=1)
izpis_stevila.grid(row=9, column=0, columnspan=1)
#Loop
root.mainloop()
I've noticed few problems with your code. I was able to make it running without too many changes, although probably it is not the best way.
First answer to your question: you are getting this error, because you are trying to change string -> '' to int. It happens because function() is running before you click button.
Another problem:
izpis_stevila = Label(root, text="" + stevilo)
variable 'stevilo' simply doesn't exist before calling function(), so delete it from here.
My proposition for changes:
1)
gumb = Button(root, text="Generate number", width=17, height=2,command = lambda: function())
Without lambda your function will run no matter of state of your button.
2)
first = IntVar(root, value=0)
second = IntVar(root, value=1)
prvo_stevilo = Entry(root, width=20, borderwidth=3, textvariable=first)
drugo_stevilo = Entry(root, width=20, borderwidth=3, textvariable=second)
If you run function without any values in your entry you will get error. This change allows you to put default value for your entry widgets.
3)
def function():
if prvo_stevilo.get() == '' or drugo_stevilo.get() =='':
return
else:
string_answer1 = prvo_stevilo.get()
int1 = int(string_answer1)
string_answer2 = drugo_stevilo.get()
int2 = int(string_answer2)
stevilo = random.randint(int1, int2)
izpis_stevila = Label(root, text=str(stevilo))
izpis_stevila.grid(row=9, column=0)
Firstly check if your entry is not empty.
Secondly update label, also remeber about changing int to string here text=str(stevilo).
I have programmed a script which takes random four elements from a table and question to the user using tkinter, random and sqlite3. Currently, I can ask a question. Implement four choices with radiobuttons. I can also test if the answer is correct or not and show the result to the user via toplevel().
Problem is, how can I refresh the question after the continue button clicked?
My whole code is below. I have tried refreshing the random numbers and labels under continue_asking or another def called from continue_asking. But it doesn't work at all.
from tkinter import *
from sqlite3 import *
from random import *
class Question(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.prepare_question()
def prepare_question(self):
self.tumu = {0:['ask1','answer1'], # instead of SQL query
1:['ask2','answer2'],
2:['ask3','answer3'],
3:['ask4','answer4']}
self.create_widgets()
def create_widgets(self):
self.choiceFrame = Frame(self)
self.choiceFrame.grid(row=2, column=0)
self.choiceNum = IntVar()
for i in range(4):
Radiobutton(self.choiceFrame, text=self.tumu[i][1], variable=self.choiceNum, value=i) \
.grid(row=2, column=i, padx=5, pady=5)
self.q_num = randrange(4)
self.q_word = self.tumu[self.q_num][0]
lbl_question = Label(self, text="Which one is the meaning of the word: " + self.q_word, font="Courier 12")
lbl_question.grid(row=0, column=0, columnspan=4, padx=5, pady=5, sticky=W)
txt_question = Text(self, height=1, font="Courier 12", pady=2)
txt_question.tag_configure("myStyle", font="Courier 12 bold")
txt_question.insert("end", "Please choose the answer and ")
txt_question.insert("end", "click okay to see the results.", "myStyle")
txt_question.configure(state="disabled")
txt_question.grid(row=1, column=0, columnspan=4, padx=5, sticky=W)
btn_okay = Button(self, text="Okay", font="12", command=self.a_control)
btn_okay.grid(row=3, column=0, columnspan=2)
def a_control(self):
self.choosenWord = self.q_num
self.frm_answer = Toplevel()
self.frm_answer.title("Result")
self.selectedWord = self.choiceNum.get()
txt_result = Text(self.frm_answer, height=4, width = 40)
if self.choosenWord == self.selectedWord:
txt_result.insert("end", "Congrats! Your answer is correct.\n")
else:
txt_result.insert("end","Your answer is not correct.\n")
txt_result.insert("end", "Correct answer is " + self.tumu[self.q_num][1] + '\n')
txt_result.insert("end", "Please click Continue to continue.\n")
txt_result.insert("end", "Click cancel to quit.")
txt_result.grid(row=0, column=0, columnspan=2, padx = 5, pady=5)
txt_result.configure(state="disabled")
btn_continue = Button(self.frm_answer, text="Continue", command=lambda: self.continue_asking(self.frm_answer))
btn_continue.grid(row=1, column=0, padx=5, pady=5, sticky = W)
btn_quit = Button(self.frm_answer, text="Cancel", command=self.end_asking)
btn_quit.grid(row=1, column=1, padx=5, pady=5, sticky = W)
def continue_asking(self,frm_answer):
frm_answer.destroy()
def end_asking(self):
root.destroy()
root = Tk()
app = Question(root)
root.mainloop()
I have tried adding prepare_question to continue_asking. It keeps asking questions but widgets are not changing. They are just overlapping.
EDIT
So let's restart from scratch, i was totally wrong because no widget was removed and they stacked in the main Frame children list.
You still don't need to write so much code, mostly move some parts.
First, to be able to update the widgets and prepare the new question peacefully, move
self.create_widgets() in the constructor and put the random index self.q_num and self.q_word inside prepare_question, since it belongs to the logic of the question creation.
In create_widgets() you only need to keep some control on the label question, so we add self.lbl_question...
Finally, i suggest to create a new function update_widgets(), but you can put the logic inside continue_asking().
In this function, call prepare_question to update the next question (sql query and random stuff). Since we move the random index, everything is ready to update each widget:
text of the question label
text of radiobuttons. I'm not so proud of the loop to change those, but that'll do the trick. (we keep the values created for the indexes to match the new ones, i'm not very sure about this logic with SQL queries, i follow your first implementation with text=self.tumu[i][1])
If someone can tell how to get the radiobutton value more easily, i'm interested
Here is the whole code:
from tkinter import *
from sqlite3 import *
from random import *
class Question(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.prepare_question()
self.create_widgets()
def prepare_question(self):
self.tumu = {0:['ask1','answer1'], # instead of SQL query
1:['ask2','answer2'],
2:['ask3','answer3'],
3:['ask4','answer4']}
self.q_num = randrange(4)
self.q_word = self.tumu[self.q_num][0]
def create_widgets(self):
self.choiceFrame = Frame(self)
self.choiceFrame.grid(row=2, column=0)
self.choiceNum = IntVar()
for i in range(4):
Radiobutton(self.choiceFrame, text=self.tumu[i][1], variable=self.choiceNum, value=i) \
.grid(row=2, column=i, padx=5, pady=5)
self.lbl_question = Label(self, text="Which one is the meaning of the word: " + self.q_word, font="Courier 12")
self.lbl_question.grid(row=0, column=0, columnspan=4, padx=5, pady=5, sticky=W)
txt_question = Text(self, height=1, font="Courier 12", pady=2)
txt_question.tag_configure("myStyle", font="Courier 12 bold")
txt_question.insert("end", "Please choose the answer and ")
txt_question.insert("end", "click okay to see the results.", "myStyle")
txt_question.configure(state="disabled")
txt_question.grid(row=1, column=0, columnspan=4, padx=5, sticky=W)
btn_okay = Button(self, text="Okay", font="12", command=self.a_control)
btn_okay.grid(row=3, column=0, columnspan=2)
def a_control(self):
self.choosenWord = self.q_num
self.frm_answer = Toplevel()
self.frm_answer.title("Result")
self.selectedWord = self.choiceNum.get()
txt_result = Text(self.frm_answer, height=4, width = 40)
if self.choosenWord == self.selectedWord:
txt_result.insert("end", "Congrats! Your answer is correct.\n")
else:
txt_result.insert("end","Your answer is not correct.\n")
txt_result.insert("end", "Correct answer is " + self.tumu[self.q_num][1] + '\n')
txt_result.insert("end", "Please click Continue to continue.\n")
txt_result.insert("end", "Click cancel to quit.")
txt_result.grid(row=0, column=0, columnspan=2, padx = 5, pady=5)
txt_result.configure(state="disabled")
btn_continue = Button(self.frm_answer, text="Continue", command=self.continue_asking)
btn_continue.grid(row=1, column=0, padx=5, pady=5, sticky = W)
btn_quit = Button(self.frm_answer, text="Cancel", command=self.end_asking)
btn_quit.grid(row=1, column=1, padx=5, pady=5, sticky = W)
def continue_asking(self):
self.frm_answer.destroy()
self.update_widgets()
def update_widgets(self):
self.prepare_question()
# change question text
self.lbl_question.configure(text = "Which one is the meaning of the word: " + self.q_word)
# change Radiobutton
for child in self.choiceFrame.children.values():
index = child.config()['value'][4]
child.configure(text = self.tumu[index][1])
if index == 0: # reset the focus
child.select()
def end_asking(self):
root.destroy()
root = Tk()
app = Question(root)
root.mainloop()
First crap post: (the not to do part)
You don't need to change so much code to fix the present issue, have you already tried the following ?
def continue_asking(self,frm_answer):
frm_answer.destroy()
self.prepare_question()
I won't review the whole code, there is another place for that, but you can also avoid the lambda when you call continue_asking(), since you store the frame in self.frm_answer
btn_continue = Button(self.frm_answer, text="Continue", command=self.continue_asking)
# [...]
def continue_asking(self):
self.frm_answer.destroy()
self.prepare_question()