Tkinter window in python not responding - python

I have a countdown program (code below) that should start counting down from whatever length of time you have put in (you all know how a timer works, right?). But the tkinter window simply freezes when you press start but does not return any error until a windows error message saying that the window is not responding pops up. I have included some print statements as I was trying to debug it and it shows in shell that the program is working as it repeatedly prints c .Does anyone know how to sort out this problem?
import tkinter as tk
import time
def change(direction, stringvar, up_button, down_button):
if direction == 'up':
stringvar.set(stringvar.get()+1)
down_button.config(state = 'normal')
if int(stringvar.get())== 59:
up_button.config(state = 'disabled')
if direction == 'down':
stringvar.set(stringvar.get()-1)
up_button.config(state = 'normal')
if stringvar.get()== 0:
down_button.config(state = 'disabled')
def startTimer():
hourEntry.destroy()
minuteEntry.destroy()
secondEntry.destroy()
print('a')
hourLab = tk.Label(root, textvariable = hourText)
minuteLab = tk.Label(root, textvariable = minuteText)
secondLab = tk.Label(root, textvariable = secondText)
print('b')
hourLab.grid(row = 1, column = 0)
minuteLab.grid(row = 1, column = 1)
secondLab.grid(row = 1, column = 2)
while hourText.get() != 0 or minuteText != 0 or secondText !=0:
print('c')
time.sleep(1)
secondText.set(secondText.get()-1)
if int(secondText.get()) == 0:
secondText.set(59)
if int(minuteText.get()) == 0:
if int(hourText.get()) == 0:
continue
else:
hourText.set(str(int(hourText.get())-1))
else:
minuteText.set(str(int(minuteText.get())-1))
root = tk.Tk()
root.title('Timer')
hourText = tk.IntVar()
minuteText = tk.IntVar()
secondText = tk.IntVar()
hourText.set(1)
minuteText.set(1)
secondText.set(1)
## create buttons and entry boxes using loop
up1 = tk.Button(root, text = '^^^', command = lambda: change('up', hourText, up1, down1))
up2 = tk.Button(root, text = '^^^', command = lambda: change('up', minuteText, up2, down2))
up3 = tk.Button(root, text = '^^^', command = lambda: change('up', secondText, up3, down3))
hourEntry = tk.Entry(root, textvariable = hourText, width = 5)
minuteEntry = tk.Entry(root, textvariable = minuteText, width = 5)
secondEntry = tk.Entry(root, textvariable = secondText, width = 5)
down1 = tk.Button(root, text = '...', command = lambda: change('down', hourText, up1, down1))
down2 = tk.Button(root, text = '...', command = lambda: change('down', minuteText, up2, down2))
down3 = tk.Button(root, text = '...', command = lambda: change('down', secondText, up3, down3))
start = tk.Button(root, text = 'Start', command = startTimer)
up1.grid(row = 0, column = 0, pady = 5, padx = 5)
up2.grid(row = 0, column = 1)
up3.grid(row = 0, column = 2, padx = 5)
hourEntry.grid(row = 1, column = 0, padx = 2, pady = 5)
minuteEntry.grid(row = 1, column = 1, padx = 2, pady = 5)
secondEntry.grid(row = 1, column = 2, padx = 2, pady = 5)
down1.grid(row = 2, column = 0)
down2.grid(row = 2, column = 1)
down3.grid(row = 2, column = 2)
start.grid(row = 3, columnspan = 3, pady = 5)
root.mainloop()

