Saving variables from entry widgets - python

I want to have the text input of this entry box save to a list and then be printed. I cannot have it save the input upon the button press and it just prints the placeholder variable.
names = []
from tkinter import*
class Trip:
def __init__(self, parent):
E_name = "q"
self.En_name = "g"
self.En_name = str(self.En_name)
self.go = Frame(parent, width = 500, height = 450, bg = "snow", pady = 30, padx = 10)
self.go.grid(row = 1, column = 0)
self.go.grid_propagate(0) # to reserve space required for frame
self.tet = Frame(parent, width = 500, height = 450, bg = "snow")
name = Label(self.go, text = "Name:", bg = "snow")
name.grid(row = 1, column = 0, sticky = E)
self.E_name = Entry(self.go, width = 40, textvariable = self.En_name)
self.E_name.grid(row = 1, column = 1, sticky = W, pady = 4)
menuButton = Button(self.go, text = "Continue", command = self.breakeverything)
menuButton.grid(row = 8, column = 1, pady = 4)
def breakeverything(self):
names.append(self.En_name)
print (names[0])
self.E_name.delete(0, "end")
#main routine
if __name__ == "__main__":
root = Tk()
root.title("Traveller Details")
play = Trip(root)
root.geometry("500x450+0+0")
root.mainloop()

A textvariable is supposed to be a tkinter.StringVar(), not a primitive string. Your application looks simple enough that it shouldn't even need it. Take out self.En_name, take out the textvariable, and just retrieve the current value of the Entry widget in breakeverything() (which should no longer be an appropriate name):
def breakeverything(self):
names.append(self.E_name.get())
print(names[-1]) # printing the last name in the list seems more useful
self.E_name.delete(0, "end")
I would also recommend moving names into Trip.__init__ and making it an instance variable like everything else, with self.names = []. It'll make it easier to keep track of scopes.

You're using textvariable incorrectly (you must use one of the special Tkinter variables such as StringVar), but you don't need to use it at all. Simply save a reference to the widget, then call the get method when you want the value:
self.E_name = Entry(self.go, width = 40)
...
print("you entered: " + self.E_name.get())
If you insist o using textvariable, use a StringVar and then call the get method on that instead:
self.En_name = StringVar()
self.E_name = Entry(..., textvariable=self.En_name)
...
print("you entered: " + self.En_name.get())

Related

Python Tkinter: object has no attribute tk

I am new to tkinter, python, and programming in general. I have made an example program of what I'm trying to do. I am trying to use tkinter GUI to receive user inputs for date and time, then convert these tk entries into strings, then check the format of the date and time strings, then if the format is good add the date and time to a list. My issue is with converting the tk entries into strings. When I try to do so I receive an error that says "Example object has no attribute tk". In my program, I have a tk window that is made in my UserInputWindow function, and I pass this window to PromptDateTime, which is where the user is prompted to enter a date and time. When I try to convert using "dateFromUser = tk.Entry(self)", this is the part that receives the error. I don't understand why the PromptDateTime function had no problem editing the window from UserInputWindow function, yet when tk is directly referenced there is an issue.
Also: I had some trouble with formatting my code below (new to stack overflow) so please note that the first section of code is part of "class Example()", and the second section of code is the main function.
Thank you for your help! Please be nice! I'm a newbie and open to critiques.
class Example():
#data members
__dateEntry = None
__timeEntry = None
exampleList = []
def UserInputWindow(self, windowName, instruction):
#Create new window to display fields and options
new_window = tk.Tk()
new_window.title(f'{windowName}')
new_window.geometry = ("500x500")
#Label to display instructions
label_instruction = Label(new_window, text = (f'{instruction}'), font = ("Courier", 10), justify = LEFT, fg = "black", bg = "light yellow")
label_instruction.grid(row = 0, column = 0)
return new_window
#this function checks to see if date string from user is in proper format, and if it is not an error window appears.
def VerifyDate(self, d):
#code deleted for simplicty for this example
#this function checks to see if time string from user is in proper format, and if it is not an error window appears.
def VerifyTime(self, t):
#code deleted for simplicty for this example
#this function prompts user for date and time
def PromptDateTime(self, new_window):
#Label to display instructions
label_instruction = Label(new_window, text = "Enter activity date and time: ",font = ("Courier", 10), justify = LEFT, fg = "black", bg = "light yellow")
label_instruction.grid(row = 0, column = 0)
#Create labels and entries for date and time
label_date = Label(new_window, text = "Enter date in MM/DD/YYYY format: ",fg = "black", bg = "white")
label_date.grid(row = 1, column = 0, padx = 5)
dateEntry = Entry(new_window, fg = 'black', bg = 'white', width = 10)
dateEntry.grid(row = 2, column = 0, padx = 5)
dateFromUser = tk.Entry(self)
str(dateFromUser)
label_time = Label(new_window, text = "Enter time in hh:mm format (military time): ",fg = "black", bg = "white")
label_time.grid(row = 3, column = 0, padx = 5)
timeEntry = Entry(new_window, fg = 'black', bg = 'white', width = 10)
timeEntry.grid(row = 4, column = 0, padx = 5)
self.VerifyDate(dateFromUser)
self.VerifyTime(timeEntry)
def SubmitButton(self, new_window, new_command):
button_submit = Button(new_window, fg = "black", bg = "light blue", text = "Submit", command = new_command)
button_submit.grid(row = 17, column = 10, pady = 5)
def PromptAndAddToList(self):
window = self.UserInputWindow('Date and Time', 'Enter date and time as specified below.')
self.PromptDateTime(window)
self.SubmitButton(window, lambda:exampleList.append(otherClass(dateEntry, timeEntry)))
#################################################
if __name__ == '__main__':
from tkinter import *
import tkinter as tk
import datetime
ex = Example()
ex.PromptAndAddToList()
root = tk.Tk()
root.withdraw()
root.mainloop()
As the error said, the parent of dateFromUser is Example:
dateFromUser = tk.Entry(self) # self is instance of class Example
but Example is not a tkinter widget.
Use new_window instead of self:
dateFromUser = tk.Entry(new_window)

