Tkinter - setting string variables and getting entry values when looping - python

My goal is to be able to pass string variables to two different entries for user validation and return the user modified values. The code works fine if it is executed a single time; however, when looped, it only performs correctly during the first iteration of the loop. During subsequent iterations the string variables for the entries are blank.
I have experimented with update_idletasks() and time-sleep without luck. I am running Python 2.4 on Windows XP.
# -*- coding: cp1252 -*-
import Tkinter
def retrieve_text():
app_win.quit()
for item in range(3):
numero_dossier = item+1
version_dossier = item+2
app_win = Tkinter.Tk()
l = Tkinter.Label(app_win, text="Veuillez valider les informations suivantes et les corriger au besoin :")
l.grid(row=0, column=0, columnspan=2)
l.pack()
v1 = Tkinter.StringVar()
v1.set(numero_dossier)
l1 = Tkinter.Label(app_win, text="Numéro de dossier:", anchor='w', justify='left')
e1 = Tkinter.Entry(app_win, textvariable=v1)
l1.pack()
e1.pack()
v2 = Tkinter.StringVar()
v2.set(version_dossier)
l2 = Tkinter.Label(app_win, text="Version du dossier:", anchor='w', justify='left')
e2 = Tkinter.Entry(app_win, textvariable=v2)
l2.pack()
e2.pack()
app_button = Tkinter.Button(app_win,text="OK",command=retrieve_text)
app_button.pack()
app_win.mainloop()
app_win.withdraw()
numero_dossier = e1.get().strip()
version_dossier = e2.get().strip()
print numero_dossier, version_dossier

This is fundamentally broken:
for item in range(3):
...
app_win = Tkinter.Tk()
Tkinter is simply not designed to work this way. Your program should only ever create a single instance of the class Tk, and you should call mainloop exactly once.

There is no rationale in the question on why the widgets are being constructed multiple times, so I will take that as a mistake. Also, the name app_win for an Tkinter.Tk instance might be fooling you. Instantiating Tkinter.Tk starts a tcl interpreter, and then loads tk which as a "bonus" gives you a window.
The more sensible approach is creating the widgets only once, and then doing the multiple validations you are after. Here is your code adjusted for this:
import Tkinter
NUM_D = range(3)
VER_D = range(3)
CURR_D = 0
def retrieve_and_update_text():
global CURR_D
num_d = e1.get().strip()
ver_d = e2.get().strip()
print num_d, ver_d
CURR_D = (CURR_D + 1) % 3
v1.set(NUM_D[CURR_D] + 1)
v2.set(VER_D[CURR_D] + 2)
root = Tkinter.Tk()
l = Tkinter.Label(root, text=u"Label")
l.grid(row=0, column=0, columnspan=2)
v1 = Tkinter.StringVar()
l1 = Tkinter.Label(root, text=u"Num", anchor='w', justify='left')
e1 = Tkinter.Entry(root, textvariable=v1)
l1.grid(row=1)
e1.grid(row=1, column=1)
v2 = Tkinter.StringVar()
l2 = Tkinter.Label(root, text=u"Ver", anchor='w', justify='left')
e2 = Tkinter.Entry(root, textvariable=v2)
l2.grid(row=2)
e2.grid(row=2, column=1)
app_button = Tkinter.Button(root, text=u"OK", command=retrieve_and_update_text)
app_button.grid(row=3)
v1.set(NUM_D[CURR_D] + 1)
v2.set(VER_D[CURR_D] + 2)
root.mainloop()