To implement your program :
import tkinter as tk
import time
def change(direction, stringvar, up_button, down_button):
if direction == 'up':
stringvar.set(stringvar.get()+1)
down_button.config(state = 'normal')
if int(stringvar.get())== 59:
up_button.config(state = 'disabled')
if direction == 'down':
stringvar.set(stringvar.get()-1)
up_button.config(state = 'normal')
if stringvar.get()== 0:
down_button.config(state = 'disabled')
def timer():
if hourText.get() != 0 or minuteText != 0 or secondText !=0:
print('c')
time.sleep(1)
secondText.set(secondText.get()-1)
if int(secondText.get()) == 0:
secondText.set(59)
if int(minuteText.get()) == 0:
if int(hourText.get()) == 0:
pass
else:
hourText.set(str(int(hourText.get())-1))
else:
minuteText.set(str(int(minuteText.get())-1))
root.after(1, timer)
def startTimer():
hourEntry.destroy()
minuteEntry.destroy()
secondEntry.destroy()
print('a')
hourLab = tk.Label(root, textvariable = hourText)
minuteLab = tk.Label(root, textvariable = minuteText)
secondLab = tk.Label(root, textvariable = secondText)
print('b')
hourLab.grid(row = 1, column = 0)
minuteLab.grid(row = 1, column = 1)
secondLab.grid(row = 1, column = 2)
root.after(1, timer)
root = tk.Tk()
root.title('Timer')
hourText = tk.IntVar()
minuteText = tk.IntVar()
secondText = tk.IntVar()
hourText.set(1)
minuteText.set(1)
secondText.set(1)
## create buttons and entry boxes using loop
up1 = tk.Button(root, text = '^^^', command = lambda: change('up', hourText, up1, down1))
up2 = tk.Button(root, text = '^^^', command = lambda: change('up', minuteText, up2, down2))
up3 = tk.Button(root, text = '^^^', command = lambda: change('up', secondText, up3, down3))
hourEntry = tk.Entry(root, textvariable = hourText, width = 5)
minuteEntry = tk.Entry(root, textvariable = minuteText, width = 5)
secondEntry = tk.Entry(root, textvariable = secondText, width = 5)
down1 = tk.Button(root, text = '...', command = lambda: change('down', hourText, up1, down1))
down2 = tk.Button(root, text = '...', command = lambda: change('down', minuteText, up2, down2))
down3 = tk.Button(root, text = '...', command = lambda: change('down', secondText, up3, down3))
start = tk.Button(root, text = 'Start', command = startTimer)
up1.grid(row = 0, column = 0, pady = 5, padx = 5)
up2.grid(row = 0, column = 1)
up3.grid(row = 0, column = 2, padx = 5)
hourEntry.grid(row = 1, column = 0, padx = 2, pady = 5)
minuteEntry.grid(row = 1, column = 1, padx = 2, pady = 5)
secondEntry.grid(row = 1, column = 2, padx = 2, pady = 5)
down1.grid(row = 2, column = 0)
down2.grid(row = 2, column = 1)
down3.grid(row = 2, column = 2)
start.grid(row = 3, columnspan = 3, pady = 5)
root.mainloop()
Tkinter uses a method (Tk.after) that allow the user to overcome the tk mainloop. (The window does not wait for the function to finish).
It allows us to update manually all the widgets (canvas, button, label [ect...])
This is a method I always use in my tkinter applications, because I don't trust tk.mainloop () to do what I want.

It is beacause you used a while loop. Your window is waiting for it to end.
You should use intstead a window.after(time, target) :
import tkinter
window = tk.Tk()
def task():
# do things here
window.after(1, task)
window.after(100, task)
window.mainloop()

Related

tkinter throws error using a variable for button name to set state

