Python Tkinter retrieving input of multiple values - python

Here is the below code and I am having issues surrounding retrieving input from multiple values. I have been working on this issue for some time now without any suggest. I do appreciate the insight; however, I am at wits end. If someone could please provide a fix to my code I would be ever so grateful.
#!C:/Python27/python.exe
from Tkinter import *
import ImageTk, Image
root = Tk()
root.title('HADOUKEN!')
def retrieve_input(text,chkvar,v):
textarea_result = text.get()
checkbox_result = chkvar.get()
radiobutton_result = v.get()
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=lambda: retrieve_input(text,chkvar,v))
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()
print textarea_result
print checkbox_result
print radiobutton_result

You have several problems in your code, though most of them produce errors that should be self-explanatory. My suggestion is to start over with just a single widget, and get the logic working for that to reduce the number of things that could go wrong. Once you have that working, you can then add one widget at a time as you learn how to use that widget.
That being said, here are the most obvious errors that I spotted:
The first problem is that you are incorrectly calling the get method of a text widget. This method is documented to take two arguments -- a starting index and an ending index. Since tkinter always adds a trailing newline, you want to get everything from the start ("1.0"), to the end minus one character ("end-1c"). Thus, you should be getting the value in the text widget like this:
textarea_result = text.get("1.0", "end-1c")
The second problem is that retrieve_input seems to assume that v is a StringVar or IntVa since you are calling a get method on it. Given that you are using that variable with a radiobutton, that's what it should be. However, you created it as a normal variable, which of course doesn't have a get method. You should declare it as one of the special tkinter variables:
...
v = StringVar()
radio1 = Radiobutton(root, text="Src", variable=v, value=1)
...
The third problem is, retrieve_input is setting local variables. If you want to set the value of global variables (which I assume, since you are later trying to access them after the widget is destroyed), then you need to declare them as global:
def retrieve_input(text,chkvar,v):
global textarea_result, checkbox_result, radiobutton_result
...

Related

Tkinter: Changing image of Radiobutton using another Radiobutton works only the first time

I am trying to create a game level editor. The program reads a binary file, associate the byte to a image and then, with a loop, it shows all the images in canvas (Canvas B). The images are Radiobutton. This part works properly.
Below (Canvas A) I have a set of images that are radiobuttons too. Here I choose the image I want to use by clicking on it. This image will be used to redesign the Canvas B Then I go to the Canvas B, decide which tile I want to change and click on it. And it works: the radiobutton has now the chosen image.
In fact it works every time but only the first time. If I change my mind and want to change a radiobutton already changed nothing happens.
I tried to understand what the problem is by printing the variable of the radiobutton with .get()and I see that it stored the value of the last rabiobutton clicked. I tried to reset this value even with del but it doesn't work.
Here's the code (canvas B)
img_list=[]
n_row = 0
n_col = 0
index = 0
x = IntVar()
for f in os.listdir(path):
img_list.append(ImageTk.PhotoImage(Image.open(os.path.join(path,f))))
n_col +=1
index +=1
if n_col > 21:
n_row +=1
n_col = 1
tile = Radiobutton(A, image=img_list[index-1], indicatoron=0, bd=2, variable = x, value = index, selectcolor="red", command=several)
tile.grid(row=n_row, column = n_col)
And here's Canvas A
def erase():
global val_t_e_x
del val_t_e_x
val_t_e_x=t_e_x.get()
print(val_t_e_x)
img_qui=[]
for f in os.listdir(path):
img_qui.append(ImageTk.PhotoImage(Image.open(os.path.join(path,f))))
def several_editor():
global codice_bb
global val_x
global val_t_e_x
val_t_e_x=t_e_x.get()
print(val_t_e_x)
row_qui=row_list[val_t_e_x-1]
col_qui=col_list[val_t_e_x-1]
tile_editor=Radiobutton(B, image=img_qui[val_x-1], variable = val_t_e_x, value = rev, indicatoron=0, bd=0, selectcolor="blue",
highlightbackground="black", highlightcolor="black", command=erase)
tile_editor.grid(row=row_qui, column=col_qui)
col_b=0
row_b=9
l_editor=[]
row_list=[]
col_list=[]
rev=0
t_e_x = IntVar()
for x, y in zip(line[::2], line[1::2]):
a= ("./gfx/"+(x+y)+".png")
row_b-=1
rev+=1
if row_b<1:
col_b+=1
row_b=8
im = Image.open(a)
ph = ImageTk.PhotoImage(im)
l_editor.append(ph)
tile_editor = Radiobutton(B, image=l_editor[rev-1], variable = t_e_x, value = rev, indicatoron=0, bd=0, selectcolor="blue",
highlightbackground="black", highlightcolor="black", command=several_editor)
tile_editor.grid(row=row_b, column=col_b)
row_list.append(row_b)
col_list.append(col_b)
I suppose that the problem is in the function def several_editor()
tile_editor=Radiobutton(B, image=img_qui[val_x-1], variable = val_t_e_x, value = rev,
indicatoron=0, bd=0, selectcolor="blue", highlightbackground="black",
highlightcolor="black", command=erase)
and that I am not handling the val_t_e_x variable properly.
Hope you can help me.
The reason your function isn't returning is because you don't know what the input is for several_editor(). You need to anonymize it with lambda.
I'm going to provide a simple example of why this is necessary:
import tkinter, os, sys
import tkinter.ttk as ttk
class T():
def __init__(self):
labelstr=["ascii"]
top = tkinter.Tk()
top.geometry('200x50')
top.title('lambda')
for label in labelstr:
self.lab = tkinter.Label(top, text=label, width=len(label)).grid(row=labelstr.index(label)+1, column=0)
self.ent = tkinter.Entry(top, width=10).grid(row=labelstr.index(label)+1, column=1)
but = tkinter.Button(top, text="submit", command=lambda: self.submit(top))
but.grid(row=labelstr.index(label)+1, column=3)
top.mainloop()
def submit(self, frame):
for i in frame.winfo_children():
if i.winfo_class() == "Entry":
i.delete(0, tkinter.END)
i.insert(0, "HelloWorld!")
I can't really test the code where I am at the moment, but this should work.
The above is to provide a functional example of proper use of a lambda function within your code and demonstrate why you'd need it. Try removing the lambda and see that the function runs only once and will no longer run properly. This symptom should look familiar to you as it's exactly as you described it. Add the lambda back and the function runs again each time you hit the button.

