winfo_exists() does not see an existing Label - python

I can't get Label.winfo_exists() to see a Label printed earlier.
I have a window with multiple buttons that all pass data to this routine. On the first pass, this prints Labels on "line A." if another button is pressed (including the first one) this routine runs again, printing the same set of labels on line "A" again, while printing the data from the second button press on line "B." I am trying to delete all previously laid labels before putting another layer down. I would actually have up to line "L" as a maximum.
So I run the routine. On the first pass, I get a NameError at the start (because that label is not there, yet). After I create the label, I do the test again and the winfo_exists() shows properly.
On the second pass, (I have tried the same and different buttons), the first check shows 0 from a NameError again, when it should show 1. After I print the label the second time, it shows 1 again and if I try to delete from another routine, it deletes the 2nd one on top, but not the original label.
This window has lots of other data that I can't just delete the whole window.
rosterloops = len(final_roster)
print(f'Roster Loops {rosterloops}') # Prints 1 on 1st run, 2 on 2nd
ex_test = IntVar()
if rosterloops >=1:
try:
ex_test = roster_unit.winfo_exists()
except NameError:
print('NameError') # Prints on both runs
ex_test = 0
except KeyError:
print('Key Error')
ex_test = 0
print(f'BV Test 1 is {ex_test}') # Prints "0" on both runs
if ex_test == 1:
print('Got here!') # Never gets here
roster_del.destroy()
data = final_roster.get(1)
data_split = data.split("#")
org = data_split[0]
name = data_split[1]
model = data_split[2]
gunnery = int(data_split[7])
pilot = int(data_split[8])
num1 = int(bva)
num2 = float(gpmatrix[gunnery][pilot])
roster_adj_bv = round((num1 * num2))
bv_array[1] = roster_adj_bv
# Name/Model
roster_unit = Label(root, text=f' {name} {model}')
roster_unit.place(x=rosterx + 40, y=rostery, width=230)
# Gunnery/Pilot
roster_gun = Label(root, text=f'{gunnery} /')
roster_gun.place(x=rosterx + 270, y=rostery)
roster_gplus = Button(root, image=pimg, width=20, height=15,
command=lambda rl=1, x=rosterx, y=rostery: upg(root, rl, final_roster,
bv_array, x, y))
try:
ex_test = roster_unit.winfo_exists()
except NameError:
print('NameError')
ex_test = 0
except KeyError:
print('Key Error')
ex_test = 0
print(f'BV Test 1a is {ex_test}') # Prints "1" on both runs
I should get the first winfo_exists() run to show a 0 on the 1st pass, then 1 on the second so the program can get to the .destroy() functions under the "Got here!" print.

Related

Validation python, Using GUI