Thanks to Bryan Oakley and mmgp, I was able to come up with the following code that does what I need, even though I am breaking the mainloop rule as it gets called during each iteration of the loop. All comments are welcome. Thanks again!
# -*- coding: cp1252 -*-
import Tkinter
root = Tkinter.Tk()
def retrieve_and_update_text():
#global CURR_D
dossier = e1.get().strip()
version = e2.get().strip().upper()
print dossier, version
root.quit()
for item in range(3):
dossier = item+1
version = item+2
l = Tkinter.Label(root, text=u"Veuillez valider les informations suivantes et les corriger au besoin :")
l.grid(row=0, column=0, columnspan=2)
v1 = Tkinter.StringVar()
l1 = Tkinter.Label(root, text=u"Dossier :", anchor='w', justify='left')
e1 = Tkinter.Entry(root, textvariable=v1)
l1.grid(row=1)
e1.grid(row=1, column=1)
v2 = Tkinter.StringVar()
l2 = Tkinter.Label(root, text=u"Version :", anchor='w', justify='left')
e2 = Tkinter.Entry(root, textvariable=v2)
l2.grid(row=2)
e2.grid(row=2, column=1)
app_button = Tkinter.Button(root, text=u"OK", command=retrieve_and_update_text)
app_button.grid(row=3)
v1.set(dossier)
v2.set(version)
root.mainloop()
if item == range(3)[-1]: # if last item
root.withdraw()

Related

Tkinter create clear button to clear various textbox

I have around 40 textboxes named from d1 to d40.
Currently I have created a Clear Button with 40 lines, each line stating the textbox number (eg: "d1.delete(0, END)" to clear the textbox).
I know there should be a smarter way... but I tried many times and failed.
Below please find extract of my code:
import tkinter as tk
from tkinter import *
win = Tk()
win.wm_title("Testing")
win.wm_geometry("400x400+10+30")
v = StringVar()
v.set('abcd')
d1 = Entry(win, text=v)
d1.place(x=10, y=10, height=30, width=400)
s = StringVar()
s.set('abc22222222')
d2 = Entry(win, text=s)
d2.place(x=10, y=50, height=30, width=400)
t = StringVar()
t.set('abc22sdfefe222222')
d3 = Entry(win, text=t)
d3.place(x=10, y=90, height=30, width=400)
def clearcomm():
n = 0
for i in range(3):
n +=1
'd{}.delete(0, END)'.format(n)
Button(win, text='Clear', command=clearcomm, height=1, width=6, font=("arial", 7, "bold"), fg="white", bg="red").place(x=10, y=150)
mainloop()
then I also tried:
clearlist = []
n = 0
for i in range(3):
n +=1
command = 'd{}.delete(0, END)'.format(n)
clearlist.append(command)
n = 0
def clearcomm():
for list in clearlist:
return
but this one no response...so I do not know how to do it. Very grateful if you can give some advise.
The smarter way you probably look for is a list of all textboxes you want to clear:
global textboxes
textboxes = []
global contents
contents = []
for y in [10,50,90]:
v = StringVar()
v.set('sometext')
d1 = Entry(win, textvariable=v)
d1.place(x=10, y=y, height=30, width=400)
textboxes.append(d1)
contents.append(v)
You then have two lists. One containing all entry widgets, the other containing all contents. You can manipulate both using for-loops to iterate over all objects:
def clearcomm():
for c in contents:
c.set('')
or
def clearcomm():
for t in textboxes:
t.delete(0,END)
Both should work since you use textvariables.
[EDIT: global statements moved uniformly to the front. Thanks for noting, Cool Cloud.]

how to get the the value from the entry widget in tkinter in python3.6

I'm trying to get the data from the entry box.I'm not getting the use of those variables. It's showing me blank when I try to print the result. I tried using lambda but still not working. I'm new at this. Please show me where I'm wrong. I tried online but they are older version solutions.
def insertdata(E1):
print(E1)
e1 = StringVar()
L1 = Label(F1, text ="Serial No:",anchor = E)
L1.grid(row = 0 ,column = 0)
E1 = Entry(F1,textvariable = e1)
E1.grid(row = 0 ,column = 2, sticky = N)
v1 = e1.get()
Button (F2,text = "Paid",command=lambda:insertdata(v1)).pack(side= TOP)
This how to get content in entry widget and print. With the code you posted, you are doing a lot of wrong things; you cannot use pack and grid to postion your widget in the same window. Also never do this: Button (F2,text = "Paid",command=lambda:insertdata(v1)).pack(side= TOP), but always position your layout manager on the next line.
EXAMPLE
b = Button (F2,text = "Paid",command=lambda:insertdata(v1))
b.pack(side= TOP)
FULL CODE
from tkinter import *
def insertdata():
print(e1)
print(E1.get())
root = Tk()
L1 = Label( text="Serial No:", anchor=E)
L1.grid(row=0, column=0)
e1 = StringVar()
E1 = Entry( textvariable=e1)
E1.grid(row=0, column=2, sticky=N)
b = Button( text="Paid", command=insertdata)
b.grid(row=10, column=30)
root.mainloop()
You have set v1 to e1.get() before anything could be entered into the entry.
I tried the following code, and it works fine.
from tkinter import * # SHOULD NOT USE.
F1=Tk()
F2=Tk()
def insertdata(E1):
print(E1)
e1 = StringVar()
L1 = Label(F1, text ="Serial No:",anchor = E)
L1.grid(row = 0 ,column = 0)
E1 = Entry(F1,textvariable = e1)
E1.grid(row = 0 ,column = 2, sticky = N)
Button (F2,text = "Paid",command=lambda:insertdata(e1.get())).pack(side= TOP) # SHOULD NOT USE.