Python Entry box takes text input in multiple Entry box

Im making a GUI application where I have 4 Entry section and if I enter text in one Entry box all Entry box are taking data. How do I code such that only on clicking over Entry box it should take input respectively...
Code:
from Tkinter import *
def time():
t1h=int(Ihr.get())
t1m=int(Imin.get())
t2h=int(Ohr.get())
t2m=int(Omin.get())
app = Tk()
app.title("VM")
app.geometry("150x210")
app.resizable(0,0)
note = Label(app, text="Clock IN Time :")
note.place(x=10, y=10)
Ihr = Entry(app,text="...")
Ihr.place(x=10, y=30,width="30")
Ihr.focus()
note = Label(app, text="::")
note.place(x=43, y=30)
Imin = Entry(app,text="...")
Imin.place(x=60, y=30,width="30")
note = Label(app, text="(hr)")
note.place(x=12, y=50)
note = Label(app, text="(min)")
note.place(x=58, y=50)
Ihr = Entry(app,text="...")
Imin = Entry(app,text="...")
I suspect the problem is on these two lines, in particular the text keyword arguments. At first glance I don't see the behavior of text documented anywhere, but I'm guessing they behave something like the textvariable argument. Since they both point to the same "..." object, changing one Entry will change the other.
Don't use the text argument to set the text of Entries. Use the .insert method instead.
Ihr = Entry(app)
Ihr.insert(0, "...")
Imin = Entry(app)
Imin.insert(0, "...")
Update:
Bryan Oakley confirms that the text and textvariable keyword arguments have the same effect. Generally, you should not pass a string object to these arguments; a StringVar is most conventional. You may be interested in using StringVars here, since you can use their .set method to set the contents of the Entry objects, without having to use the arguably more complicated .insert method.
Ihr_var = StringVar()
Ihr_var.set("...")
Ihr = Entry(app,text=Ihr_var)
Imin_var = StringVar()
Imin_var.set("...")
Imin = Entry(app,text=Imin_var)

How to autocall a function with a Listbox based on data in a separate Entry Widget without a button

I am trying to have my Listbox automatically run a query and populate immediately when corresponding Entry box has a value. This would be done without the use of a UPDATE or SELECT button(command=). If all fails I will have to resort to a button function call... I was hoping this could be accomplished without the use of a button. Essentially the autoquery would get (l) from 'team_input' and update levlistbox with the database result.
def autoquery(l):
levListbox.delete(0, "end")
l = team_input.get()
cursor = dbi.cursor()
cursor.execute("""SELECT level FROM teamstatus WHERE game='%s'"""%(l,))
rows = cursor.fetchall()
for results in rows:
levListbox.insert("end", results)
root.after(5000, autoquery)
root = Tk()
teamLabel=Label(topListFrame, text="Team", font="Verdana 8 bold")
teamLabel.grid(row=0,column=0)
team_input = StringVar()
team_input = Entry(topListFrame, textvariable=team_input, width=10)
team_input.grid(row=1,column=0)
levLabel=Label(topListFrame, text="Level", font="Verdana 8 bold")
levLabel.grid(row=0,column=1)
levListbox=Listbox(topListFrame, height=1,width=8)
#TRIED TO USE lambda WITH autoquery(team_input))
levListbox.grid(row=1, column=1)
autoquery()
root.mainloop()
You can callback a method when the string in an entry is changed by making use of special tkinter variables or variable classes such as StringVar and the method trace_add. Now you already seem to want to use StringVar but:
team_input = StringVar()
team_input = Entry(topListFrame, textvariable=team_input, width=10)
lines make team_input first be the variable class required to do that but you then overwrite that variable with Entry which makes not much sense. Try replacing to:
team_input_var = StringVar()
team_input = Entry(topListFrame, textvariable=team_input_var, width=10)
and then add before mainloop:
team_input_var.trace_add('write', autoquery)
If you want to call autoquery whenever what's written in entry is changed.
Also note that def autoquery(l) looks redundant, but since trace_add sends 3 somewhat not related arguments, replace it with def autoquery(*args).

