String Variable not setting initial value - python

class Lay():
def __init__(self):
root=Tk()
root.configure(background="black")
var=StringVar()
var.set("OVERVIEW")
Label(root,textvariable=var).grid(row=1,column=1,sticky=W+E+N+S)
Entry(root, textvariable = var).place(rely=1.0,relx=1.0,x=0,y=0,anchor=SE)
root.mainloop()
Hello, when i run this the initial value of the string variable does not appear, but when i type into the entry box, the text i type appears in the label. I'm not quite sure why this occurs, but i get an empty label to begin with, with the entry box. Thank you for any help.

Although, I couldn't reproduce the problem, I refactored your code to initialize tkinter widgets through a class(inspired by the snippet in the docs) and also increased the window size so that the widgets are clearly viewed. If there is anything else in your code that is calling multiple windows as #jasonharper suggested, you should share that.
import tkinter as tk
class Lay(tk.Tk):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.var=tk.StringVar()
self.var.set("OVERVIEW")
self.Widgets()
def Widgets(self):
self.displaylbl = tk.Label(self,textvariable=self.var)
self.displaylbl.grid(row=2,column=1,sticky=tk.W+tk.E+tk.N+tk.S)
self.entry = tk.Entry(self, textvariable = self.var)
self.entry.place(rely=1.0,relx=1.0,x=0,y=0,anchor=tk.SE)
app = Lay()
app.geometry("200x200")
app.mainloop()
Output:

Related

tkinter: Why am I getting a small window plus my main window and gridding is off? __init__ problem?

Creates two windows and gridding is not correct. Some additional comments in the code initiation.
I have used this approach, without the super init with no problem, many times.
Advice appreciated.
Thanks
# timhockswender#gmail.com
import tkinter as tk
from tkinter import ttk
class constants_page(tk.Frame):
def __init__(self):
super(constants_page, self).__init__() # from stackoverflow
# if not used error = 'constants_page' object has no attribute 'tk'
# if used, another tiny window is opened
# in addtion to the constants_page
self.constants_page = tk.Tk()
self.constants_page.geometry("1000x500") #width*Length
self.constants_page.title("Owen's Unit Conversion App")
self.constants_page.configure(background='light blue')
self.CreateWidgets()
def CreateWidgets(self):
self.value_label = ttk.Label(self.constants_page,text="Value----->" , width =10 )
self.value_label.grid(row=0, column=1, columnspan=1, sticky='nse')
# Problem: not gridding properly
self.title_label = ttk.Label(self.constants_page, text="Important Physical Constants",
anchor=tk.CENTER, font=("Arial",20)).grid(row=2, columnspan=2)
for r in range(2):
self.constants_page.rowconfigure(r, weight=1, uniform='row')
for c in range(2):
self.constants_page.columnconfigure(c, weight=1 )
def Show_Page():
# Create the entire GUI program
program = constants_page()
program.mainloop()
if __name__ == "__main__":
Show_Page()
The super call expects you to provide a root window (an instance of tk.Tk()). If you don't provide one it defaults to the first root window opened, and if none has been opened yet then it helpfully opens one for you. A few lines later you open a second one yourself.
The easy fix is to remove the self.constants_page = tk.Tk() line. The proper fix is to make the Tk() instance outside of the class and pass it in. This allows you to use the Frame class itself to lay out widgets (use self instead of self.constants_page). Try this:
import tkinter as tk
from tkinter import ttk
class constants_page(tk.Frame):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
master.geometry("1000x500") #width*Length
master.title("Owen's Unit Conversion App")
self.configure(background='light blue')
self.CreateWidgets()
def CreateWidgets(self):
self.value_label = ttk.Label(self,text="Value----->" , width =10 )
self.value_label.grid(row=0, column=1, columnspan=1, sticky='nse')
self.title_label = ttk.Label(self, text="Important Physical Constants",
anchor=tk.CENTER, font=("Arial",20)).grid(row=2, columnspan=2)
for r in range(2):
self.rowconfigure(r, weight=1, uniform='row')
for c in range(2):
self.columnconfigure(c, weight=1 )
def Show_Page():
# Create the entire GUI program
program = tk.Tk()
win = constants_page(program)
win.pack()
program.mainloop()
if __name__ == "__main__":
Show_Page()

"NameError[Command Name] is not defined" When Using Buttons in Tkinter