I am attempting to validate the text box field so that the user can only insert integers, although i have used a while loop to attempt and cannot figure it out I keep getting errors. Please help.
from tkinter import *
import tkinter as tk
from tkinter.tix import *
# setup the UI
root = Tk()
# Give the UI a title
root.title("Distance converter Miles to Kilometers")
# set window geometry
root.geometry("480x130")
# setup the buttons
valRadio = tk.IntVar()
myText=tk.StringVar()
e1 =tk.IntVar()
def calculate(*arg):
while True:
try:
if valRadio.get() == 1:
# get the miles ( Calculation )
res = round(float(e1.get()) / 1.6093,2)
# set the result text
myText.set( "Your input converts to " + str(res) + " Miles")
break
if valRadio.get() == 2:
# get the kilometeres
res = round(float(e1.get()) * 1.6093,2)
# set the result text
myText.set( "Your input converts to " + str(res) + " Kilometers")
break
if ValueError:
myText.set ("Please check selections, only Integers are allowed")
break
else:
# print error message
res = round(float(e1.get()) / 1.6093,2)
myText.set ("Please check selections, a field cannot be empty")
break
except ValueError:
myText.set ("Please check selections, a field cannot be empty")
break
# Set the label for Instructions and how to use the calculator
instructions = Label(root, text="""Hover me:""")
instructions.grid(row=0, column=1)
# set the label to determine the distance field
conversion = tk.Label( text=" Value to be converted :" )
conversion.grid(row=1,column = 0,)
# set the entry box to enable the user to input their distance
tk.Entry(textvariable = e1).grid(row=1, column=1)
#set the label to determine the result of the program and output the users results below it
tk.Label(text = "Result:").grid(row=5,column = 0)
result = tk.Label(text="(result)", textvariable=myText)
result.grid(row=5,column=1)
# the radio button control for Miles
r1 = tk.Radiobutton(text="Miles",
variable=valRadio, value=1).grid(row=3, column=0)
# the radio button control for Kilometers
r2 = tk.Radiobutton(text="Kilometers",
variable=valRadio, value=2).grid(row=3, column=2)
# enable a calculate button and decide what it will do as well as wher on the grid it belongs
calculate_button = tk.Button(text="Calculate \n (Enter)", command=calculate)
calculate_button.grid(row=6, column=2)
# deploy the UI
root.mainloop()
I have attempted to use the While loop inside the code although I can only get it to where if the user inputs text and doesn't select a radio button the error will display but I would like to have it where the text box in general will not allow anything but integers and if it receives string print the error as it does if the radio buttons aren't selected.
define validation type and validatecommand. validate = key makes with every key input it runs validatecommand. It only types if that function returns true which is 'validate' function in this case.
vcmd = (root.register(validate), '%P')
tk.Entry(textvariable = e1,validate="key", validatecommand=vcmd).grid(row=1, column=1)
this is the validation function
def validate(input):
if not input:
return True
elif re.fullmatch(r'[0-9]*',input):
return True
myText.set("Please check selections, only Integers are allowed")
return False
it return true only when its full of numbers([0-9]* is an regular expression which defines all numbers) or empty. If it contains any letter it return False any it denied this way.
Also do not forget to imports
import re

Tkinter/Python hanging on user response if response is the last option in a while or if loop

The following code works for requesting input from a user through the Tkinter GUI and turning that input into a usable variable in the main script. However, any value that I put as the last in a list in the if statement (here "4") will hang and crash the program upon enter. This was also the case for "n" in a yes/no scenario. It also happens if I replace the if statement with a while not in [values] - the final value will crash the program. Is this just a quirk of Tkinter or is there something that I am missing?
import tkinter as tk
from tkinter import *
# get choice back from user
global result
badinput = True
while badinput == True:
boxwidth = 1
result = getinput(boxwidth).strip().lower()
if result in ['1', '2', '3', '4']:
badinput = False
# iterate through play options
if result == '1':
# Do Something
elif result =='2':
# Do Something
elif result =='3':
# Do Something
else:
# Do Something
def getinput(boxwidth):
# declaring string variable for storing user input
answer_var = tk.StringVar()
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
return
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(answer_var)
answer_entry.destroy()
return answer_var.get()
In case anyone is following this question, I did end up solving my problem with a simple if statement within the callback. I can feed a dynamic "choicelist" of acceptable responses into the callback upon user return. If the answer is validated, the gate_var triggers the wait function and sends the program and user response back into the program.
'''
def getinput(boxwidth, choicelist):
# declaring string variable for storing user input
answer_var = tk.StringVar()
gate_var = tk.StringVar()
dumplist = []
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
if choicelist == None:
clearscreen(dumplist)
gate_var.set(answer_entry.get())
return
if answer_var.get() in choicelist:
# passes a validated entry on to gate variable
clearscreen(dumplist)
gate_var.set(answer_entry.get())
else:
# return to entry function and waits if invalid entry
clearscreen(dumplist)
ErrorLabel = tk.Label(root, text = "That is not a valid response.")
ErrorLabel.pack()
ErrorLabel.config(font = ('verdana', 18), bg ='#BE9CCA')
dumplist.append(ErrorLabel)
return
global topentry
if topentry == True:
answer_entry = tk.Entry(top, width = boxwidth, borderwidth = 5)
else:
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(gate_var)
answer_entry.destroy()
return answer_var.get()
'''