I want to pass a button name to tkinter as a variable. This method works for Text fields, but not for buttons in my code.
I am building a gui app and I want to have a generic clear function that zaps a text entry field and resets a button from NORMAL to DiSABLED.
There are multiple buttons and fields, hence the desire to make this generic.
For the code I have, the buttons are present with the exception of clear all.
I am setting the variable w_button to the specific name of the (existing) button based on what is passed to the function.
def switch_clear(elem_type):
if elem_type == 'scn':
w_button = 'b_clear_scn'
clear_field = 'scn_file_entry'
print ('scenario')
elif elem_type == 'sol2':
w_button = 'b_clear_sol2'
clear_field = 'sol2_file_entry'
print ('sol2')
elif elem_type == 'mdl':
w_button = 'b_clear_mdlList'
clear_field = 'mdlList_file_entry'
print ('mdl')
elif elem_type == 'all':
print ('clear all TBD')
return()
if w_button["state"] == NORMAL:
clear_field.delete(0, END)
w_button["state"] = DISABLED
return()
Here's what happens:
C:\utils>my_frame3.py
scenario
Traceback (most recent call last):
File "C:\utils\my_frame3.py", line 127, in <module>
b_clear_scn = Button(first_frame, text = "Clear scenario", command = switch_clear('scn'), height = 2, state=DISABLED)
File "C:\utils\my_frame3.py", line 100, in switch_clear
if w_button["state"] == NORMAL:
TypeError: string indices must be integers
C:\utils>
I realize I could duplicate and push the clear operations into the if/elif statements, and I may have to live with that but - is it possible to reference buttons as variables? How can I do this?
Complete code as requested below. The preview is a mess despite using the code widget, but in my file lines are correctly formatted (notepad++). Tx
import os, sys
from tkinter import *
from tkinter import messagebox
from tkinter import filedialog
root2 = Tk()
root2.title('Model Processing')
root2.geometry('{}x{}'.format(512, 400))
# colors
color1 = 'light cyan'
color2 = 'gold'
color3 = 'RosyBrown1'
color4 = 'lavender'
color5 = 'linen'
bg_color = 'azure'
# number of items to process; until >1 OK is disabled; if >1 OK is enabled TBD
l_to_do = [] # items to process; scn, sol2, modelList, installed models
# functions/commands
def callback():
print ('A button was clicked.')
return;
def my_exit():
result = messagebox.askquestion("Cancel Model Processing", "Are you sure?", icon='warning')
if result == 'yes':
root2.quit()
else: # user changed mind
pass
def choose_import_file(str_ftype):
which_field = ''
which_clear_btn = ''
ftype = str_ftype
mdl_opts = {}
if ftype == 'scn':
title_msg = 'Choose a scenario file'
mdl_opts['filetypes'] = [('Supported types', ('.scn')),
('scenario files',('.scn'))]
which_field = scn_file_entry
which_clear_btn = 'b_clear_scn'
elif ftype == 'sol2':
title_msg = 'Choose a SOL2 file'
mdl_opts['filetypes'] = [('Supported types', ('.txt')),
('sol2 files',('.txt'))]
which_field = sol2_file_entry
elif ftype == 'mdllist':
title_msg = 'Choose a ModelList file'
print ('TBD: ModelList file')
file_input = filedialog.askopenfilename(title = title_msg, **mdl_opts)
if file_input == '':
print ('error or cancelled by user')
return
else:
f_inp_file = os.path.basename(file_input)
f_inp_file_base = str(file_input.split('.')[0])
f_inp_file_ext = str.lower(str(file_input.split('.')[1]))
f_inp_d_name = os.path.dirname(file_input)
print('File chosen:', f_inp_file_base)
# populate scenario file field
which_field.insert(INSERT,file_input)
which_clear_btn["state"] = NORMAL
# define appropriate clear button active
# define_clear_btn.configure(state = ACTIVE)
return
def switch_clear(elem_type):
if elem_type == 'scn':
if b_clear_scn["state"] == NORMAL:
scn_file_entry.delete(0, END)
b_clear_scn["state"] = DISABLED
elif elem_type == 'sol2':
f b_clear_sol2["state"] == NORMAL:
clear_field = 'sol2_file_entry'
b_clear_sol2["state"] = DISABLED
elif elem_type == 'mdl':
if b_clear_mdlList["state"] == NORMAL:
clear_field = 'mdlList_file_entry'
b_clear_mdlList["state"] = DISABLED
elif elem_type == 'all':
print ('clear all TBD')
return()
return()
# create all of the main containers
first_frame = Frame(root2, bg=color5, width = 512, height=90, pady=10)
second_frame = Frame(root2, bg=color5, width = 512, height=90, pady=10)
third_frame = Frame(root2, bg=color5, width=512, height=90, pady=10)
fourth_frame = Frame(root2, bg=color5, width = 512, height = 90, pady=10)
# layout all of the main containers
root2.grid_rowconfigure(3, weight=1)
root2.grid_rowconfigure(2, weight=1)
root2.grid_rowconfigure(1, weight=1)
root2.grid_columnconfigure(0, weight=1)
first_frame.grid(row=0, sticky="ew")
second_frame.grid(row=1, sticky="ew")
third_frame.grid(row=2, sticky="ew")
fourth_frame.grid(row = 3, sticky="e")
# create the widgets for the first frame
#scn_label = Label(first_frame, text = 'Scenario file')
scn_file_entry = Entry(first_frame, background=bg_color, width = 50)
b_choose_scn = Button(first_frame, text = "Choose a scenario..", command = lambda: choose_import_file('scn'), height = 2)
b_clear_scn = Button(first_frame, text = "Clear scenario", command = switch_clear('scn'), height = 2, state=DISABLED)
# layout the widgets in the first frame
#scn_label.grid(row = 0, column = 0, padx = (10,50), pady=5)
scn_file_entry.grid(row = 0, column = 1, padx = (10,10))
b_choose_scn.grid(row=0, column=0, padx = (10,10), sticky=W)
b_clear_scn.grid(row=2, column=0, padx = (10,10), sticky=W)
# second frame
# sol2_label = Label(second_frame, text = 'Sol2 file')
sol2_file_entry = Entry(second_frame, background=bg_color, width = 50)
b_choose_sol2 = Button(second_frame, text = "Choose SOL2 file..", command = lambda: choose_import_file('sol2'), height = 2)
b_clear_sol2 = Button(second_frame, text = "Clear SOL2", command = switch_clear('sol2'), height = 2, state=DISABLED)
# layout the widgets in the second frame
# sol2_label.grid(row = 0, column = 0, padx = (10,50), pady=5)
sol2_file_entry.grid(row = 0, column = 1, padx = (10,10), sticky=EW)
b_choose_sol2.grid(row=0, column=0, padx = (10,10), sticky=W)
b_clear_sol2.grid(row=2, column=0, padx = (10,10), sticky=W)
# third frame
# mdlList_label = Label(third_frame, text = 'ModelList.txt file')
mdlList_file_entry = Entry(third_frame, background=bg_color, width = 50)
b_choose_mdlList = Button(third_frame, text = "Choose ModelList.txt file..", command = callback, height = 2)
b_clear_mdlList = Button(third_frame, text = "Clear ModelList", command = callback, height = 2, state=DISABLED)
# layout the widgets in the third frame
#mdlList_label.grid(row = 0, column = 0, padx = (10,10), pady=5, sticky = 'ns')
mdlList_file_entry.grid(row = 0, column = 1, padx = (10,10), sticky=EW)
b_choose_mdlList.grid(row=0, column=0, padx = (10,10), sticky=W)
b_clear_mdlList.grid(row=2, column=0, padx = (10,10), sticky=W)
#####################################################################
# create bottom widgets
#####################################################################
clear_all = Button(fourth_frame, text='Clear All', padx = '5', command = callback, height = 2, state=DISABLED)
ok_btn = Button(fourth_frame, text='OK', padx = '5', command = callback, height = 2, state=DISABLED)
cancel_btn = Button(fourth_frame, text='Cancel', height = 2, padx = '12', command = my_exit)
#####################################################################
# layout the bottom widgets
#####################################################################
clear_all.grid(row = 0, column = 2, sticky = 'e')
ok_btn.grid(row = 0, column = 3, sticky = 'e')
cancel_btn.grid(row = 0, column = 4, sticky = 'e')
# commands/bindings
root2.mainloop()
I believe this is what you are trying to do. The below is fully commented with explanations. switch_clear becomes entirely unnecessary with this method. The buttons directly clear their corresponding entry in their command, and Entry validation takes care of the corresponding button state.
Note: I wrote all of this before you posted your full code
import tkinter as tk
root = tk.Tk()
root.geometry('400x400')
#toggle the state of buttons based on entry text length
def toggle_button(name, text):
global btn_switch
btn_switch[name]['state'] = 'normal' if len(text) else 'disabled'
return True
#to hold the buttons so they are easy to position
#just for this example
buttons = tk.Frame(root)
buttons.pack(side='top', anchor='nw')
#create a tcl wrapper for the validate command
vcmd = tk.Widget.register(root, toggle_button)
#mock-up of your entries ~ validate on key press. send widget name and full text to vcmd
scn_file_entry = tk.Entry(root, width=20)
scn_file_entry.configure(validate="key", validatecommand=(vcmd, '%W', '%P'))
scn_file_entry.pack(side='left', anchor='nw')
sol2_file_entry = tk.Entry(root, width=20)
sol2_file_entry.configure(validate="key", validatecommand=(vcmd, '%W', '%P'))
sol2_file_entry.pack(side='left', anchor='nw')
mdlList_file_entry = tk.Entry(root, width=20)
mdlList_file_entry.configure(validate="key", validatecommand=(vcmd, '%W', '%P'))
mdlList_file_entry.pack(side='left', anchor='nw')
#mock-up of your buttons ~ delete the entry text in a lambda and let entry validation handle the button state
b_clear_scn = tk.Button(buttons, text="scn", state='disabled')
b_clear_scn.configure(command=lambda: scn_file_entry.delete(0, 'end'))
b_clear_scn.pack(side='left', anchor='nw')
b_clear_sol2 = tk.Button(buttons, text="sol2", state='disabled')
b_clear_sol2.configure(command=lambda: sol2_file_entry.delete(0, 'end'))
b_clear_sol2.pack(side='left', anchor='nw')
b_clear_mdlList = tk.Button(buttons, text="mdl", state='disabled')
b_clear_mdlList.configure(command=lambda: mdlList_file_entry.delete(0, 'end'))
b_clear_mdlList.pack(side='left', anchor='nw')
#create a dictionary of 'widget name':corresponding button, for toggle_button to reference
btn_switch = {
f'{scn_file_entry}':b_clear_scn,
f'{sol2_file_entry}':b_clear_sol2,
f'{mdlList_file_entry}':b_clear_mdlList,
}
root.mainloop()