I'm trying to set up a list of checkbuttons from top to bottom in the GUI and add up the associated "onvalues" for each of the checkbuttons that are on.
My problem now is that for some reason my 'command' attribute in my 'calcbutton' is giving me a "Name 'calc_cost' is not defined" error.
I've added a bunch of imports that you see at the top of the code hoping that would solve the problem, to not much avail.
import tkinter as tk
from tkinter import *
from tkinter import Button
servicelist = ("Oil change","Lube job","Radiator flush","Transmission flush","Inspection","Muffler replacement","Tire rotation")
servicecost = (30,20,40,100,35,200,20)
a = 0
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def calc_cost(self):
print(a)
def init_window(self):
self.master.title("GUI")
self.pack(fill=BOTH, expand=1)
for i in range(len(servicelist)):
serviceButton = Checkbutton(self, text=servicelist[i], onvalue = servicecost[i], var = a)
serviceButton.place(x=0, rely = i*.1)
calcButton = tk.Button(self, text = "Calculate Cost", fg = "black", bg = "green", command = calc_cost)
calcButton.pack(side = "bottom")
root = Tk()
#size of the window
root.geometry("400x300")
app = Window(root)
root.mainloop()
The checkbuttons pop up and the GUI works for the most part besides the displaying of the 'calcbutton' as well as getting the "NameError: name 'calc_cost' is not defined"
Change command = calc_cost to command = self.calc_cost
self represents the instance of the class. By using the self keyword we can access the attributes and methods of the class in python.
It will give you this output

Why does Python tkinter label widget not update?

class First_Frame(Frame):
def __init__(self,master):
super().__init__(master)
self.grid()
self.widgets()
def widgets(self):
self.commandent1=StringVar()
self.commandent1.set("tutaj bedzie sie pokazywal aktualny status")
self.img=Image.open("database.XPM","r")
self.image_true=ImageTk.PhotoImage(self.img)
self.label=Label(self,image=self.image_true).grid()
self.label2=Label(self,text="twoje gui uzytkownika").grid()
self.widgets_2()
def widgets_2(self):
self.status_text=Label(self,text=self.commandent1.get())
self.entry1=Entry(self)
self.entry1.bind("<Return>",self.update_status)
self.entry1.grid()
self.status_text.grid()
def update_status(self):
self.x=self.entry1.get()
self.commandent1.set(self.x)
You have 2 main reasons your Label (not text) widget is not updating.
Reason 1. You need to handle the event that is being passed to update_status from the binding. To do this just add event or any argument name really you want. I just use event for readability.
def update_status(self, event):
Reason 2. You need to and the less obvious reason here for some is the way you are using your StringVar() on the label widget. Here you are assigning the current text value of the StringVar() only once and never again. To properly use the StringVar() with a label widget you will need to assign the StringVar() to a textvariable argument and not a text argument.
Like this:
Label(self,textvariable=self.commandent1).grid()
Note I took out the image portion of your code as it was irrelevant to the question. Your final code should look something like this:
from tkinter import *
class First_Frame(Frame):
def __init__(self, master):
super().__init__()
self.grid()
self.widgets()
def widgets(self):
self.commandent1 = StringVar()
self.commandent1.set("tutaj bedzie sie pokazywal aktualny status")
Label(self,text="twoje gui uzytkownika").grid()
self.widgets_2()
def widgets_2(self):
self.entry1 = Entry(self)
self.entry1.bind("<Return>", self.update_status)
self.entry1.grid()
Label(self,textvariable=self.commandent1).grid()
def update_status(self, event):
self.commandent1.set(self.entry1.get())
root = Tk()
First_Frame(root)
root.mainloop()

How to automatically insert several tkinter items in Tk() window using classes

