I am using Tkinter entry widgets to allow users to input text to a GUI. The entry widgets have default text which I would like to clear with a single button press. I have the following code:
from Tkinter import *
def delete_entries(fields):
for field in fields:
field.delete(0,END)
def UserInput(status,name):
optionFrame = Frame(root)
optionLabel = Label(optionFrame)
optionLabel["text"] = name
optionLabel.pack(side=LEFT)
var = StringVar(root)
var.set(status)
w = Entry(optionFrame, textvariable= var)
w.pack(side = LEFT)
optionFrame.pack()
if __name__ == '__main__':
root = Tk()
fields = 'ExperimentNumber', 'OutputFileName', 'npts1', 'block1'
ExperimentNumber = UserInput("1", "Experiment number")
OutputFileName = UserInput("output.txt", "Output file name")
npts1 = UserInput("1000", "Number of points")
block1 = UserInput("8", "Block size")
Delete_button = Button(root, text = 'Clear all', command = delete_entries(fields))
Delete_button.pack()
I have tried creating fields with the list of variables that I want to delete (as above) and iterating over this in the function delete_entries(), however this returns an error because the entries in fields are strings. I have tried replacing fields with fields = ExperimentNumber for example, but this returns an error because ExperimentNumber hasn't yet been defined. Finally I tried putting ExperimentNumber within the delete function i.e.
def delete_entries():
ExperimentNumber.delete(0,End)
but this doesn't work because ExperimentNumber has the attribute NoneType (I don't understand why this is, because the delete_entries() function isn't called until after the ExperimentNumber Entry widget is created via the function UserInput). How can I go about deleting all the text in the Entry widgets? I have about 20 of these in my actual code and would like the user to be able to clear all the fields with one button press.
You are on the right track but you missed two little things. I added those two in your code and tried to explain with comments.
from Tkinter import *
def delete_entries():
for field in fields:
field.delete(0,END)
def UserInput(status,name):
optionFrame = Frame(root)
optionLabel = Label(optionFrame)
optionLabel["text"] = name
optionLabel.pack(side=LEFT)
var = StringVar(root)
var.set(status)
w = Entry(optionFrame, textvariable= var)
w.pack(side = LEFT)
optionFrame.pack()
return w
#this return is crucial because if you don't return your widget's identity,
#you can not use them in another function
if __name__ == '__main__':
root = Tk()
ExperimentNumber = UserInput("1", "Experiment number")
OutputFileName = UserInput("output.txt", "Output file name")
npts1 = UserInput("1000", "Number of points")
block1 = UserInput("8", "Block size")
#you are saying it does not work because of they are strings.
#then don't assign strings to fields. assign variables.
fields = ExperimentNumber, OutputFileName, npts1, block1
#since fields is defined in global scope, you don't need to use it as parameter
Delete_button = Button(root, text = 'Clear all', command = delete_entries)
Delete_button.pack()
root.mainloop()
Related
I need to represent in "ventana2" the pairs entered in "ventana", so that a new frame appears when the key is new. When the key already exists in the dictionary, I need to change the old value in the frame created for that key previously (the new value is adding old and new).
I can not get the frames permanently related to my dictionary partner, through the key.
Thank you very much in advance, and sorry for my english.
Here is a summary of the code:
import tkinter as tk
ventana = tk.Tk()
ventana2 = tk.Tk()
name = tk.StringVar()
tk.Entry(ventana, textvariable=name, width=30).grid(row=0, column=1)
tk.Label(ventana, text = 'Nombre').grid(row=0, column=0)
value = tk.StringVar()
tk.Entry(ventana, textvariable=value, width=30).grid(row=1, column=1)
tk.Label(ventana, text = 'Celular').grid(row=1, column=0)
contactos={}
def intro():
nom = name.get()
if nom in contactos:
cel = contactos[nom] + float(value.get())
contactos[nom] = cel
else:
cel = float(value.get())
contactos[nom] = cel
create_widget()
def create_widget():
frame = tk.Frame(ventana2)
frame.pack()
nomb = tk.Label(frame, text=name.get()).pack(side=tk.LEFT)
telf = tk.Label(frame, text=contactos[name.get()]).pack(side=tk.RIGHT)
intro_btn = tk.Button(ventana, text='Intro', command = intro)
intro_btn.grid(row=2, column=0, columnspan=2, sticky = 'ew')
ventana.mainloop()
Labels created inside the create_widget() function is in the function scope. After the function ends all references to the label is lost. So you need to think of a way to save references to the label (suggest return statement) and associate them to the dictionary of contactos.
Update - relate a frame with a value
Save a reference to the object you wish to remember and the name you want to use to recall it in a list(or dict or tuple et.). Then append all that to your global list of widgets. For example:
nomb = tk.Label( ... )
widget_parameters = ['Nomb Label', nomb]
global_widget_list.append(widget_parameters)
Then you can search the global_widget_list for any widget you have named and get a referance to that widget.
I have included some example code to illustrate one way that you can accomplish that. Play around with it until you understand it and you will be able to implement it in your own application.
from tkinter import *
import time
root = Tk()
root.geometry('300x200')
global_widget_list = [] # List for holding all widgets
def make_label(): # Create label
text_label = Label(root,text='Text input')
text_label.pack()
global_widget_list.append(['Text Label',text_label]) # Add widget to list
def make_input(): # Create entry
inputvar = StringVar()
text_input = Entry(root,width=20,textvariable=inputvar)
text_input.pack()
global_widget_list.append(['Text Input',text_input,inputvar]) # Add widget to list
make_label() # Run functions to cretae GUI
make_input()
root.update() # Take care of updating GUI
time.sleep(3) # Wait so you have time to see the original, then change it
# Now, loop through all widgets and do what you want
for widget in global_widget_list:
widget_name = widget[0]
widget_id = widget[1]
print(widget_name, 'has identity', widget_id)
if widget_name == 'Text Label':
print('Changing test label text to: ALL CAPS')
widget_id.configure(text='ALL CAPS')
if widget_name == 'Text Input':
print('Changing text in entry to: SAMPLE')
var = widget[2]
var.set('SAMPLE')
root.update() # Take care of updating GUI
time.sleep(3) # Wait so you have time to see the changes, then change it
print('Removing Entry from application GUI')
global_widget_list[1][1].pack_forget() # Remove entry form GUI
I am using tkinter GUI. Created GUI, Now at one of my GUI ask Input value and I need to display that Input Value in another function and print that value.
Code is as below:
def EventOnBtnIO():
#some commutation
ForceNumericItem() #Called the function to open the new GUI
request = 'FF'+Value
print request
return
This is my GUI which consists of entry box and buttons
def ForceNumericItem():
global Subtop
Subtop = Toplevel(top)
Subtop.geometry("350x110+500+200")
Subtop.title("Force Numeric Items")
Subtop.grab_set()
frame = Frame(Subtop,width=15, height=200,bd = 1)
frame.pack(fill = 'both',padx=3, pady=3)
# frame.config(relief=RIDGE)
global entry2
global entrytext2
entrytext2 = IntVar()
entry2 = Entry(frame,textvariable=entrytext2, width = 45)
entry2.pack(padx = 5, pady = 5)
entry2.focus_set()
entry2.selection_range(0, END)
topButtonShow = Button(frame, text = 'OK',command = ForceValue,width = 10)
topButtonBack = Button(frame, text = 'Cancel',command = okclose,width = 10)
topButtonShow.pack(side = LEFT,padx=45,pady=5)
topButtonBack.pack(side = RIGHT,padx=45,pady=5)
return
After OK click, it should take the Value and display in my EventOnBtnIO function
def ForceValue():
global Value
Value = int(entrytext2.get())
print Value
Subtop.destroy()
top.deiconify()
return
I think it is related to local or global varibale, but not able to fix it. Getting value now
FF
Expected value
FF + Value
The function in which you create your popup window returns before the user has input a number in it. To fix this, you could use the .wait_window() method:
def EventOnBtnIO():
ForceNumericItem()
top.wait_window(Subtop)
request = 'FF'+str(Value)
print request
first off im very new to programing Python 3.4.3, im trying to call 5 entrys and put them into and array and display that, but im stuck at GPA1 not defined, but it is defined in for the entry app
import sys
from tkinter import *
def save_data():
fileD.write("GPA1:\n")
fileD.write("%s\n" % GPA1.get())
fileD.write("GPA2:\n")
fileD.write("%s\n" % GPA2.get())
fileD.write("GPA3:\n")
fileD.write("%s\n" % GPA3.get("1.0", END))
app = Tk()
app.title('Student Grade Report')
gpa1=str(GPA1.get())
gp1=float(gpa1)
gpa2=str(GPA2.get())
gp2=float(gpa2)
gpa3=str(GPA3.get())
gp3=float(gpa3)
gpa4=str(GPA4.get())
gp4=float(gpa4)
gpa5=str(GPA5.get())
gp5=float(gpa5)
gpas=gp1+gp2+gp3+gp4+gp5
avg=gpas/5
def DisplayMsg():
DL=str("Dean's list")
AP=str("Academic Probation")
note=("No Message")
if (avg>3.5):
note=DL
else:
if (avg<2.0):
note=AP
return str(note)
classi = StringVar()
classi.set(None)
Label(app, text = "Classification:").pack()
Classification = StringVar()
Classification.set(None)
Radiobutton(app, variable = classi, text = "freshman", value = "freshman").pack()
Radiobutton(app, variable = classi, text = "sophmore", value = "sophmore").pack()
Radiobutton(app, variable = classi, text = "junior", value = "junior").pack()
Radiobutton(app, variable = classi, text = "senior", value = "senior").pack()
Label(app, text = "GPA1:").pack()
GPA1= StringVar()
GPA1.set(None)
GPA1= Entry(app,textvariable=Gpa1).pack()
Label(app, text = "GPA2:").pack()
GPA2= StringVar()
GPA2.set(None)
GPA2 = Entry(app)
Label(app, text = "GPA3:").pack()
GPA3= StringVar()
GPA3.set(None)
GPA3= Entry(app)
Label(app, text = "GPA4:").pack()
GPA4= StringVar()
GPA4.set(None)
GPA4= Entry(app)
Label(app, text = "GPA5:").pack()
GPA5= StringVar()
GPA5.set(None)
GPA5= Entry(app)
Button(app, text= "Message", command = DisplayMsg).pack()
Button(app, text = "Save", command = save_data).pack()
app.mainloop()
The program published above does have some problems with indentation, but I suspect that this happened when inserting into the editor.
Also, I suspect your error says Gpa1 undefined, not GPA1. This is because you assign a text variable to the Entry which is not initialized yet (i.e. it does not exist).
The way you pack() the widgets, make them appear vertically. If you want them in a spreadsheet like table, you have to use a packer such as .grid(), and specify the column and row where you want the widget to appear.
Here's the code, slightly cleaned up (Note that I had to use Tkinter to find the module - not tkinter):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
from Tkinter import *
def save_data():
fileD.write("GPA1:\n")
fileD.write("%s\n" % GPA1.get())
fileD.write("GPA2:\n")
fileD.write("%s\n" % GPA2.get())
fileD.write("GPA3:\n")
fileD.write("%s\n" % GPA3.get("1.0", END))
app = Tk()
app.title('Student Grade Report')
gpa1=str(GPA1.get())
gp1=float(gpa1)
gpa2=str(GPA2.get())
gp2=float(gpa2)
gpa3=str(GPA3.get())
gp3=float(gpa3)
gpa4=str(GPA4.get())
gp4=float(gpa4)
gpa5=str(GPA5.get())
gp5=float(gpa5)
gpas=gp1+gp2+gp3+gp4+gp5
avg=gpas/5
def DisplayMsg():
DL=str("Dean's list")
AP=str("Academic Probation")
note=("No Message")
if (avg>3.5):
note=DL
elif (avg<2.0):
note=AP
return str(note)
def main():
app = Tk()
app.title('Student Grade Report')
classi = StringVar()
classi.set(None)
Label(app, text = "Classification:").pack()
Classification = StringVar()
Classification.set(None)
Radiobutton(app, variable = classi, text = "freshman", value = "freshman").pack()
Radiobutton(app, variable = classi, text = "sophmore", value = "sophmore").pack()
Radiobutton(app, variable = classi, text = "junior", value = "junior").pack()
Radiobutton(app, variable = classi, text = "senior", value = "senior").pack()
Gpa1 = None
Label(app, text = "GPA1:").pack()
GPA1= StringVar()
GPA1.set(None)
GPA1= Entry(app,textvariable = Gpa1).pack()
Label(app, text = "GPA2:").pack()
GPA2= StringVar()
GPA2.set(None)
GPA2 = Entry(app)
Label(app, text = "GPA3:").pack()
GPA3= StringVar()
GPA3.set(None)
GPA3= Entry(app)
Label(app, text = "GPA4:").pack()
GPA4= StringVar()
GPA4.set(None)
GPA4= Entry(app)
Label(app, text = "GPA5:").pack()
GPA5= StringVar()
GPA5.set(None)
GPA5= Entry(app)
Button(app, text= "Message", command = DisplayMsg).pack()
Button(app, text = "Save", command = save_data).pack()
app.mainloop()
main()
NOTE: Sorry! I added a NOTE to the original post, instead of my answer. Here's the correct note: You are not done yet! There are still issues to be resolved. Eg. The fileD.write won't work if you don't open the file first.
You need to fix all the problems described in jcoppens' very thorough answer, but the actual problem you're asking about is another one, that you also need to fix. (I'm assuming that your actual indentation and structure looks like what he's guessed in his answer. If this doesn't apply to your actual code… well, it applies to the code in his answer, which your code will hopefully be a lot like once you fix all the other problems.)
Inside save_data, you do this:
fileD.write("%s\n" % GPA1.get())
But there's no global variable named GPA1, and no local variable inside that function named GPA1.
There is a local variable inside main with that name, but that doesn't help; the whole point of local variables is that they're local—the only live inside one function.
You could fix this by making GPA1 global, by just adding global GPA1 to the top of your main function. This is the quickest solution, but usually not the best.
A better solution is to create a class, and make GPA1 an attribute of that class. Whichever Tkinter docs or tutorial you're using will probably have lots of good examples of this.
You could also change save_data to take GPA1 as a parameter, and then use functools.partial(save_data, GPA1) instead of just save_data, as a callback.
Or you could put all of these functions inside another function and make GPA1 a nonlocal variable instead of a global one. (I wouldn't recommend this, just including it for completeness…)
Of course whatever you do, you need to do the same for GPA2 or you'll just get the same error again two lines later.
Needless to say, there's no guarantee this is the last bug in your program.
The piece of code below takes input from user through a form and then returns the input as multiplied by 2. What I want to do is, when a user types a number (for example 5) and presses the "Enter" key on keyboard or clicks on "Calculate" button, the place where he entered the number "5" should also display 10, besides the place immediately below. Normally, the form keeps the number entered , but the place right below it gets updated and displays 10 (let us say you have entered 5)
How can I also update the form place?
(Please let me know if my question is unclear, so I can better explain myself.)
from tkinter import *
def multiplier(*args):
try:
value = float(ment.get())
result.set(value * 2)
except ValueError:
pass
mGui = Tk()
mGui.geometry("300x300+300+300")
ment = StringVar()
result = StringVar()
mbutton = Button (mGui, text = "Calculate", command = multiplier)
mbutton.pack()
mEntry = Entry(mGui, textvariable = ment, text="bebe")
mEntry.pack()
mresult = Label(mGui, textvariable = result)
mresult.pack()
You can use Entry's delete and insert methods.
from tkinter import *
def multiplier(*args):
try:
value = float(ment.get())
res = value *2
result.set(res)
mEntry.delete(0, END) #deletes the current value
mEntry.insert(0, res) #inserts new value assigned by 2nd parameter
except ValueError:
pass
mGui = Tk()
mGui.geometry("300x300+300+300")
ment = StringVar()
result = StringVar()
mbutton = Button (mGui, text = "Calculate", command = multiplier)
mbutton.pack()
mEntry = Entry(mGui, textvariable = ment, text="bebe")
mEntry.pack()
mresult = Label(mGui, textvariable = result)
mresult.pack()
The StringVars you update via the set method, which you're doing in the multiplier function. So you question is how to trigger the call the multiplier when the user presses enter, you can use:
mGui.bind('<Return>', multiplier)
Do you also want to change the text in the Entry? The question is a bit unclear. You can do that via ment.set as well.
I'm tring to put some drop down list on a graphic interface I'm building.
I've found the following code for a drop down list, but I'm not able to adapt it to my code.
from Tkinter import *
def print_it(event):
print var.get()
root = Tk()
var = StringVar()
var.set("a")
OptionMenu(root, var, "a","b","c", command=print_it).pack()
root.mainloop()
This is my code, it's quite simple what I've done so far. A menu shows up, it asks for how many (n) components does the users want to enter, and it shows n options to entry. The code above shows 'blank' entrys after you put the desired number of components. I want to replace those three blank entrys with three drop down list.
It's marked when I want to put those dropdown lists.
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
class Planificador:
def __init__(self,master):
master.title("Planificador")
self.frameOne = Frame(master)
self.frameOne.grid(row=0,column=0)
# Logo
self.imgLabel = Label(self.frameOne, image = None)
self.imgLabel.grid(row=0,column=0)
self.img = ImageTk.PhotoImage(file = "logo.png")
self.imgLabel["image"] = self.img
self.botones()
def botones(self):
self.piezastext = Label(self.frameOne, text = " number of components ", justify="center")
self.piezastext.grid(row=1, column=0)
self.entrypiezas = Entry(self.frameOne,width=5)
self.entrypiezas.grid(row=2, column=0)
self.aceptarnumpiezas = Button(self.frameOne,text="Aceptar", command=self.aceptar_piezas,width=8)
self.aceptarnumpiezas.grid(row=6, column=0)
def aceptar_piezas(self):
num_piezas = self.entrypiezas.get()
print num_piezas
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
n = 1;
while n <= int(num_piezas):
self.textopieza = Label(self.frameOne, text = "Pieza", justify="left")
self.textopieza.grid(row=n, column=0)
// INSTEAD THESE 'n' BLANK ENTRYS, I WANT TO PUT 'n' DROP DOWN LISTS
self.entrypiezas = Entry(self.frameOne,width=5)
self.entrypiezas.grid(row=n, column=1)
self.aceptarpiezas = Button(self.frameOne,text="Aceptar",width=8)
self.aceptarpiezas.grid(row=int(num_piezas)+1, column=0)
n += 1
# Main
if __name__ == "__main__":
# create interfacE
root = Tk()
movieApp = Planificador(root)
root.mainloop()
So I want to know how can I put that drop down list on a given frame, frameOnein my case, instead of a full window. Thanks in advance.
I modified your aceptar_piezas function to do what I think you want:
def aceptar_piezas(self):
num_piezas = self.entrypiezas.get()
print num_piezas
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
# Create a list of tuples to hold the dynamically created Optionmenus
# The first item in the tuple is the menu, the second is its variable
self.optionmenus = list()
n = 1
while n <= int(num_piezas):
self.textopieza = Label(self.frameOne, text = "Pieza", justify="left")
self.textopieza.grid(row=n, column=0)
# Variable for the Optionmenu
var = StringVar()
# The menu
menu = OptionMenu(self.frameOne, var, "a","b","c")
menu.grid(row=n, column=1)
# Set the variable to "a" as default
var.set("a")
# Add the menu to the list of Optionmenus
self.optionmenus.append((menu, var))
n += 1
def clicked():
"""This function was made just to demonstrate. It is hooked up to the button"""
for optionmenu in self.optionmenus:
print optionmenu[1].get()
print self.optionmenus
# This button doesn't need to be in the while loop
self.aceptarpiezas = Button(self.frameOne, text="Aceptar", command=clicked, width=8)
self.aceptarpiezas.grid(row=int(num_piezas)+1, column=0)
The tuples in the list are in the order that the Optionmenus were created. So, the first tuple contains the data for the first Optionmenu, the second for the second, and so forth.