Tkinter Dual Command for one Button

I'm doing my GCSE's and this is one of the tasks that I have been given, (btw I'm not very good at this) I need help with putting two commands into one button on tkinter for python. Here is my Code
# --------------------- START OF SCRIPT ---------------------
# Imports
from tkinter import *
# Question 1
def rootclose():
root.destroy()
def question1():
q1 = Tk()
q1.geometry("500x500+200+200")
f1 = Frame()
f1.pack(side=LEFT)
f2 = Frame()
f2.pack(side=RIGHT)
q1l1 = Label(q1, text="Question 1", fg="Green")
q1l1.pack()
q1l2 = Label(q1, text="What Operating System Dose Your Phone Run?", fg="Green")
q1l2.pack()
def question2v1():
q2v1 = Tk()
a1.destroy()
q2v1.geometry("500x500+200+200")
q2v1l1 = Label(q2v1, text="", fg="Green")
q2v1l1.pack()
q2v1l2 = Label(q2v1, text="", fg="Green")
q2v1l2.pack()
b1 = Button(q2v1, text="Android")
b2 = Button(q2v1, text="")
b1.pack()
b2.pack()
q2v1.mainloop()
def ios():
q3 = Tk()
q1.destroy()
q3.geometry("500x500+200+200")
q3l1 = Label(q3, text="Question 1", fg="Green")
q3l1.pack()
q3l2 = Label(q3, text="Did you select IOS", fg="Green")
q3l2.pack()
b1 = Button(q3, text="Android")
b2 = Button(q3, text="IOS")
b1.pack()
b2.pack()
q3.mainloop()
q1b1 = Button(q1, text="Android", command=question2v1)
q1b2 = Button(q1, text="IOS", command=ios)
q1b1.pack()
q1b2.pack()
q1.mainloop()
# Tkinter startups
root = Tk()
# Size ect..
root.geometry("500x500+200+200")
#HelpBot
L1 = Label(root, text="Welcome To HelpBot", fg="Green")
L1.pack()
# StartButton
B1 = Button(root, text="Start!", command=question1 and rootclose)
B1.pack()
# END OF SCRIPT
root.mainloop()
I am specifically trying to fix this
# StartButton
B1 = Button(root, text="Start!", command=question1 and rootclose)
B1.pack()
The And that I have put in the command section of the button will only run the Last function in this case "rootclose" and not bother with this first which in this case is "question1"
Create a function to do your 2 commands, and make calling that the command that the button does.

Data Entry error

l would like to create a control system for administrator on Tkinter and some functions (add, delete, update and load) are main part of control system but when l run the code , these functions do not work and there is no error message. But ,l could not figure out where the problem is. My code is still not completed yet. İf l solve it, then l will move to another step.
import tkinter
from tkinter import *
userlist = [
['Meyers', '12356'],
['Smith','abcde'],
['Jones','123abc34'],
['Barnhart','12//348'],
['Nelson','1234'],
["Prefect",'1345'],
["Zigler",'8910'],
['Smith','1298']]
def domain():
def whichSelected () :
print ("At %s of %d" % (select.curselection(), len(userlist)))
return int(select.curselection()[0])
def addEntry():
userlist.append ([nameVar.get(), passwordVar.get()])
setSelect()
def updateEntry():
userlist[whichSelected()] = [nameVar.get(), passwordVar.get()]
setSelect()
def deleteEntry():
del userlist[whichSelected()]
setSelect()
def loadEntry():
name, password = userlist[whichSelected()]
nameVar.set(name)
passwordVar.set(password)
def makeWindow():
win=Tk()
global nameVar, passwordVar, select
frame1 = Frame(win)
frame1.pack()
Label(frame1, text="Name").grid(row=0, column=0, sticky=W)
nameVar = StringVar()
name = Entry(frame1, textvariable=nameVar)
name.grid(row=0, column=1, sticky=W)
Label(frame1, text="Password").grid(row=1, column=0, sticky=W)
passwordVar= StringVar()
password= Entry(frame1, textvariable=passwordVar)
password.grid(row=1, column=1, sticky=W)
frame2 = Frame(win) # Row of buttons
frame2.pack()
b1 = Button(frame2,text=" Add ",command=addEntry)
b2 = Button(frame2,text="Update",command=updateEntry)
b3 = Button(frame2,text="Delete",command=deleteEntry)
b4 = Button(frame2,text=" Load ",command=loadEntry)
b1.pack(side=LEFT); b2.pack(side=LEFT)
b3.pack(side=LEFT); b4.pack(side=LEFT)
frame3 = Frame(win) # select of names
frame3.pack()
scroll = Scrollbar(frame3, orient=VERTICAL)
select = Listbox(frame3, yscrollcommand=scroll.set, height=6)
scroll.config (command=select.yview)
scroll.pack(side=RIGHT, fill=Y)
select.pack(side=LEFT, fill=BOTH, expand=1)
return win
def setSelect():
userlist.sort()
select.delete(0,END)
for name in userlist:
select.insert(END,name)
win=makeWindow()
setSelect()
win.mainloop()
page1=Tk()
but1=Button(page1,text="Domain",command=domain).pack()
It is bad practice to define your functions in a function and makes debugging pretty difficult. I would start by using an object to create this GUI. Object variables:
passwordVar and nameVar,
select
userlist
win
There's a lot going wrong for your code.
For instance, you don't need to import tkinter twice. Your casing of the variable names doesn't follow PEP8. You could benefit from an OOP approach.
I would suggest finding a good IDE to code in that can highlight your formatting and errors.
Take a look at the provided code:
import tkinter as tk
user_list = [
['Meyers', '12356'],
['Smith','abcde'],
['Jones','123abc34'],
['Barnhart','12//348'],
['Nelson','1234'],
["Prefect",'1345'],
["Zigler",'8910'],
['Smith','1298']]
class Domain(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
self.name_var = tk.StringVar()
self.password_var = tk.StringVar()
self.make_window()
def which_selected(self):
print("At %s of %d" % (self.select.curselection(), len(user_list)))
return int(self.select.curselection()[0])
def add_entry(self):
user_list.append([self.name_var.get(), self.password_var.get()])
self.set_select()
def update_entry(self):
user_list[self.which_selected()] = [
self.name_var.get(), self.password_var.get()]
self.set_select()
def delete_entry(self):
del user_list[self.which_selected()]
self.set_select()
def load_entry(self):
name, password = user_list[self.which_selected()]
self.name_var.set(name)
self.password_var.set(password)
def make_window(self):
frame1 = tk.Frame(self.parent)
frame1.pack()
tk.Label(frame1, text="Name").grid(row=0, column=0, sticky=tk.W)
name = tk.Entry(frame1, textvariable=self.name_var)
name.grid(row=0, column=1, sticky=tk.W)
tk.Label(frame1, text="Password").grid(row=1, column=0, sticky=tk.W)
password = tk.Entry(frame1, textvariable=self.password_var)
password.grid(row=1, column=1, sticky=tk.W)
frame2 = tk.Frame(self.parent) # Row of buttons
frame2.pack()
b1 = tk.Button(frame2, text=" Add ", command=self.add_entry)
b2 = tk.Button(frame2, text="Update", command=self.update_entry)
b3 = tk.Button(frame2, text="Delete", command=self.delete_entry)
b4 = tk.Button(frame2, text=" Load ", command=self.load_entry)
b1.pack(side=tk.LEFT)
b2.pack(side=tk.LEFT)
b3.pack(side=tk.LEFT)
b4.pack(side=tk.LEFT)
frame3 = tk.Frame(self.parent) # select of names
frame3.pack()
scroll = tk.Scrollbar(frame3, orient=tk.VERTICAL)
self.select = tk.Listbox(frame3, yscrollcommand=scroll.set, height=6)
scroll.config(command=self.select.yview)
scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.select.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
def set_select(self):
user_list.sort()
self.select.delete(0, tk.END)
for name in user_list:
self.select.insert(tk.END, name)
if __name__ == '__main__':
root = tk.Tk()
Domain(root)
root.mainloop()
Note:
There's still errors here, but I don't exactly know what you're trying to do so I've just restructured it here so you can start on a better path.

Python Tk _tkinter.TclError: invalid command name ".42818376"

I am getting the error mentioned in the title of the post I really just want this to work. Been working on this problem for a while now and it is frustrating. My ultimate goal is to obtain the values for the varables text, chkvar, and v.
Thanks to anyone who can reply and help on this!!
#!C:/Python27/python.exe
from Tkinter import *
import ImageTk, Image
root = Tk()
root.title('HADOUKEN!')
def killwindow():
root.destroy()
text = Text(root, height=16, width=40)
scroll = Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=scroll.set)
text.grid(sticky=E)
scroll.grid(row=0,column=1,sticky='ns')
text.focus()
chkvar = IntVar()
chkvar.set(0)
c = Checkbutton(root, text="CaseIt", variable=chkvar)
c.grid(row=1,column=0,sticky=W)
v = ""
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
radio1.grid(row=1,column=0)
radio1.focus()
radio2 = Radiobutton(root, text="Dst", variable=v, value=2)
radio2.grid(row=2,column=0)
b1 = Button(root, text="Submit", command=killwindow)
b1.grid(row=1, column=2)
img = ImageTk.PhotoImage(Image.open("Hadoken.gif"))
panel = Label(root, image = img)
panel.grid(row=0, column=2)
root.mainloop()
tk1 = text.get(text)
tk2 = chkvar.get(chkvar)
tk3 = v.get(v)
print tk1
print tk2
print tk3
Once mainloop exits, the widgets no longer exist. When you do text.get(text), you're trying to access a deleted widget. Tkinter simply isn't designed to allow you to access widgets after the main window has been destroyed.
The quick solution is to modify killwindow to get the values before it destroys the window, and store them in a global variable which you can access after mainloop exits.
The program didn't make it through the variable getting, so it never reported the incorrect method calls. I made a few changes to the original code (added a textval StringVar, and changed the v variable to another IntVar). I had a feeling the "associated variables" wouldn't have a problem, and didn't need to be included in the killwindow code. The only variable I grab in killwindow is the text data.
Working code (changed lines marked with #++) :
#!C:/Python27/python.exe
from Tkinter import *
import ImageTk, Image
root = Tk()
root.title('HADOUKEN!')
textval = StringVar() #++ added
def killwindow():
textval.set(text.get('1.0',END)) #++ grab contents before destruction
root.destroy()
text = Text(root, height=16, width=40)
scroll = Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=scroll.set)
text.grid(sticky=E)
scroll.grid(row=0,column=1,sticky='ns')
text.focus()
chkvar = IntVar()
chkvar.set(0)
c = Checkbutton(root, text="CaseIt", variable=chkvar)
c.grid(row=1,column=0,sticky=W)
v = IntVar() #++ changed
v.set(1) #++ initial value
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
radio1.grid(row=1,column=0)
radio1.focus()
radio2 = Radiobutton(root, text="Dst", variable=v, value=2)
radio2.grid(row=2,column=0)
b1 = Button(root, text="Submit", command=killwindow)
b1.grid(row=1, column=2)
img = ImageTk.PhotoImage(Image.open("Hadoken.gif"))
panel = Label(root, image = img)
panel.grid(row=0, column=2)
root.mainloop()
# windows are destroyed at this point
tk1 = textval.get() #++ changed
tk2 = chkvar.get() #++ changed
tk3 = v.get() #++ changed
print tk1
print tk2
print tk3

Categories