Make an Entry When a Checkbox is Unchecked in Tkinter

I have a check button that is checked by default. If the user unchecks it, a label and an entry should appear. I tried to do so by using the key binding method; however, it has a drawback which is that if the user checks the checkbox again, the new label and entry won't disappear. How do I solve that problem?
checkButtonVar = IntVar(value = 1)
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar)
labelIsChanceDefault = Label(root, text="Make chance = 0.9?")
labelIsChanceDefault.grid(row=3, column = 0, sticky = 'w')
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
def checkCheckButton(event):
labelChance = Label(root, text = "Enter chance of winning")
labelChance.grid( row = 3, column = 2)
global entryChance
entryChance = Entry(root, borderwidth = 3)
entryChance.grid(row = 3, column = 3)
checkButtonIsChnaceDefault.bind('<Button-1>', checkCheckButton)
Here's a screenshot of the program to make things clear.
You don't need to bind the Check-button. Use command option. And setting offvalue and onvalue can control the appearance.
See the tkinter.Checkbutton
checkButtonVar = IntVar()
checkButtonIsChnaceDefault = Checkbutton(root, variable = checkButtonVar,offvvalue=0,onvalue=1,command=checkCheckButton)
...
checkButtonIsChnaceDefault.grid(row = 3, column = 1)
#==== Define the widgets here.
labelChance = Label(root, text = "Enter chance of winning")
entryChance = Entry(root, borderwidth = 3)
def checkCheckButton():
if checkButtonVar.get()==0:
labelChance.grid( row = 3, column = 2)
entryChance.grid(row = 3, column = 3)
else:
labelChance.grid_forget()
entryChance.grid_forget()

Python Tkinter. How to store entry via button in label