Tkinter: AttributeError using .get()

I am trying to retrieve a variable from a Tkinter Wiget but I am running into this error message:
AttributeError: 'int' object has no attribute 'get'
Here is the widget code
JobNEntry = tkinter.Entry(menu, textvariable = tk.IntVar(JobNo))
JobNEntry.grid(row=2, column=2, sticky="W")
Here is the call code
JobNo=JobNo.get()
Also I need to know if the variable JobNo is writable to a file.
Thanks in advance
The get() method is part of several widgets in tkinter and is not something that you can use on a normal int or str object. get() must be called on a variable that is a widget object that has a get() method, like Entry.
Its likely you need to do:
JobNEntry.get()
This will get the current value from the entry field as a string.
If you want to save the value of that string you can. There are several tutorials on Stack Overflow and the web that go into detail on how to save a string to a file.
Looking at the code you have shown us, it's possible you have not created your IntVar() correctly.
Make sure you define the IntVar() first then set that variable as the textvariable.
Something like this:
JobNo = tk.IntVar()
JobNEntry = tkinter.Entry(menu, textvariable = JobNo)
The attribute error might be because you havnt already initialized the variable JobNo as an 'IntVar'
This is the code i have come up with :
import tkinter as tkinter
menu=tkinter.Tk()
JobNo=tkinter.IntVar()
JobNEntry = tkinter.Entry(menu, textvariable = JobNo)
JobNEntry.grid(row=2, column=2, sticky="W")
JobNo=JobNo.get()
menu.mainloop()
You need to initialize JobNo as an Integer Variable using IntVar()
JobNo=tkinter.IntVar()
And then use it in the Entrybox.
If you had some string to add to the entry, you should initialise as StringVar()
Also when you initialize, make sure you do it after opening the Tk window.(here i put it after menu=tkinter.Tk())
Something like this:
from tkinter import *
from tkinter import ttk
def save_job_no():
try:
n = job_no.get()
except TclError:
status.config(text = "This is not an integer")
return False
status.config(text="")
f = open("my_file.txt", "w")
f.write(str(n))
return True
root = Tk()
job_no = IntVar()
entry = ttk.Entry(root, width = 30, textvariable = job_no)
entry.grid()
label = ttk.Label(root, textvariable = job_no)
label.grid()
status = ttk.Label(root)
status.grid()
button = ttk.Button(root, text = "Write to a file", command = save_job_no)
button.grid()
root.mainloop()

Creating a GUI with Tkinter of Python

I have written the following code:
from Tkinter import *
root = Tk()
root.title("Power Method")
labeltext1 = StringVar()
labeltext2 = StringVar()
labeltext1.set('Parameters') # Set start value
labeltext2.set('Epsilon')
label1 = Label (root, textvariable = labeltext1, height = 4)
label1.pack()
Entry(root, textvariable = labeltext1). pack()
label2 = Label (root, textvariable = labeltext2)
label2.pack()
Entry(root, textvariable = labeltext2). pack()
checkBox1 = Checkbutton(root, text = "NumPy")
checkBox1.pack()
checkBox2 = Checkbutton(root, text = "Not NumPy")
checkBox2.pack()
Button(root, text = "Exit").pack(side = RIGHT)
Button(root, text = "Compute").pack(side = RIGHT)
root.mainloop()
This code, when run, creates a window that contains Parameters, Epsilon as two places that you could enter value and NumPy and Not NumPy as checkboxes and finally a compute and exit button.
I am trying to format the code, in a way that Parameters and Epsilon appear on the left of the window, Numpy and Not Numpy infront of them on the right and Compute and Exit stay in their current positions.
Any help regarding the formatting would be appreciated.
Alright you need to google .grid() and .pack() and .place() for tkinter to learn more about what each is good for. For your case you could use any of them, but .grid() is probably the best and easiest for you to use.
To do this you must change .pack() to .grid() everywhere you have it, then you should use the row and column options to put your widgets where you want them. E.G.
label1.grid(row = 1, column = 1)
label2.grid(row = 1, column = 2)
this will put label2 on the right side of label1. The way .grid() works is that the columns are as wide as the largest (widest) widget in that column, same applies for rows.
if you need anything else just ask, but please do look at the documentations as Bryan said.

Categories