Why does the entry widget not work in this case i put it in a frame, tkinter-python

So this is a basic clock and alarm that i am creating, and in the process i want the user to type in what hour and minute they want to set for the alarm. But the entry widget here is not responding.
import time
import tkinter as tk
current_date, current_time = 0, 0
def current_info(timeinfo): #function to get the current time and date
global current_date, current_time
# current time
current_time = time.strftime('%H:%M:%S')
current_date = time.strftime(r'%m/%d/%Y')
clock.after(200, timeinfo)
#Initialise the window
clock = tk.Tk()
clock.title('Easy CLock')
clock.configure(bg='#121212')
clock.columnconfigure(0, weight = 1)
clock.columnconfigure(1, weight = 1)
clock.columnconfigure(2, weight = 1)
clock.columnconfigure(3, weight = 1)
border_effects = {
"flat": tk.FLAT,
"sunken": tk.SUNKEN,
"raised": tk.RAISED,
"groove": tk.GROOVE,
"ridge": tk.RIDGE,
}
#Logo will be under the main parent
logo = tk.PhotoImage(file = r'C:\Users\User\VSC\Alarm\Logo1.png')
logo_size = logo.subsample(5)
#Time and Date function
def time_date():
current_info(time_date)
#Displays the time
c_time = tk.Label(f_time, text = current_time, fg='white', bg='#121212', font=('Verdana', 30))
c_date = tk.Label(f_time, text = current_date, font=('Verdana', 10), fg='white', bg='#121212')
c_time.grid(column=0, row=0)
c_date.grid(column=0, row=1)
#alarm button command
def alarm_func():
current_info(alarm_func)
c_time = tk.Label(f_alarm, text = current_time, fg='white', bg='#121212', font=('Verdana', 10))
c_date = tk.Label(f_alarm, text = current_date, font=('Verdana', 10), fg='white', bg='#121212')
def pressed_enter(): #Command for the enter button
set_label = tk.Label(f_alarm, text = f'Alarm has been set for {time_set}', fg ='white', bg = '#121212', borderwidth = 1, relief = border_effects['sunken'])
set_label.grid(column = 4, row = 0, sticky = 'W')
# Set the time and date for the alarm
set_time = tk.StringVar()
alarm_entry = tk.Entry(clock, textvariable = set_time)
set_time.set('H : M')
time_set = alarm_entry.get()
#label and entry to set alarm / Enter Button
c_label = tk.Label(f_alarm, text = 'Set Alarm: ', font = ('Verdana', 10), fg= 'white', bg ='#121212' )
alarm_enter = tk.Button(f_alarm, text = 'Enter', font = ('Verdana', 7), width = 5, command = pressed_enter)
#Pack the widgets
c_time.grid(row = 0, column = 0)
c_date.grid(column = 1 , row = 0)
alarm_enter.grid(row = 2, column = 3)
c_label.grid(row = 2, sticky = 'W')
alarm_entry.grid(row = 2, column = 1)
#configure the empty columns
f_alarm.columnconfigure(2, minsize = 10)
def recall_frame(event):
if event == f_alarm:
event.grid_forget()
f_time.grid(column=0, row =1, columnspan = 4, sticky = 'N')
elif event == f_time:
event.grid_forget()
f_alarm.grid(column=0, row=1, columnspan = 4, sticky = 'W')
def back_func():
pass
#Creating Frames
f_time = tk.Frame(clock) #Clock Button
f_alarm = tk.Frame(clock) #Alarm Buttton
#configure the frames
f_time.configure(bg = '#121212')
f_alarm.configure(bg = '#121212')
#Setting label in the frame
f_lbl = tk.Label(clock, text= ' Simplistic Clock', image = logo_size, font=('Verdana', 30), fg='white', bg='#121212', compound = tk.LEFT, padx = 35)
time_but = tk.Button(clock, text='Clock', command= lambda :[time_date(), recall_frame(f_alarm)], bg='#f39c12', relief = border_effects['ridge'], pady = 7)
alarm_but = tk.Button(clock, text = 'Alarm', command = lambda :[alarm_func(), recall_frame(f_time)], bg='#f39c12', relief = border_effects['ridge'], pady = 7)
quit_but = tk.Button(clock, text='Exit', command = clock.quit, bg='#f39c12', relief = border_effects['ridge'], pady = 7)
back_but = tk.Button(clock, text = 'Back ', command = back_func, bg='#f39c12', relief = border_effects['ridge'], pady = 7)
f_lbl.config(borderwidth = 4, relief = border_effects['sunken'])
#Putting it on the frames
f_lbl.grid(column = 0, row = 0, columnspan = 5, sticky = 'EW')
time_but.grid(column = 0, row = 3, sticky = 'EW')
alarm_but.grid(column = 1, row = 3, sticky = 'EW')
quit_but.grid(column = 3, row = 3, sticky = 'EW')
back_but.grid(column = 2, row = 3, sticky = 'EW')
clock.mainloop()
i tried testing an entry widget outside the frame and the entry widget was able to work, is it because the frame f_alarm is not looping constantly in the background?
When someone clicks on your button which activates the pressed_enter() function, it will call that function again every time which will set the time to H:M and it will get that value as the set_time.get() is called immediately after.
You're also creating a new Entry every time the button is being clicked because you put alarm_entry = tk.Entry(clock, textvariable=set_time)
in there as well. You should only put the set_time.get inside of that button so that it gets the value that is currently filled in into the Entry. The other things like
set_time = tk.StringVar()
alarm_entry = tk.Entry(clock, textvariable=set_time)
set_time.set('H : M')
Should be put outside of that function so they don't get called every time someone clicks on the button.