Command function for button "resets"

So in my tkinter python program I am calling on a command when a button is clicked. When that happens it runs a function but in the function I have it set a label to something on the first time the button is clicked and after that it should only update the said label. Basically after the attempt it changes the attempt to 1 ensuring the if statement will see that and not allow it to pass. However it keeps resetting and I don't know how to stop it. When you click the button no matter first or third the button resets and proof of that occurs because the h gets printed. It's as if the function restarts but it shouldn't since it's a loop for the GUI.
def fight(): #Sees which one is stronger if user is stronger he gets win if no he gets loss also displays enemy stats and removes used characters after round is finished
try:
attempt=0
namel = ""
namer=""
left = lbox.curselection()[0]
right = rbox.curselection()[0]
totalleft = 0
totalright = 0
if left == 0:
namel = "Rash"
totalleft = Rash.total
elif left==1:
namel = "Untss"
totalleft = Untss.total
elif left==2:
namel = "Illora"
totalleft = 60+35+80
if right == 0:
namer = "Zys"
totalright = Zys.total
elif right==1:
namer = "Eentha"
totalright = Eentha.total
elif right==2:
namer = "Dant"
totalright = Dant.total
lbox.delete(lbox.curselection()[0])
rbox.delete(rbox.curselection()[0])
print(namel)
print(namer)
if attempt == 0:
wins.set("Wins")
loss.set("Loss")
print("h")
attempt=1
if (totalleft>totalright):
wins.set(wins.get()+"\n"+namel)
loss.set(loss.get()+"\n"+namer)
else:
wins.set(wins.get()+"\n"+namer)
loss.set(loss.get()+"\n"+namel)
except IndexError:
pass
Also for those of you who saw my previous question I still need help with that I just also want to fix this bug too.
At beginning of function fight you set attempt = 0 so you reset it.
Besides attempt is local variable. It is created when you execute function fight and it is deleted when you leave function fight. You have to use global variable (or global IntVar)
attempt = 0
def fight():
global attempt
BTW: of you use only values 0/1 in attempt then you can use True/False.
attempt = False
def fight():
global attempt
...
if not attempt:
attempt = True

Assign OptionMenu Variable in Python