I really need help with some code. I don't expect you to write it for me, since it is a school project, but I am just really lost and need help.
The code I am writing is some sort of production system.
It doesn't need to actually be able to send a task anywhere, since this is just an imagined scenario.
The code has to consist of three files: data.py, model.py and gui.py.
Gui can access the two other files
Data can only access model
Model can't access either of the other two.
My teacher had written some of the code witch I have continued on. Some of the text is in danish, but most comments are in English.
The code is as follows.
data.py
from model import *
class Data(object):
def __init__(self):
self.units = []
self.finished_tasks = []
def __str__(self):
result = "These tasks have been finished: "
for i in self.finished_tasks:
result += str(i)
return result
def task_done(self, unit):
done_task = unit.task_done()
if done_task != None:
#TODO: add to list of finished tasks
pass
def add_task(self, name, amount, unit):
s = Springroll_task(name, amount)
unit.add_to_queue(s)
def read_from_database(self):#doesn't actually read from db..
self.units.append(Production_unit("maskine1"))
self.units.append(Production_unit("maskine2"))
self.add_task("Miniruller", 100, self.units[0])
self.add_task("Maxiruller", 200, self.units[0])
self.add_task("HowIRoll", 3000, self.units[0])
self.add_task("RulleMarie", 40, self.units[1])
self.add_task("Rullesten", 500, self.units[1])
self.add_task("Toiletpapirsruller", 6000, self.units[1])
model.py
class Springroll_task(object):
def __init__(self, name, amount):
self.name = name
self.amount = amount
def __str__(self):
return self.name + " " + str(self.amount)
class Production_unit(object):
def __init__(self, amount={}, name={},):
#name of the production unit
self.name = name
self.amount = amount
#the current task
self.current_task = None
#the tasks in the queue
self.springroll_queue = []
#the size of the queue
self.queue_size = 0
def __str__(self):
#TODO
return self.name + " " + str(self.amount)
def add_to_queue(self, task={}):
if self.current_task == None:
self.current_task = task
else:
self.springroll_queue.append(task)
self.queue_size += 1
#remember to update queue_size
pass
def task_done(self):
#TODO: remember the old current task.
#Set the current task to be the first in the queue (and remove from queue)
# - if there is a task in the queue.
#return the old current task.
#remember to update queue_size
self.queue_size -= 1
pass
gui.py
from tkinter import *
from model import *
from data import Data
class Application(Frame):
def __init__(self, master, unit):
self.mod = Production_unit()
super(Application, self).__init__(master)
self.grid()
self.unit = unit
self.create_widgets()
def create_widgets(self):
self.unit_name_lbl = Label(self, text = self.unit.name)
self.unit_name_lbl.grid(row = 0, column = 0, columnspan = 2, sticky = W)
self.cur_prod_lbl = Label(self, text = "produktion nu: ")
self.cur_prod_lbl.grid(row = 1, column = 0, columnspan = 2, sticky = W)
self.prod_lbl = Label(self, text = "produkt")
self.prod_lbl.grid(row = 2, column = 0, sticky = W)
self.amount_lbl = Label(self, text = "antal")
self.amount_lbl.grid(row = 2, column = 1, sticky = W)
#Label for production now
self.amount1_lbl = Label(self, text = " ", bg ="red")
self.amount1_lbl.grid(row = 3, column = 0, sticky = W)
self.amount2_lbl = Label(self, text = " ", bg ="red")
self.amount2_lbl.grid(row = 3, column = 1, sticky = W)
#Button for task finished
self.finished_but = Button(self, text = "Opgave afsluttet", bg ="pink", command=self.mod.task_done)
self.finished_but.grid(row = 3, column = 2, sticky = W)
#Label for queue
self.queue_lbl = Label(self, text = "Kø")
self.queue_lbl.grid(row = 4, column = 0, sticky = W)
#Label for production queue
for i in range(0,3):
self.name_lbl =Label(self, text = self.mod.springroll_queue, bg="red", width= 6)
self.name_lbl.grid(row = 5+i, sticky = W)
for j in range(0,3):
self.qt_lbl =Label(self, text = self.mod.springroll_queue, bg="red", width= 4)
self.qt_lbl.grid(row = 5+j, column = 1)
self.new_lbl = Label(self, text = "Ny")
self.new_lbl.grid(row = 10, column = 0, sticky = W)
#Entry for entries
self.eq1_ent = Entry(self, text = "", width=6)
self.entry_name = self.eq1_ent.get()
self.eq1_ent.grid(row = 11, sticky = W)
self.ea1_ent = Entry(self, text = "", width=4)
self.ea1_ent.grid(row = 11, column = 1, sticky = W)
#Button for add to queue
self.add_but = Button(self, text = "Tilføj til kø", bg ="pink", command=self.mod.add_to_queue(self.ea1_ent.get()))
self.add_but.grid(row = 11, column = 2, sticky = W)
def done(self):
d.task_done(self.unit)
self.redraw()
def add(self):
n = "Nyt navn" #read from gui
a = "Nyt antal" #read from gui
d.add_task(n, a, unit)
self.redraw()
def redraw(self):
#TODO
pass
# main
root = Tk()
root.title("Daloon")
root.geometry("300x300")
d = Data()
d.read_from_database()
p = d.units[0]
app = Application(root, p)
root.mainloop()
So it currently looks like this:
What I need to be able to do is to take an input in the bottom two entry widgets and put them in one of the 4 label widgets above, beginning from the top and then in the queue afterwards, this should happen when I press the button add_but, which seems to be gone currently.
After that I need the task stored in the data file when the "Opgave afsluttet" button is pressed.
I really hope someone is able to help me!
I edited it with some suggestions, and am calling the right self.eq1_ent.get() now, I think. I dont get any error any longer, now I just don't really know how to make it do what I want.
Edit 2: I am slowly getting some stuff, so i have made changes in the model.py and gui.py...
It looks like this now:
self.eq1 is not defined. you have self.q1_lbl and self.eq1_ent.
To access the label use self.q1_lbl.
To be able to set text to your label create them as following:
self.var = StringVar()
self.unit_name_lbl = Label(self, textvariable=self.var)
For example, from redraw() you can set 'text' to self.unit_name_lbl like this : self.var.set('text').
Check if you missed self in d.add_task(n, a, unit)
When you do command=mod.add_to_queue(self.ea1_ent.get()) the mod.add_to_queue function will be called directly, if you want to pass argument to this function when user press the button, you can use lambda:
command=lambda: mod.add_to_queue(self.ea1_ent.get)