if master._last_child_ids is None: AttributeError: 'PhotoImage' object has no attribute '_last_child_ids'

from tkinter import *
from PIL import ImageTk, Image
root = Tk()
root.title("Images")
root.iconbitmap(r"C:\Users\DellABD\Downloads\lolol.ico")
my_img1 = ImageTk.PhotoImage(Image.open(r"E:\imagespy\illusion.jpg"))
my_img2 = ImageTk.PhotoImage(Image.open(r"E:\imagespy\scan0053.jpg"))
my_img3 = ImageTk.PhotoImage(Image.open(r"E:\imagespy\scan0054.jpg"))
my_img4 = ImageTk.PhotoImage(Image.open(r"E:\imagespy\scan0055.jpg"))
my_img5 = ImageTk.PhotoImage(Image.open(r"E:\imagespy\scan0056.jpg"))
my_img_list = [my_img1, my_img2, my_img3, my_img4, my_img5]
my_label = Label(image = my_img1)
my_label.grid(row = 0, column = 0, columnspan = 3)
def forward(image_number):
global my_label
global back
global forward
my_label.grid_forget()
my_label = Label(my_img_list[image_number - 1])
my_label.grid(row = 0, column = 0, columnspan = 3)
def back():
global my_label
global back
global forward
global my_label
global back
global forward
my_label.grid_forget()
my_label = Label(my_img_list[image_number - 1])
button_forward = Button(root, text = ">>>", command = lambda: image_number + 1)
button_back = Button(root, text = "<<<", command = lambda: image_number - 1)
if button_back == 1:
button_back = Buuton(rrot, text = "<<<", state = DISABLED)
button_back.grid(row = 1, column = 0)
button_forward.grid(row = 1, column = 2)
my_label.grid(row = 0, column = 0, columnspan = 3)
button_back = Button(root, text = "<<<", padx = 20, pady = 20, command = back)
button_forward = Button(root, text = ">>>", padx = 20, pady = 20, command = lambda: forward(2))
button_quit = Button(root, text = "Exit", padx = 20, pady = 20, command = root.quit)
button_back.grid(row = 1, column = 0)
button_forward.grid(row = 1, column = 2)
button_quit.grid(row = 1, column = 1)
root.mainloop()
when I run the programme and press the Forward button it shows me an error. I wanted to move on next image by pressing forward and when I press the first image disappears but next image dont show up and shows error.
if master._last_child_ids is None:
AttributeError: 'PhotoImage' object has no attribute '_last_child_ids'
The problem is this code:
Label(my_img_list[image_number - 1])
You are trying to use an image as the parent/master of a label. You need to use this instead:
Label(image=my_img_list[image_number - 1])