I am working on a menu system that allows user to select date and location to access a specific file. I know it will be a lot of hard coding for each specific file. I want to use an OptionMenu system. I am getting values printed, but how can i define these values and pass them through a function to open that specific file. I am thinking a long if else statement. (IE if Monday && a then pass this call function).
Here is my code
#mainmenu
class MyOptionMenu(OptionMenu):
def __init__(self, master, status, *options):
self.var = StringVar(master)
self.var.set(status)
OptionMenu.__init__(self, master, self.var, *options)
self.config(font=('calibri',(20)),bg='white',width=20)
self['menu'].config(font=('calibri',(10)),bg='white')
root = Tk()
#attemtping to assign numerical values
Monday = 1
Tuesday = 2
Wednesday = 3
Thursday = 4
Friday = 5
mymenu1 = MyOptionMenu(root, 'Select day', 'Monday','Tuesday','Wednesday', 'Thursday', 'Friday')
mymenu2 = MyOptionMenu(root, 'Select Location', 'd','e','f')
#menus come up fine and values correctly printed
def ok():
print "value is", (mymenu1.var).get(), (mymenu2.var).get()
button = Button(root, text="OK", command=ok)
button.pack()
mymenu1.pack()
mymenu2.pack()
(mymenu1.var).get()
(mymenu2.var).get()
#assign variable x to return values
x = (mymenu1.var).get()
if x <2:
print 'Negative changed to zero'
elif x == 0:
print 'Zero'
elif x == 1:
print 'Single'
else:
print 'More'
root.mainloop()
I am getting this as an output
"More"/
"value is Monday e", which shows I am able to access the correct outcome, but I am lost on implementing that variable (Tuesday) in the next step.
#JustForFun, your question is a little tangled and a bit hard to contemplate, but I think i understand what you want.
Firstly you have put the last part at the wrong place (from #assign variable x to return values), this will be run through at the start, but not after the ok button is clicked, so x will always equal 'Select day' (thus why you get more printed when you run it), you should put this inside a function to be called in ok(), or in ok() itself:
def ok():
print "value is", (mymenu1.var).get(), (mymenu2.var).get()
x = (mymenu1.var).get()
if x <2:
print 'Negative changed to zero'
elif x == 0:
print 'Zero'
elif x == 1:
print 'Single'
else:
print 'More'
This will get the value for x and test it when ok is clicked, and it can lead to more actions like using the results gained to open a file etc. BUT, you have (I think) just rushed the last part with the if/elif etc statements as the first if...: will pick up items below 2 (<), so the next two elif statements aren't going to evaluate as true, do you intend to have (>) in the first statement?
Also you probably need to include a variable for the second optionmenu in the if/elif statements:
if x > 2 and y == ...:
# open specific file? etc...

Python program getting stuck

I am new to Python and I am writing a program just for fun. My program consists of three .py files (let's say a.py, b.py, c.py). a will either call on the functions within either b or c, depending on the user's option. After it completes its first round it asks if the user would like to continue or simply exit the program. If they chose continue it asks again whether it should run b or c.
The problem I ran into is that the first time around, a will call the functions in either perfectly fine, it runs smoothly, and then when I select to continue it again calls either function perfectly fine, it will go into the function, but then the function gets stuck in its first step.
The program is not terminating, not giving an error. It accepts the raw_input variable but it will not continue. I was wondering if there was some way to force it to accept the variable and then continue the process (getting it 'unstuck'). I already tried putting pass on the next line. That didn't work.
Here are the steps it takes starting from the request to continue:
Continue = tkMessageBox.askyesno('Cypher Program', 'I have completed the task'
+ '\nWould you like to do anything else?')
## This is in a.py;
if Continue == True:
cyp()
def cyp():
global root
root = Tk()
root.title("Cypher Program")
root['padx'] = 40
root['pady'] = 20
textFrame = Frame(root)
Label(root, text = 'What would you like to do?').pack(side = TOP)
widget1 = Button(root, text = 'Encrypt a file', command = encrypt)
widget1.pack(side = LEFT)
widget2 = Button(root, text = 'Decrypt a file', command = decrypt)
widget2.pack(side = RIGHT)
widget3 = Button(root, text = 'Quit', command = quitr)
widget3.pack(side = BOTTOM)
root.mainloop()
def encrypt():
root.destroy()
encrypt3.crypt()
##Then from there it goes to b.py;
def crypt():
entry('Enter a file to encrypt:', selectFile)
def entry(msg1, cmd):
global top
top = Toplevel() ##changed it to Toplevel
top.title("File Encrypion")
top['padx'] = 40
top['pady'] = 20
textFrame = Frame(top)
entryLabel = Label(textFrame)
entryLabel['text'] = msg1
entryLabel.pack(side = LEFT)
global entryWidget
entryWidget = Entry(textFrame)
entryWidget['width'] = 50
entryWidget.pack(side = LEFT)
textFrame.pack()
button = Button(top, text = "Submit", command = cmd)
button.pack()
button.bind('<Return>', cmd)
top.mainloop()
def selectFile():
if entryWidget.get().strip() == "":
tkMessageBox.showerror("File Encryption", "Enter a file!!")
else:
global enc
enc = entryWidget.get().strip() + '.txt'
top.destroy() ##gets stuck here
##This is the rest of crypt(). It never returns to the try statement
try:
view = open(enc)
except:
import sys
sys.exit(badfile())
text = ''
You need to restructure your code to only create the root window once, and only call mainloop once. Tkinter is not designed to be able to create and destroy the root multiple times in a single process.
If you need multiple windows, create additional windows with the Toplevel command.

Categories