I apologize in advance if this is a stupid simple question, but i am really bad att python classes and can't seem to get it to work!
Here is my code:
from tkinter import *
a = Tk()
class toolsGUI():
def __init__(self, rootWin):
pass
def frame(self):
frame = Frame(rootWin)
frame.configure(bg = 'red')
frame.grid()
def button(self, binding, text):
btn = Button(rootWin, text=text)
btn.configure(bg = 'orange', fg = 'black')
btn.bind('<'+binding+'>')
btn.grid(row=1, sticky = N+S+E)
I simply want the button() or frame() to understand that rootWin is the same as in __init__, in this case rootWin should be variable a, thus placing the button in the Tk() window. After looking around, I understand that this is not the way to do it. Do anyone have another suggestion that might work?
You're pretty close. You are passing a to the toolsGUI initializer which is the right first step. You simply need to save this as an instance variable, then use the variable whenever you need to reference the root window:
def __init__(self, rootWin):
...
self.rootWin = rootWin
...
def frame(self):
frame = Frame(self.rootWin)
...
An alternative is to have toolsGUI inherit from Frame, in which case you can put all of the widgets in the frame instead of the root window. You then need the extra step of putting this frame inside the root window.
class toolsGUI(Frame):
def __init__(self, rootWin):
Frame.__init__(self, rootWin)
def frame(self):
frame = Frame(self)
...
a = Tk()
t = toolsGUI(a)
t.pack(fill="both", expand=True)
a.mainloop()
As a final bit of advice: don't user variables that are the same name as methods if you can avoid it. "frame" is a poor choice of function names. Instead, call it "create_frame" or something, otherwise it could be confused with class Frame and the local variable frame

how to stack two widgets and switch between them?

I want to script two widgets which would be stacked and I would switch from one to another with a key. Each widget would be a Frame containing several Labels. I have the following code so far (only one Label per Frame):
import Tkinter as tk
import ttk
import datetime
def main():
# initialize root
root = tk.Tk()
# initialize widgets
dash = Dashboard(root)
notepad = Notepad(root)
# set key actions
root.bind('<F11>', root.lift)
root.bind('<F1>', dash.raiseme)
root.bind('<F2>', notepad.raiseme)
root.mainloop()
class Dashboard(ttk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent) # voodoo
self.dashframe = tk.Frame(parent)
self.labone = tk.Label(self.dashframe, text="lab1", fg='black', bg='blue')
self.labone.grid(row=0, column=0)
def raiseme(self, event):
print "raiseme dash"
self.labone.configure(text=datetime.datetime.now())
self.dashframe.lift()
class Notepad(ttk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent) # also voodoo
self.noteframe = tk.Frame(parent)
self.laboneone = tk.Label(self.noteframe, text="lab11", fg='white', bg='red')
self.laboneone.grid(row=0, column=0)
def raiseme(self, event):
print "raiseme notepad"
self.laboneone.configure(text=datetime.datetime.now())
self.noteframe.lift()
if __name__ == '__main__':
main()
Pressing F1 and F2 reach the correct routines but the only thing I get is the main window, empty. There are no errors displayed so I guess that the code runs fine (just not the way O would like to :)).
Can I achieve the switch using the skeleton above?
There are at least two big problems with your code.
First, you're creating all these new frames, but not placing them anywhere, so they will never show up anywhere. If you have a main window with nothing placed on it, of course you will just "get the main window, empty". You need to call pack or some other layout method on any widget to get it to show up on its parent. In this case, it sounds like you want to put them both in the exact same place, so grid or place is probably what you want.
Second, your Dashboard and Notepad classes are themselves Frames, but they don't do any Frame-ish stuff; instead, they each create another, sibling Frame and attach a label to that sibling. So, even if you packed the Dashboard and Notepad, they're just empty frame widgets, so that wouldn't do any good.
If you fix both of those, I think your code does what you want:
class Dashboard(ttk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent) # voodoo
self.labone = tk.Label(self, text="lab1", fg='black', bg='blue')
self.labone.grid(row=0, column=0)
self.grid(row=0, column=0)
def raiseme(self, event):
print "raiseme dash"
self.labone.configure(text=datetime.datetime.now())
self.lift()
class Notepad(ttk.Frame):
def __init__(self, parent):
ttk.Frame.__init__(self, parent) # also voodoo
self.laboneone = tk.Label(self, text="lab11", fg='white', bg='red')
self.laboneone.grid(row=0, column=0)
self.grid(row=0, column=0)
def raiseme(self, event):
print "raiseme notepad"
self.laboneone.configure(text=datetime.datetime.now())
self.lift()
However, you might also want to set a fixed size for everything; otherwise you could end up lifting the red widget and, e.g., only covering 96% of the blue one because the current time is a bit narrower than the previous oneā€¦
The code you linked to for inspiration attempted to do this:
newFrame = tkinter.Frame(root).grid()
newFrame_name = tkinter.Label(newFrame, text="This is another frame").grid()
That won't work, because grid returns None, not the widget. But at least it calls grid; yours doesn't even do that.

Categories

Resources