Tkinter Spinbox textvariable argument has no effect. Is there something I missed?

I've defined a class with a 'bpm' attribute:
class Section:
def __init__(self, id, bpm, bars, reps, num_tracks):
self.id = id
self.bpm = bpm
self.bars = bars
self.reps = reps
self.num_tracks = num_tracks
then I call the attribute to use it as the textvariable argument on a spinbox, once I've created an instance of my Section class, inside a dictionary:
def add_section():
new_id = next(itertools.count(1))
sections[new_id] = Section(new_id, 120, 1, 2, 1)
print((str(sections[new_id].bpm)))
sections[new_id].label_section_title = Label(root, text="Section {}".format(sections[new_id].id, relief = GROOVE))
sections[new_id].label_section_title.grid(row = 1, column = 4, columnspan = 5)
sections[new_id].label_bpm = Label(root, text="BPM: ")
sections[new_id].label_bpm.grid(row = 2, column = 4)
sections[new_id].bpm_control = Spinbox(root, from_ = 1, to = 999, textvariable = sections[new_id].bpm, command = lambda: sections[new_id].bpm_change(sections[new_id].bpm_control.get()))
sections[new_id].bpm_control.grid(row = 2, column = 5)
I'm able to print the value of sections[new_id].bpm as 120, so I know that works.
But even though I am setting textvariable on the spinbox, I'm just getting a value of 1 on the spinbox when I'd like it to be the 120 from the new instance. Even if I just set textvariable to straight up 120 I still just get a 1 there.
You need to set it as a IntVar() to use
self.bpm = IntVar()
self.bpm.set(bpm) # set value passed in
When getting the value from your spinbox you get either use Spinbox.get() which will return a string of the current value or self.bpm.get() which will be an int value

Getting Input from Radiobutton

