I am trying to change a label automatically in python, I want it to change every half a second, this is my code for tkinter, the function being called (that is being put into "message") returns a new string every half a second, what am I doing wrong?
import Tkinter as tk
class Application(tk.Frame):
def __init__(self):
self.root = tk.Tk()
self.root.geometry("150x136")
tk.Frame.__init__(self, self.root)
self.create_widgets()
def create_widgets(self):
self.root.bind('<Return>', self.parse)
self.grid()
self.instruction = tk.Label(self, text = "QuickReader")
self.instruction.grid(row = 0, column = 0, columnspan = 4)
self.entry = tk.Entry(self)
self.entry.grid(row = 2, column = 0)
self.submit = tk.Button(self, text="Submit")
self.submit.bind('<Button-1>', self.parse)
self.submit.grid(row = 4, column = 0)
self.words = tk.Label(self, text = "Start")
self.words.grid(row = 5, column = 0, columnspan = 4)
def parse(self, event):
filename = self.entry.get()
message = open_txt(filename)
self.words.set(message)
def start(self):
self.root.mainloop()
Application().start()
To change label text, use one of following:
self.words.config(text=message)
self.words.configure(text=message)
self.words['text'] = message
http://effbot.org/tkinterbook/label.htm
You can associate a Tkinter variable with a label. When the contents of the variable changes, the label is automatically updated:
v = StringVar()
Label(master, textvariable=v).pack()
v.set("New Text!")
So, that should be pretty easy to implement.
Related
I have two sets of code. One works the other doesn't and I don't know why. In the first set of code I am storing my application into a class and referencing everything there. In the second one I am storing everything in the main function and using it there.
The main details of the problem are here:
I am using a entry widget and a button widget which is initially disabled. I want the button's state to be normal when there is text in the entry widgets text field.
I have searched online for many answers to the first set of code but the closest I have gotten is the second set of code. First I tried to integrate it into my code however that did not work. So what I did was take the code and strip it to the bare minimum and put everything into the main function.
The main difference between the two is one is in a class and the other is in the main function.
import tkinter as tk
class Aplication(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
self.grid()
self.button_clicks = 0
something = tk.StringVar()
button3 = tk.Button(self, text="Print entry", padx = 10, height = 2, bg = "blue", state = "disabled")
entry = tk.Entry(self, textvariable = something)
something.trace('w', self.ActivateButton) #need this to always be exsecuted
entry.grid(column = 2, row = 1)
button3["command"] = lambda: self.PrintEntry(entry.get())
button3.grid(padx = 10, pady = 10)
def PrintEntry (self, entry):
print(entry)
def ActivateButton(self, *_):
if something.get():
button3['state'] = "normal"
else:
button3['state'] = "disabled"
if __name__ == '__main__':
top= tk.Tk()
top.title("Simple Button")
top.geometry("500x300")
app = Aplication(top)
top.mainloop()
def PrintEntry (entry):
print(entry)
def ActivateButton(*_):
if entry.get():
button3['state'] = "normal"
else:
button3['state'] = "disabled"
if __name__ == '__main__':
top= tk.Tk()
top.title("Simple Button")
top.geometry("500x300")
something = tk.StringVar()
button3 = tk.Button(top, text="Print entry", padx = 10, height = 2, bg = "blue", state = "disabled")
entry = tk.Entry(top, textvariable = something, bd = 2)
something.trace('w', ActivateButton)
entry.grid(column = 2, row = 3)
button3["command"] = lambda: PrintEntry(entry.get())
button3.grid(row = 3, column = 1, padx = 10, pady = 10)
top.mainloop()
There are no error messages; however you will find in the first set, the button's state never gets set to normal. Is there a way to do this for the first one? What is the difference between the two that makes it to where I can't enable the button in the first one if it is impossible?
You have to use self. to create class variables so they will be accesible in all methods in class. Currently you create local variable something in __init__ and it is deleted when Python ends __init__ - so finally it removes something.trace() and it doesn't check value in entry.
In this code I use self.something and self.button3 and it works correctly.
import tkinter as tk
class Aplication(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
self.grid()
self.button_clicks = 0
self.something = tk.StringVar()
self.button3 = tk.Button(self, text="Print entry", padx = 10, height = 2, bg = "blue", state = "disabled")
entry = tk.Entry(self, textvariable = self.something)
self.something.trace('w', self.ActivateButton) #need this to always be exsecuted
entry.grid(column = 2, row = 1)
self.button3["command"] = lambda: self.PrintEntry(entry.get())
self.button3.grid(padx = 10, pady = 10)
def PrintEntry (self, entry):
print(entry)
def ActivateButton(self, *_):
if self.something.get():
self.button3['state'] = "normal"
else:
self.button3['state'] = "disabled"
if __name__ == '__main__':
top= tk.Tk()
top.title("Simple Button")
top.geometry("500x300")
app = Aplication(top)
top.mainloop()
EDIT: the same little different - without lambda. I use self.entry (as class variable) directly in print_entry.
import tkinter as tk
class Aplication(tk.Frame):
def __init__(self, master):
super().__init__(master)#tk.Frame.__init__(self,master)
self.grid()
self.button_clicks = 0
self.something = tk.StringVar()
self.entry = tk.Entry(self, textvariable=self.something)
self.entry.grid(column=2, row=1)
self.button3 = tk.Button(self, command=self.print_entry, text="Print entry", padx=10, height=2, bg="blue", state="disabled")
self.button3.grid(padx=10, pady=10)
self.something.trace('w', self.activate_button) #need this to always be exsecuted
def print_entry(self):
print(self.entry.get())
def activate_button(self, *_):
if self.something.get():
self.button3['state'] = "normal"
else:
self.button3['state'] = "disabled"
if __name__ == '__main__':
top= tk.Tk()
top.title("Simple Button")
top.geometry("500x300")
app = Aplication(top)
top.mainloop()
As pointed out by #furas you need to prefix your variables in the constructor method def __init__ with self. so you can access attributes and methods since it literally represents an instance of the class. This link explains it in more detail https://stackoverflow.com/a/2709832/7585554.
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.grid()
self.button_clicks = 0
self.something = tk.StringVar()
self.button3 = tk.Button(self, text="Print entry", padx=10, height=2, bg="blue", state="disabled")
self.entry = tk.Entry(self, textvariable=self.something)
self.something.trace('w', self.ActivateButton)
self.entry.grid(column=2, row=1)
self.button3["command"] = lambda: self.PrintEntry()
self.button3.grid(padx=10, pady=10)
def PrintEntry (self):
print(self.entry.get())
def ActivateButton(self, *_):
if self.something.get():
self.button3['state'] = "normal"
else:
self.button3['state'] = "disabled"
if __name__ == '__main__':
top = tk.Tk()
top.title("Simple Button")
top.geometry("500x300")
app = Application(top)
top.mainloop()
I am writing a program that will take skill names as input from text entries and calculate the corresponding value of all of the skills entered. When I enter a skill in the program and then print the skill to the shell it appears as an object? Why does this happen and how can I fix it, do I need a repr or str? Why doesn't the delete method to clear the text entry work as well?
import tkinter as tk
from tkinter import ttk
#make the lists to store the skill names
floorEle1Skills = []
class startValue(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Start Value Calculator")
tk.Tk.minsize(self, width = 350, height = 300)
container = tk.Frame(self)
container.pack(side = 'top', fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for f in (startPage, floorPage, pommelPage, ringsPage, vaultPage, pbarsPage, hbarPage):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.showFrame(startPage)
#make the lists to store the skill names
floorEle1Skills = []
def showFrame(self, cont):
frame = self.frames[cont]
frame.tkraise()
def floorEle1(skill):
floorEle1Skills.append(skill)
#clear the text entry
#ele1Entry.delete(0, tk.END)
#why doesnt this work???
#why is it printed as an object??
print(floorEle1Skills)
class startPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Select Event")
label.pack(pady = 10, padx = 10)
floorButton = ttk.Button(self, text = "Floor", command = lambda : controller.showFrame(floorPage))
floorButton.pack()
class floorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Floor")
label.pack(pady = 10, padx = 10)
#make the entries and labels
ele1Label = tk.Label(self, text = "Element Group 1:")
ele1Label.pack()
skill1 = tk.StringVar()
ele1Entry = tk.Entry(self, textvariable = skill1)
ele1Entry.pack()
ele1Button = ttk.Button(self, text = "Add", command = lambda : controller.floorEle1())
ele1Button.pack()
startButton = ttk.Button(self, text = "Back to Start", command = lambda : controller.showFrame(startPage))
startButton.pack(side = 'bottom')
Welcome to Python. The problem is in the function floorEle1(skill). This is a member function of class startValue, but the argument list doesn't begin with self. Python doesn't force you to name the first variable self; you can actually name it whatever you want (but don't do it!). So within this function the variable named skill acts just like the variable self.
It's exactly as if you had written this:
def floorEle1(self):
floorEle1Skills.append(self)
#clear the text entry
#ele1Entry.delete(0, tk.END)
#why doesnt this work???
#why is it printed as an object??
print(floorEle1Skills)
I think you can see now that your code, in effect, appends self to floorEle1Skills; i.e., you append the instance of your main window! So when you print the list, the print statement shows that the list contains an object.
As already mentioned in the another answer the problem with the code turns around the function floorEle1(self, skill), BUT ... there are also some other issues that should be properly addressed in order to get the entered skills passed to the list of skills (see code below):
import tkinter as tk
from tkinter import ttk
#make the lists to store the skill names
# floorEle1Skills = []
class startValue(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Start Value Calculator")
tk.Tk.minsize(self, width = 350, height = 300)
container = tk.Frame(self)
container.pack(side = 'top', fill = 'both', expand = True)
container.grid_rowconfigure(0, weight = 1)
container.grid_columnconfigure(0, weight = 1)
self.frames = {}
for f in (startPage, floorPage): # , pommelPage, ringsPage, vaultPage, pbarsPage, hbarPage):
frame = f(container, self)
self.frames[f] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.showFrame(startPage)
#make the lists to store the skill names
self.floorEle1Skills = []
def showFrame(self, cont):
self.floorEle1Skills = []
frame = self.frames[cont]
frame.tkraise()
def floorEle1(self, skill):
print("#", skill.get())
self.floorEle1Skills.append(skill)
#clear the text entry
#ele1Entry.delete(0, tk.END)
#why doesnt this work???
#why is it printed as an object??
for item in self.floorEle1Skills:
print("##",item.get())
class startPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Select Event")
label.pack(pady = 10, padx = 10)
floorButton = ttk.Button(self, text = "Floor", command = lambda : controller.showFrame(floorPage))
floorButton.pack()
class floorPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Floor")
label.pack(pady = 10, padx = 10)
#make the entries and labels
ele1Label = tk.Label(self, text = "Element Group 1:")
ele1Label.pack()
skill1 = tk.StringVar()
ele1Entry = tk.Entry(self, textvariable = skill1)
ele1Entry.pack()
ele1Button = ttk.Button(self, text = "Add", command = lambda : controller.floorEle1(ele1Entry))
ele1Button.pack()
startButton = ttk.Button(self, text = "Back to Start", command = lambda : controller.showFrame(startPage))
startButton.pack(side = 'bottom')
root = tk.Tk()
my_gui = startValue()
root.mainloop()
Other changes in the code are:
definition of self.floorEle1Skills = [] in the '__ init __()' function and passing the appropriate parameter to controller.floorEle1(ele1Entry) so that the input string value is passed to the function handling the button push.
The above code prints the user input to the terminal (twice, first from the passed user input, second all items in the list).
Placing self.floorEle1Skills = [] line in showFrame() resets the list collecting the input of skills (making restart of input possible).
The code above solves both issues addressed in the question, but this doesn't mean that there are not further issues needing to be solved.
I am writing a calculator program with python, and i keep getting an error message
AttributeError: 'Application' object has no attribute 'response_txt'
from tkinter import *
class Application(Frame):
""" GUI application calculator. """
def __init__(self, master):
""" Initialize the frame. """
super(Application, self).__init__(master)
# Adds the grid layout manager
self.grid()
# The result string
self.response_str = ""
#sets up the controls in the frame
self.create_widgets()
def create_widgets(self):
""" Create and sequence """
#Text Sequence
self.sequence_txt = Text(self, height = 1, width = 30, wrap=WORD)
self.sequence_txt.grid(row = 0, column = 0, columnspan = 2)
# Configure the Text to center
self.sequence_txt.tag_config("center_align", justify='center')
# Configure the Text to center
self.response_txt.tag_config("center_align", justify='center')
###buttons
# Button 1
Button(self,
bg='1',
command = self.one_btn_clicked,
height = 2
).grid(row = 2, column = 0, sticky = NSEW)
#buttons clicked
def one_btn_clicked(self):
"""This method is run when the one button gets clicked"""
#append a 1
self.response_str+="1"
#update text
self.response_txt.delete(0.0, END)
self.response_txt.insert(0.0, self.response_str, "center_align")
#add number
self.compare_sequences();
#main
root = Tk()
root.title("Calculator")
app = Application(root)
root.mainloop()
When i ran this through the module, it gave me this error:
AttributeError: 'Application' object has no attribute 'response_txt'
I tried importing a submodule like this:
`import self.response_txt`
And then it gave me this error message:
ImportError: No module named 'self'
I really need this to work, school assignment due tomorrow. Any ideas are appreciated, I am very new to programming. I am also aware that the program is not really that close to done, but before I can move to any other steps I need to make sure what I did here will work in the first place. Thank you.
You forgot to intitalise self.response_txt. Furthermore, '1' is not a valid argument for bg in the code:
Button(self,
bg='1',
command = self.one_btn_clicked,
height = 2
).grid(row = 2, column = 0, sticky = NSEW)
Corrected code:
from tkinter import *
class Application(Frame):
""" GUI application calculator. """
def __init__(self, master):
""" Initialize the frame. """
super(Application, self).__init__(master)
# Adds the grid layout manager
self.grid()
# The result string
self.response_str = ""
#sets up the controls in the frame
self.create_widgets()
def create_widgets(self):
""" Create and sequence """
#Text Sequence
self.sequence_txt = Text(self, height = 1, width = 30, wrap=WORD)
self.sequence_txt.grid(row = 0, column = 0, columnspan = 2)
self.response_txt = Text(self, height = 1, width = 30, wrap=WORD)
self.response_txt.grid(row = 0, column = 0, columnspan = 2)
# Configure the Text to center
self.sequence_txt.tag_config("center_align", justify='center')
# Configure the Text to center
self.response_txt.tag_config("center_align", justify='center')
###buttons
# Button 1
Button(self,
bg='white',
command = self.one_btn_clicked,
height = 2
).grid(row = 2, column = 0, sticky = NSEW)
#buttons clicked
def one_btn_clicked(self):
"""This method is run when the one button gets clicked"""
#append a 1
self.response_str+="1"
#update text
self.response_txt.delete(0.0, END)
self.response_txt.insert(0.0, self.response_str, "center_align")
#add number
self.compare_sequences();
#main
root = Tk()
root.title("Calculator")
app = Application(root)
root.mainloop()
Also you haven't created compare_sequences function.
I am trying to make an entry widget display beneath a Label using the .grid() function; however, it is simply not showing up. Here is my code:
#demonstrates how to use a class with Tkinter
from Tkinter import *
import tkMessageBox
class Application(Frame):
def __init__(self, master):
""" Initializes the Frame"""
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
self.previous_trans = Text(width = 100, height = 5, wrap = WORD)
self.previous_trans.grid(row = 0, column = 0, columnspan = 2)
self.items = Text(width = 50, height = 16, wrap = WORD)
self.items.grid(row = 1, column = 1, rowspan = 14, sticky = E)
self.additem = Label(text = "Add Item")
self.additem.grid(row = 1)
self.myentry = Entry(self)
self.myentry.grid(row = 2)
root = Tk();
root.title("Work In Progress")
app = Application(root)
root.mainloop();
The reason is because:
you don't specify a row or column for app, so it defaults to 0,0
you don't specify a parent for self.previous_trans so it defaults to the root window -- the same as for the application frame
you explicitly put self.previous_trans in row zero, column zero, which overwrites the label
You need to be giving an explicit parent of self to all of the widgets inside of Application:
self.previous_trans = Text(self, ...)
self.items = Text(self, ...)
self.additem = Label(self, ...)
self.myentry = Entry(self, ...)
I'm trying to add a "Done" button to my program that will print the content of both Entry widgets to a new box. I can get the button to appear, but I can't get the information to show up in a new box. What am I doing wrong?
from Tkinter import *
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.grid()
self._name = StringVar()
self._name.set("Enter name here")
self._age = IntVar()
self._age.set("Enter age here")
top = self.winfo_toplevel() # find top-level window
top.title("Entry Example")
self._createWidgets()
self._button = Button(self,
text = "Done")
self._button.grid(row = 1, column = 0, columnspan = 2)
def _createWidgets(self):
textEntry = Entry(self, takefocus=1,
textvariable = self._name, width = 40)
textEntry.grid(row=0, sticky=E+W)
ageEntry = Entry(self, takefocus=1,
textvariable = self._age, width = 20)
ageEntry.grid(row=1, sticky=W)
def _widget(self):
tkMessageBox.showinfo
# end class Application
def main():
Application().mainloop()
You need to assign an action to your button using command: option.
To get what is written in Entry you need to use get() method.
showinfo you need two arguments, one is the title, the other one is what is going to be shown.
Also you need to import tkMessageBox.
Here is a working example.
import Tkinter as tk
import tkMessageBox
class Example(tk.Frame):
def __init__(self,root):
tk.Frame.__init__(self, root)
self.txt = tk.Entry(root)
self.age = tk.Entry(root)
self.btn = tk.Button(root, text="Done", command=self.message)
self.txt.pack()
self.age.pack()
self.btn.pack()
def message(self):
ent1 = self.txt.get()
ent2 = self.age.get()
tkMessageBox.showinfo("Title","Name: %s \nAge: %s" %(ent1,ent2))
if __name__=="__main__":
root = tk.Tk()
root.title("Example")
example = Example(root)
example.mainloop()