Similar questions have been asked, but none of them address the particular way my script is constructed:
from Tkinter import *
from ttk import *
class Gui(Frame):
def __init__(self, parent):
Frame.__init__(self, parent) #Gui inherits from built in Frame Class
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Shoes Ware")
self.pack(fill=BOTH, expand=1)
run_val = Entry(self)
run_val["width"] = 5
run_val.place(x=80, y=40)
quit_B = Button(self, text="Submit", command=self.submit)
quit_B.place(x=130, y=170)
def submit(self):
value = run_val.get()
print value
self.quit()
def main():
root = Tk()
root.geometry("300x200+50+50")
app = Gui(root)
root.mainloop()
if __name__ == '__main__':
main()
I get "NameError: global name 'run_val' is not defined" when I hit the submit button. What am I doing wrong here. Right now the print statement is just to check my work. Later on, I'll be using that value in a program.
You are not storing the reference to the Entry widget in initUI.
def initUI(self):
# ...
self.run_val = Entry(self)
self.run_val["width"] = 5
self.run_val.place(x=80, y=40)
Then you can retrieve the value of self.run_val.get() without any problem.
Related
I am trying to update a label, but the code I have written creates a new label each time. I am relatively new to tkinter so I couldn't understand how to apply other answers to my code.
from tkinter import *
import random
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master=master
self.init_window()
def init_window(self):
self.pack(fill=BOTH, expand=1)
testButton=Button(self, text="Press", command=calc)
testButton.pack()
l1=Label(text="")
def testbutton(ans): #creates a new instance of l1 each time, I want to update existing l1
var=StringVar()
l1=Label(textvariable=var) #l1.configure() gives error l1 not defined
var.set(ans)
l1.pack()
def calc():
list1=["a","b","c"]
index=random.randint(0,2)
answer=list1[index]
Window.testbutton(answer)
root=Tk()
root.geometry("400x300")
app=Window(root)
root.mainloop()
Each time the button is pressed, a new label is created, instead of updating the text on the existing label.
This is a simplified version of my actual project, but highlights the issue with labels.
I've tried to use l1.configure(...) inside the testbutton function but then it runs an error that l1 isn't defined.
To avoid creating a new Label each time, you need to make one and save it as an attribute of the Window instance. To make it accessible to the calc() function, you'll also need to pass the Window instance to it as an argument (to avoid using global variables). A common why to do that with tkinter is by using a lamba function as the Button's command= argument and making self the default value for its argument as shown below.
from tkinter import *
import random
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.pack(fill=BOTH, expand=1)
testButton = Button(self, text="Press",
command=lambda win=self: calc(win))
testButton.pack()
self.l1 = Label(text="")
self.l1.pack()
def testbutton(self, ans):
self.l1.configure(text=ans)
def calc(window): # note window argument added
list1 = ["a","b","c"]
index = random.randint(0,2)
answer = list1[index]
window.testbutton(answer)
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
You can just use class methods and attributes.
Use a StringVar to change label text:
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.pack(fill=BOTH, expand=1)
testButton = Button(self, text="Press", command=self.calc)
testButton.pack()
self.ltext = StringVar()
l1 = Label(textvariable=self.ltext)
l1.pack()
def testbutton(self, ans):
self.ltext.set(ans)
def calc(self):
list1 = ["a", "b", "c"]
index = random.randint(0, 2)
answer = list1[index]
self.testbutton(answer)
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
I'm having a trouble when i open a secondary window. Now I'm just creating a toplevel window with a button and I need to open the same secondary window If i click the button (not generate a new instance).
Which is the better way to generate single secondary window and not generating a new window instance?
I leave the code that I'm actually working on:
import tkinter
class LogWindow():
def __init__(self, parent):
self.parent = parent
self.frame = tkinter.Frame(self.parent)
class MainWindow(tkinter.Frame):
def __init__(self, parent):
tkinter.Frame.__init__(self, parent)
self.parent = parent
frame = tkinter.Frame(self, borderwidth=1)
frame.pack(fill=tkinter.BOTH, expand=True, padx=5, pady=5)
self.LogButton = tkinter.Button(frame, text="Log Viewer", command= self.openLogWindow)
self.LogButton.grid(sticky=tkinter.E+tkinter.W)
self.pack(fill=tkinter.BOTH,expand=True)
def openLogWindow(self):
self.logWindow = tkinter.Toplevel(self.parent)
self.app = LogWindow(self.logWindow)
def main():
global app, stopRead
root = tkinter.Tk()
root.geometry("300x300")
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
Maybe i need to have a single instance of a Toplevel class and call show and close to show or hide the secondary window.
Finally after some tests I've found how to solve that, thanks to the #furas response and some investigation about the Tkinter events with the protocol function.
I've got that working with:
import tkinter
logWindowExists = False
class LogWindow():
def __init__(self, parent):
global logWindowExists, root
logWindowExists = True
self.parent = parent
self.frame = tkinter.Frame(self.parent)
def on_closing(self):
global logWindowExists
logWindowExists = False
self.parent.destroy()
class MainWindow(tkinter.Frame):
def __init__(self, parent):
tkinter.Frame.__init__(self, parent)
self.parent = parent
frame = tkinter.Frame(self, borderwidth=1)
frame.pack(fill=tkinter.BOTH, expand=True, padx=5, pady=5)
self.LogButton = tkinter.Button(frame, text="Log Viewer", command= self.openLogWindow)
self.LogButton.grid(sticky=tkinter.E+tkinter.W)
self.pack(fill=tkinter.BOTH,expand=True)
def openLogWindow(self):
if not logWindowExists:
self.logWindow = tkinter.Toplevel(self.parent)
self.app = LogWindow(self.logWindow)
self.logWindow.protocol("WM_DELETE_WINDOW", self.app.on_closing)
else:
self.logWindow.deiconify()
def main():
global app, stopRead, root
root = tkinter.Tk()
root.geometry("300x300")
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
Using a boolean to know if the window exists or not i can handle when the window it's opened or not and just show the existing window or creating a new one.
I'm working on my very first Python GUI and I'm trying to modify this tkinter example, but I simply cannot figure out how to write a callback function for the OK button that will pass on the entered value to the main program.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
value=StringVar(None)
value.set("this is the default value")
valueEntry=Entry(self, textvariable=value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.quit)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
I've read a gazillion of tutorials, but none of them explains this clearly. Theoretically, I should be able to get the selected value with value.get(), but I keep getting error messages no matter where I put it. Also, AFAIK, I should be able to define a default value with value.set(), but this doesn't seem to have an effect, since the text box is empty when I run the program.
What is the easiest way to pass on values to the main python program after root.mainloop() terminates? (The actual dialog box contains several entry boxes for entering string and integer values.)
I.e. I want to be able to use something like:
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
print value
print value2
print value3
How do I define default values for entry boxes?
Change every occurrence of the value variable with self.value. This should fix it and the default value will be displayed.
UPDATE
from Tkinter import Tk, BOTH, StringVar, IntVar
from ttk import Frame, Button, Style, Label, Entry
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def showMe(self):
print(self.value.get())
def initUI(self):
self.parent.title("Get Value")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
valueLabel = Label(self, text="Value: ")
valueLabel.place(x=10, y=10)
self.value=StringVar(None)
self.value.set("this is the default value")
valueEntry=Entry(self, textvariable=self.value)
valueEntry.place(x=70, y=10)
quitButton = Button(self, text="Quit", command=self.quit)
quitButton.place(x=10, y=50)
okButton = Button(self, text="OK", command=self.showMe)
okButton.place(x=120, y=50)
def main():
root = Tk()
root.geometry("220x100+300+300")
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Both your quitButton and okButton call the self.quit functions. So no mater what value you enter when you press the OK button you are calling the quit function which has its own problems as well outside the scope of your question.
Try to define value as self.value and make the okButton call a function that does: print self.value.get().
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()
So basically i want the user interface to be updated when a user presses the start button, however when i call the maininit function it returns an error saying that root is not defined, is there any way i can get around this?
from PIL import Image, ImageTk
from Tkinter import Tk, Label, BOTH,W, N, E, S, Entry, Text, INSERT, Toplevel
from ttk import Frame, Style, Button, Label
import Tkinter
import Callingwordlist
class MainGameUI(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Type!")
self.pack(fill=BOTH, expand=1)
style = Style()
style.configure("TFrame", background="black")
Type = Image.open("Type!.png")
Typet = ImageTk.PhotoImage(Type)
label3 = Label(self, image=Typet)
label3.image = Typet
label3.place(x=0, y=0)
self.pack(fill=BOTH, expand=1)
MenuButton = Button(self, text="Main Menu")
MenuButton.pack()
MenuButton.place(x=560,y=20,height = 80,width = 100)
QuitButton = Button(self,text="Quit",command=self.parent.destroy)
QuitButton.pack()
QuitButton.place(x=680,y=20,height = 80,width = 100)
StartButton = Button(self, text="Start",command=maininit)
StartButton.pack()
StartButton.place(x=440,y=20,height=80,width=100)
def maininit():
entry1 = Entry(root,font =("Courier",38), width = 22)
entry1.pack(ipady=10)
entry1.config(bg="#CEF6F5")
entry1.place(x=90,y=200)
entry2 = Entry(root,font =("Courier",38), width = 22)
entry2.pack(ipady=10)
entry2.config(bg="#CEF6F5")
entry2.place(x=90,y=350)
text1 = Text(root,width=23,height=1,font=("Courier",38))
text1.pack()
text1.config(bg="black",fg="white",bd=0)
text1.place(x=90,y=150)
text1.insert(INSERT,"Hello")
text2 = Text(root,width=23,height=1,font=("Courier",38))
text2.pack()
text2.config(bg="black",fg="white",bd=0)
text2.place(x=90,y=300)
text2.insert(INSERT,"Test")
dtext = Text(root,font=("Courier",28),width=10,height=1)
dtext.pack()
dtext.config(bg="black",fg="white",bd=0)
dtext.insert(INSERT,"Difficulty")
dtext.place(x=90,y=500)
atext = Text(root,font=("Courier",28),width=8,height=1)
atext.pack()
atext.config(bg="black",fg="white",bd=0)
atext.insert(INSERT,"Accuracy")
atext.place(x=595,y=500)
dentry = Text(root,font=("Courier",28),width=1,height=1)
dentry.pack()
dentry.config(bg="white",bd=0)
dentry.place(x=180,y=550)
dentry.insert(INSERT,"Test")
def main():
root = Tk()
root.geometry("860x640+300+300")
app = MainGameUI(root)
root.mainloop()
if __name__ == '__main__':
main()
In your application, root is a locally defined variable confined to main(). You need to somehow pass root as an argument to maininit. Here is one way to do this:
First, change maininit() so that it accepts a parameter root:
def maininit(root):
...
Now, change the callback on StartButton so it passes maininit() the root object:
class MainGameUI(Frame):
...
def initUI(self):
...
StartButton = Button(self, text="Start",command=lambda: maininit(self.parent))
...
You are defining root inside a function, whose calling namespace is not available to the maininit() function. If you omit the definition of main() and instead write
if __name__ == "__main__":
root = Tk()
root.geometry("860x640+300+300")
app = MainGameUI(root)
root.mainloop()
root will then be defined in the global module namespace, where it IS available to the code in the function.