I am using a mix of Tkinter and graphics.py (a wrapper on Tkinter) to create a fairly basic integrator (find the area under a graph) with a GUI. As of now, the main "control panel" for the integrator is separate from the actual graph (which is made by using graphics.py). I am using Tkinter's Radiobutton() for the choice selection of the integration type (Left Rectangular, Right Rectangular, Trapezoidal, or Simpson's Approximation).
My problem is that I am unable to get the output from the radiobuttons. I was using the example from TutorialsPoint: Tkinter Radiobutton.
Here is my code:
class FunctionInput:
def __init__(self, master, window, items):
self.window = window
self.items = items
self.runProgram = True
self.typeChoice = tk.StringVar()
self.frame = tk.Frame(master)
self.typeFrame = tk.Frame(self.frame)
self.quitButton = tk.Button(self.frame, text = 'Quit', command = self.frame.quit)
self.optLabel = tk.Label(self.frame, text = 'Type of Approximation: ')
self.optL = tk.Radiobutton(self.typeFrame, text = 'Left Rectangular', variable = self.typeChoice, value = 'l')
self.optR = tk.Radiobutton(self.typeFrame, text = 'Right Rectangular', variable = self.typeChoice, value = 'r')
self.optT = tk.Radiobutton(self.typeFrame, text = 'Trapezoidal', variable = self.typeChoice, value = 't')
self.optS = tk.Radiobutton(self.typeFrame, text = 'Simpsons Rule', variable = self.typeChoice, value = 's')
self.optL.grid(row = 1, column = 1, padx = 5, pady = 5)
self.optR.grid(row = 1, column = 2, padx = 5, pady = 5)
self.optT.grid(row = 2, column = 1, padx = 5, pady = 5)
self.optS.grid(row = 2, column = 2, padx = 5, pady = 5)
self.optLabel.grid(row = 4)
self.typeFrame.grid(row = 5)
self.quitButton.grid(row = 6)
# there were numerous other widgets and frames, but I only included the relevant ones
self.frame.grid()
def getInput(self):
type_integration = self.typeChoice.get()
self.frame.quit()
return type_integration
def main():
# some other code, win and axisLabels are defined prior to this
root = tk.Tk(className = ' Function Grapher')
app = FunctionInput(root, win, axisLabels)
root.rowconfigure(0, weight = 1)
root.columnconfigure(0, weight = 1)
root.mainloop() # there is a button to exit the mainloop in my GUI
typeIntegration = app.getInput()
print typeIntegration # trying to debug it
if __name__ == '__main__': main()
However, it doesn't not print the variable. It prints an empty string, so execution is not a problem. root.mainloop() does not get stuck in an infinite loop, because I have a button in my GUI (not shown here because it is irrelevant) that exits it. An error is not raised, so I'm guessing that the issue is with setting the option to the variable. Any help is greatly appreciated.
Also, on a side note, whenever I run the program, the 'Right Rectangular', 'Trapezoidal', and 'Simpson's Rule' radiobuttons are grayed out, like such:
This grayness goes away if I click on one of the radiobuttons, but until then, it stays. If there is some way to fix this, please let me know.
Thanks!
I haven't seen the part of the exit button, but your code does something like this:
Starts the mainloop
The event handler of the exit button calls root.quit()
In getInput, retrieves the value and calls self.frame.quit()
Calling Tkinter functions after the mainloop may lead to problems like this, so you should get the value of the StringVar first and then exit the GUI loop. This is a working example based on your code:
import Tkinter as tk
class App():
def __init__(self, master):
self.master = master
self.type_integration = None
self.typeChoice = tk.StringVar()
self.typeChoice.set(None) # This fixes the grayness of the radio buttons!
self.typeFrame = tk.Frame(master)
OPTIONS = [('Left Rectangular', 'l'),
('Right Rectangular', 'r'),
('Trapezoidal', 't'),
('Simpsons Rule', 's')]
for text, value in OPTIONS:
tk.Radiobutton(self.typeFrame, text=text, variable=self.typeChoice, value=value).pack()
tk.Button(self.typeFrame, text="Exit", command=self.exit).pack()
self.typeFrame.pack()
def exit(self):
self.type_integration = self.typeChoice.get()
self.master.destroy() # self.master.quit() freezes the GUI
def getinput(self):
return self.type_integration
master = tk.Tk()
app = App(master)
tk.mainloop()
print app.getinput()
The problem was that since I was using multiple other widgets, I had to set StringVar()s master parameter as self.typeFrame:
class FunctionInput:
def __init__(self, master, window, items):
self.window = window
self.items = items
self.runProgram = True
self.frame = tk.Frame(master)
self.typeFrame = tk.Frame(self.frame)
self.typeChoice = tk.StringVar(self.typeFrame)
self.quitButton = tk.Button(self.frame, text = 'Quit', command = self.frame.quit)
self.optLabel = tk.Label(self.frame, text = 'Type of Approximation: ')
self.optL = tk.Radiobutton(self.typeFrame, text = 'Left Rectangular', variable = self.typeChoice, value = 'l')
self.optR = tk.Radiobutton(self.typeFrame, text = 'Right Rectangular', variable = self.typeChoice, value = 'r')
self.optT = tk.Radiobutton(self.typeFrame, text = 'Trapezoidal', variable = self.typeChoice, value = 't')
self.optS = tk.Radiobutton(self.typeFrame, text = 'Simpsons Rule', variable = self.typeChoice, value = 's')
self.optL.grid(row = 1, column = 1, padx = 5, pady = 5)
self.optR.grid(row = 1, column = 2, padx = 5, pady = 5)
self.optT.grid(row = 2, column = 1, padx = 5, pady = 5)
self.optS.grid(row = 2, column = 2, padx = 5, pady = 5)
self.optLabel.grid(row = 4)
self.typeFrame.grid(row = 5)
self.quitButton.grid(row = 6)
# there were numerous other widgets and frames, but I only included the relevant ones
self.frame.grid()
def getInput(self):
type_integration = self.typeChoice.get()
self.frame.quit()
return type_integration
def main():
# some other code, win and axisLabels are defined prior to this
root = tk.Tk(className = ' Function Grapher')
app = FunctionInput(root, win, axisLabels)
root.rowconfigure(0, weight = 1)
root.columnconfigure(0, weight = 1)
root.mainloop() # there is a button to exit the mainloop in my GUI
print app.getInput()
if __name__ == '__main__': main()
Also, as #A. Rodas said, to get rid of the grayness, I did:
self.typeFrame = tk.Frame(self.frame)
self.typeChoice = tk.StringVar(self.typeFrame)
self.typeChoice.set(None)

Categories