Python 3.6 tkinter says GROOVE is not defined

The below program was working fine few minutes back. I made a change,ran the code, made a small mistake, Spyder crashed and now it either cannot find Frame or Groove or something else. At the moment it says GROOVE not defined.
Tried writing it in lower case and with quotes. When I do with quotes it says: TclError: bad relief "Groove": must be flat, groove, raised, ridge, solid, or sunken. When I do lower or upper case without quotes says groove not defined.
from RiskFactorConversion import *
from tkinter import ttk, StringVar, Frame, Label, Tk, Entry
mainwindow = Tk()
mainwindow.title("Risk Factor Conversion")
datatype = StringVar()
dataconvention = StringVar()
mdlname = StringVar()
instancevalue = StringVar()
axisvalue = StringVar()
def g():
datatype = e1.get()
dataconvention = e2.get()
mdlname = e3.get()
instancevalue = e4.get()
r1 = rates.srtqualifier(mdlname,datatype,dataconvention,instancevalue)
l5["text"] =r1.makequalifier()
def f():
datatype = e5.get()
dataconvention = e6.get()
axisvalue = e8.get()
fx1 = fx.felixfxvol(datatype,dataconvention,axisvalue)
l11["text"] =fx1.fxvol()
def h():
datatype = en1.get()
dataconvention = en2.get()
fx2 = fx.murexfx(datatype,dataconvention)
la4["text"] =fx2.makequalifier()
#########Felix Frame####################################
frame1 = Frame(bg="white", colormap="new", padx = 10, relief=GROOVE, borderwidth=2)
frame1.grid(row = 0, column = 0)
l0 = Label(frame1, text= "FELIX Rates", pady =5, font = ('Georgia',14,'bold'), bg="white")
l0.grid(row = 0, column = 0,sticky= W )
l1 = Label(frame1, text= "Please provide Data Type:",bg="white", justify = "right",pady =5 )
l1.grid(row = 1, column = 0, sticky= E )
e1 = Entry(frame1,bd = 2, width =50, textvariable = datatype )
e1.grid(row = 1, column = 1)
e1.focus_set()
l2 = Label(frame1,bg="white", text= "Please provide Data Convention:",justify = "right", pady = 5)
l2.grid(row = 2, column = 0,sticky= E)
e2 = Entry(frame1,bd = 2, width =50, textvariable = dataconvention )
e2.grid(row = 2, column = 1)
l3 = Label(frame1,bg="white", text= "Please provide Model Type:", justify = "right",pady = 5)
l3.grid(row = 3, column = 0,sticky= E)
e3 = ttk.Combobox(frame1,width =45, textvariable = mdlname, state='readonly')
e3['values'] = ('IR_SABR','FX_LN','IR_LGM','IR_LMM','IR_SABR_FX_LN_GC','IR_SABR_GC','INFLATION_SABR')
e3.grid(row = 3, column = 1)
l4 = Label(frame1,bg="white", text= "Please provide Instance Name:", justify = "right",pady = 5)
l4.grid(row = 4, column = 0,sticky= E)
e4 = Entry(frame1,bd = 2, width =50, textvariable = instancevalue )
e4.grid(row = 4, column = 1)
bfelix = Button(frame1, text = "Press to get Qualifier Value", pady = 10, command = g)
bfelix.grid(row = 5, column = 0)
l5 = Label(frame1,bg="white", text= "" , justify = "right",pady = 5)
l5.grid(row = 5, column = 1)
################################################################
############FELIX FX############################################
frame2 = Frame(bg="white", colormap="new", padx = 10, relief=GROOVE, borderwidth=2)
frame2.grid(row = 0, column = 1)
l6 = Label(frame2, text= "FELIX FX", pady =5, font = ('Georgia',14,'bold'), bg="white")
l6.grid(row = 0, column = 0,sticky= W )
l7 = Label(frame2, text= "Please provide Data Type:",bg="white", justify = "right",pady =5 )
l7.grid(row = 1, column = 0, sticky= E )
e5 = Entry(frame2,bd = 2, width =50, textvariable = datatype)
e5.grid(row = 1, column = 1)
e5.focus_set()
l8 = Label(frame2,bg="white", text= "Please provide Data Convention:",justify = "right", pady = 5)
l8.grid(row = 2, column = 0,sticky= E)
e6 = Entry(frame2,bd = 2, width =50, textvariable = dataconvention )
e6.grid(row = 2, column = 1)
l10 = Label(frame2,bg="white", text= "Please provide axis 2 value:", justify = "right",pady = 5)
l10.grid(row = 3, column = 0,sticky= E)
e8 = Entry(frame2,bd = 2, width =50, textvariable = axisvalue )
e8.grid(row = 3, column = 1)
bfelixfx = Button(frame2, text = "Press to get Qualifier Value", pady = 10, command = f)
bfelixfx.grid(row = 4, column = 0)
l11 = Label(frame2,bg="white", text= "" , justify = "right",pady = 5)
l11.grid(row = 4, column = 1)
#####################################################################
############MUREX FX############################################
frame3 = Frame(bg="white", colormap="new", padx = 10, relief=GROOVE, borderwidth=2)
frame3.grid(row = 1, column = 1)
la = Label(frame3, text= "Murex FX", pady =5, font = ('Georgia',14,'bold'), bg="white")
la.grid(row = 0, column = 0,sticky= W )
la1 = Label(frame3, text= "Please provide Risk Factor Type:",bg="white", justify = "right",pady =5 )
la1.grid(row = 1, column = 0, sticky= E )
en1 = ttk.Combobox(frame3, width =45, textvariable = mdlname, state='readonly')
en1['values'] =('FX ATM VOLATILITY','FX BUTTERFLY 10D','FX BUTTERFLY 25D','FX RISK REVERSAL 10D','FX RISK REVERSAL 25D')
en1.grid(row = 1, column = 1)
en1.focus_set()
la2 = Label(frame3,bg="white", text= "Please provide Currency Pair:",justify = "right", pady = 5)
la2.grid(row = 2, column = 0,sticky= E)
en2 = Entry(frame3,bd = 2, width =50, textvariable = dataconvention )
en2.grid(row = 2, column = 1)
bmurexfx = Button(frame3, text = "Press to get Qualifier Value", pady = 10, command = h)
bmurexfx.grid(row = 4, column = 0)
la4 = Label(frame3,bg="white", text= "" , justify = "right",pady = 5)
la4.grid(row = 4, column = 1)
#####################################################################
mainwindow.mainloop()
Groove is a constant defined in Tkinter and since you are only importing specfic functions from Tkinter that doesn't include Groove, you need to add GROOVE to it or add
import tkinter as tk
and then set relief=tk.GROOVE

global variable issues with tkinter python

I am trying to create a simple interface to access the name array with first, last, previous and next functionality. But the global variable I am using as a position tracker is not working. I have already referred to various question. Would really appreciate the help. Here is the code.
from tkinter import Tk, Label, Entry, Button, StringVar, IntVar
window = Tk()
name_array = [('a1','a2','a3'), ('b1','b2','b3'), ('c1','c2','c3'),('d1','d2','d3')]
global position_track
position_track = IntVar()
first_name = StringVar()
last_name = StringVar()
email = StringVar()
def return_value(pos):
first_name.set(name_array[pos][0])
last_name.set(name_array[pos][1])
email.set(name_array[pos][2])
def update_value(pos):
name_array[pos] = (first_name.get(), last_name.get(), email.get())
def first_value():
global position_track
return_value(0)
postion_track.set(0)
def last_value():
global position_track
return_value(-1)
postion_track.set(-1)
def next_value():
global position_track
if position_track.get() == len(name_array):
position_track.set(1)
temp = postion_track.get()
return_value(temp + 1)
postion_track.set(temp + 1)
def prev_value():
global position_track
if position_track.get() == -1:
position_track.set(len(name_array - 1))
temp = postion_track.get()
return_value(temp - 1)
postion_track.set(temp - 1)
label_first_name = Label(window, text = 'First Name:', justify = 'right', padx = 5)
entry_first_name = Entry(window, textvariable = first_name)
label_last_name = Label(window, text = 'Last Name:', justify = 'right', padx = 5)
entry_last_name = Entry(window, textvariable = last_name)
label_email = Label(window, text = 'Email Address:', justify = 'right', padx = 5)
entry_email = Entry(window, textvariable = email)
button_first = Button(window, text = 'First', command = first_value)
button_last = Button(window, text = 'Last', command = last_value)
button_prev = Button(window, text = 'Prev', command = prev_value)
button_next = Button(window, text = 'Next', command = next_value)
button_quit = Button(window, text = 'Quit')
button_quit.configure(command=window.destroy)
labels = [label_first_name, label_last_name, label_email]
entries = [entry_first_name, entry_last_name, entry_email]
buttons = [button_first, button_last, button_prev, button_next, button_last, button_quit]
for i in range(3):
labels[i].grid(row = i, column = 0, sticky = 'W')
entries[i].grid(row = i, column = 1, columnspan = 6)
for j in range(6):
buttons[j].grid(row = 3, column = j, sticky = 'E')
window.mainloop()
Too many typos. Plus, you don't need to declare a global in the outermost program space, just in the function defs. Corrected working code ->
from tkinter import Tk, Label, Entry, Button, StringVar, IntVar
window = Tk()
name_array = [('a1','a2','a3'), ('b1','b2','b3'), ('c1','c2','c3'),('d1','d2','d3')]
position_track = IntVar()
first_name = StringVar()
last_name = StringVar()
email = StringVar()
def return_value(pos):
first_name.set(name_array[pos][0])
last_name.set(name_array[pos][1])
email.set(name_array[pos][2])
def update_value(pos):
name_array[pos] = (first_name.get(), last_name.get(), email.get())
def first_value():
global position_track
return_value(0)
position_track.set(0)
def last_value():
global position_track
return_value(-1)
position_track.set(-1)
def next_value():
global position_track
if position_track.get() == len(name_array):
position_track.set(1)
temp = position_track.get()
return_value(temp + 1)
position_track.set(temp + 1)
def prev_value():
global position_track
if position_track.get() == -1:
position_track.set(len(name_array) - 1)
temp = position_track.get()
return_value(temp - 1)
position_track.set(temp - 1)
label_first_name = Label(window, text = 'First Name:', justify = 'right', padx = 5)
entry_first_name = Entry(window, textvariable = first_name)
label_last_name = Label(window, text = 'Last Name:', justify = 'right', padx = 5)
entry_last_name = Entry(window, textvariable = last_name)
label_email = Label(window, text = 'Email Address:', justify = 'right', padx = 5)
entry_email = Entry(window, textvariable = email)
button_first = Button(window, text = 'First', command = first_value)
button_last = Button(window, text = 'Last', command = last_value)
button_prev = Button(window, text = 'Prev', command = prev_value)
button_next = Button(window, text = 'Next', command = next_value)
button_quit = Button(window, text = 'Quit')
button_quit.configure(command=window.destroy)
labels = [label_first_name, label_last_name, label_email]
entries = [entry_first_name, entry_last_name, entry_email]
buttons = [button_first, button_last, button_prev, button_next, button_last, button_quit]
for i in range(3):
labels[i].grid(row = i, column = 0, sticky = 'W')
entries[i].grid(row = i, column = 1, columnspan = 6)
for j in range(6):
buttons[j].grid(row = 3, column = j, sticky = 'E')
window.mainloop()

Categories