In my Python GUI script, I have a pop up window, and there is text area widget on the pop-up window, users can input some content inside, and then click one button on the pop-up window to get the input text.
But it seems that in the defined function, the widget on the pop-up window can not be accessed. the code goes as following:
from Tkinter import *
def Add_Content():
content = ent_new.get("1.0","end")
print content
def Add_Task():
task_index = 1
new_window = Toplevel()
label1 = Label(new_window, text="New Goal:")
label1.grid(row = 0, column = 0)
ent_new = Text(new_window, bg= "white", height=5, width= 30)
ent_new.grid(row=0,column =1,padx=5, pady=5)
bu_new = Button( new_window,text="Add", command = Add_Content)
bu_new.grid(row=0, column =2)
new_window.focus_force()
master = Tk()
group = LabelFrame(master, text="Operation", padx=5, pady=5, relief = RAISED)
group.grid(row=0,column= 0, padx=10, pady=10, sticky=N)
bu_add = Button(group, text = "Add Task",width = 15, command = Add_Task)
bu_add.grid(row=0,column=0)
mainloop()
in the above script, the ent_new can not be found in function Add_Content
The problem is that ent_new is in another namespace. You can solve it by making Add_Content recieve ent_new in the arguments like that,
def Add_Content(my_ent):
content = my_ent.get("1.0","end")
print content
and then using a wrapper function (lambda) when passing it to Button
bu_new = Button( new_window,text="Add", command = lambda: Add_Content(ent_new))
Without adding a class and the concept of self and parent, you can use lambda given in the first answer or you can use a global variable.
Note: In python circles globals are rather frowned upon but they work and get the job done.
from Tkinter import *
global ent_new
def Add_Content():
content = ent_new.get("1.0","end")
print content
def Add_Task():
global ent_new
task_index = 1
new_window = Toplevel()
label1 = Label(new_window, text="New Goal:")
label1.grid(row = 0, column = 0)
ent_new = Text(new_window, bg= "white", height=5, width= 30)
ent_new.grid(row=0,column =1,padx=5, pady=5)
bu_new = Button( new_window,text="Add", command = Add_Content)
bu_new.grid(row=0, column =2)
new_window.focus_force()
master = Tk()
group = LabelFrame(master, text="Operation", padx=5, pady=5, relief = RAISED)
group.grid(row=0,column= 0, padx=10, pady=10, sticky=N)
bu_add = Button(group, text = "Add Task",width = 15, command = Add_Task)
bu_add.grid(row=0,column=0)
mainloop()
Related
This question already has answers here:
Using buttons in Tkinter to navigate to different pages of the application?
(3 answers)
Closed 2 years ago.
So for my project when I click a button - the page must navigate to another. And when I do this each time it creates a different window (hence resulting in a lot of windows) or keeps stacking on top of each other
Currently I have a admin/student choice page. And if I click on the student page it will run the student log in function and this applies the same for the admin.
I want to keep the background of the windows consistent as well - but I am unable to do so and on top of that I have no clue on how to navigate via the pages - I have looked at a few videos but I did not really understand it.
contains 2 buttons admin and student which should navigate to different "windows" when clicked
def mainPage():
""""Starting Page - which navigates to the approporate login, when user logs it navigates back to this window"""
root = Tk()
root.geometry('1024x600')
load = PIL.Image.open('Image//book.jpg')
render = ImageTk.PhotoImage(load)
img =Label(root, image = render)
img.place(x=0, y=0)
my_font = font.Font(size = 15)
buttonFrame = Frame(root, width = 600, height=300, bg="grey")
buttonFrame.grid(row = 0, column = 0, padx= 10, pady=2, sticky="")
label = Label(buttonFrame, text = "Pick a Log-in", bg = "white", font=my_font).grid(row = 1, column=1, sticky="", padx=10, pady=10)
button = Button(buttonFrame, text = "Admin",command = adminLogin, width=30, height = 5, font=my_font).grid(row=2, column=1, sticky = "", padx= 10, pady=10)
button2 = Button(buttonFrame, text = "Student", command = studentLogin, width = 30, height=5, font=my_font).grid(row = 3, column=1, sticky="", padx = 10, pady=10)
root.mainloop()
def studentLogin():
root = Tk()
root.geometry('1024x600')
load = PIL.Image.open('Image//book.jpg')
render = ImageTk.PhotoImage(load)
img =Label(root, image = render)
img.place(x=0, y=0)
my_font = font.Font(size = 15)
buttonFrame = Frame(root, width = 600, height=600, bg="grey")
buttonFrame.grid(row = 0, column = 0, padx= 10, pady=2, sticky="")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
label = Label (buttonFrame, text="Welcome", font=('Helvetica', 18, 'bold'), bg="white").grid(row = 1, column = 1,sticky="", padx=10, pady=10)
label = Label(buttonFrame, text="Username", font = my_font).grid(row=2, column=1, padx=10, pady=10)
usernameEntry = Entry(buttonFrame).grid(row=2, column=2, padx=10, pady=10)
root.mainloop()
Maybe try with PySimpleGUI :)
It has a convenient window.Hide() or window.UnHide() for these cases. Its also a great library for developping GUIs, good documentation, great support, and easy to pick up.
For tkinter, you could try with
root.withdraw()
and
root.update()
root.deiconify()
I am currently working on Tkinter codes. I happen to need to create new windows exactly similar to root but my codes do not perfectly work well. The title does not appear on the new windows. This is an excerpt:
from tkinter import *
#New Window
def New_page():
window()
#Main Window
def window():
window = Tk()
window.resizable(0,0)
window.configure(background='grey')
window.state('zoomed')
window.geometry("2000x4000")
#Title Frame
TITLE_FRAME = Frame(window, relief = GROOVE, bg = "black", width=2000, height=160).grid(row=0, column=0, columnspan = 150, rowspan = 30, sticky=E+W)
Label(TITLE_FRAME, text= 'THIS IS THE TITLE PART', fg='sky blue', bg='black', font='none 40 bold',
borderwidth=5).grid(row=0,column=10)
#New Window Button
ENTRY_FRAME = Frame(window, bg='sky blue', relief = SUNKEN)
ENTRY_FRAME.grid(row=40, column=0, columnspan=20, padx=15, pady=15)
Label(ENTRY_FRAME, text= 'SELECT THE APPROPRIATE DETAILS:',
bg = 'sky blue', fg='black', font='none 10 bold', borderwidth=5).grid(row=0, column=0, columnspan=20)
NEW_WINDOW = Button(ENTRY_FRAME, text="NEW WINDOW", font='None 8 bold', width=30, command=New_page, fg= 'black', bg='white')
NEW_WINDOW.grid(row = 3, column = 0, columnspan = 3, padx = 10, pady = 10)
window.mainloop()
#Calling the Tkinter function
window()
Like in the comments, Toplevel is the way to go for this one. What I changed:
Moved making the window object globally
Renamed the function to make it makeWindow(master)
makeWindow(master) now takes in a master widget. This will make
all of the widgets made there be part of the master window.
New_page was modified to make a new Toplevel() widget
TITLE_FRAME is now made first and then grid is called on it
(EDIT) These edits fix the problems with the original window closing the program.
We want to remap the closing behaviour to act how we want. This is done with window.protocol("WM_DELETE_WINDOW",callback). We must define the callback function, in this case, deleteWindow(win).
What delete window does is take a window, and if it is the root window it hides it. Otherwise, it deletes the window. I used window.withdraw() in my code, but there's probably a better way to do it.
The way it knows if it should close the program is by keeping track of the number of active windows in the activeWindows variable. When a window is created, the number increases, when delete it decreases. If the number of active windows is 0, we can delete the main window to close the program cleanly.
The way we bind the deleteWindow(win) callback is through an anonymous function. Normally, the protocol mentioned above does not give any arguments, but we want to know which window called the function. To do this, whenever we bind the destruction of the window, we define a anonymous function using lambda that calls deleteWindow.
.
from tkinter import *
window = Tk()
window.resizable(0,0)
window.configure(background='grey')
window.state('zoomed')
window.geometry("2000x4000")
activeWindows = 1
def deleteWindow(win):
if win == window:
window.withdraw()
else:
win.destroy()
global activeWindows
activeWindows-=1
if activeWindows <= 0:
window.destroy()
#New Window
def New_page():
global activeWindows
activeWindows+=1
NEW_WINDOW=Toplevel(background='grey')
NEW_WINDOW.geometry("2000x4000")
NEW_WINDOW.protocol("WM_DELETE_WINDOW",lambda:deleteWindow(NEW_WINDOW))
makeWindow(NEW_WINDOW)
#Main Window
def makeWindow(master):
#Title Frame
TITLE_FRAME = Frame(master, relief = GROOVE, bg = "black", width=2000, height=160)
TITLE_FRAME.grid(row=0, column=0, columnspan = 150, rowspan = 30, sticky=E+W)
Label(TITLE_FRAME, text= 'THIS IS THE TITLE PART', fg='sky blue', bg='black', font='none 40 bold',
borderwidth=5).grid(row=0,column=10)
#New Window Button
ENTRY_FRAME = Frame(master, bg='sky blue', relief = SUNKEN)
ENTRY_FRAME.grid(row=40, column=0, columnspan=20, padx=15, pady=15)
Label(ENTRY_FRAME, text= 'SELECT THE APPROPRIATE DETAILS:',
bg = 'sky blue', fg='black', font='none 10 bold', borderwidth=5).grid(row=0, column=0, columnspan=20)
NEW_WINDOW = Button(ENTRY_FRAME, text="NEW WINDOW", font='None 8 bold', width=30, command=New_page, fg= 'black', bg='white')
NEW_WINDOW.grid(row = 3, column = 0, columnspan = 3, padx = 10, pady = 10)
window.protocol("WM_DELETE_WINDOW",lambda: deleteWindow(window))
#Calling the Tkinter function
makeWindow(window)
window.mainloop()
I have an app with 1 video frame and 5 Buttons. I want the video frame on top and the buttons nicely under the frame all in one row.
Here is my code:
self.root = tki.Tk()
self.panel = None
#create a button, that when pressed, will take the current
#frame and save it to file
btn= tki.Button(self.root, text="Snapshot!", command=self.takeSnapshot)
btn.grid(sticky = tki.S)
btnturnl= tki.Button(self.root, text="Left", command = self.EinsRechts)
btnturnl.grid(sticky = tki.SW)
btnturnl2= tki.Button(self.root, text="Two Left", command = self.ZweiRechts)
btnturnl2.grid(sticky = tki.SW)
btnturnr= tki.Button(self.root, text="Right", command = self.EinsLinks)
btnturnr.grid(sticky = tki.SE)
btnturnr2= tki.Button(self.root, text="Two Right", command = self.ZweiLinks)
btnturnr2.grid(sticky = tki.SE)
self.panel = tki.Label(image=image) #in this panel the video feed gets shown
self.panel.image = image
self.panel.grid(sticky = tki.N)
This is how it really looks:
what am I doing wrong?
I am not that experienced with Tkinter so if I maybe have missed a function that would be better suited for me I'd gladly change my code.
If you have questions feel free to ask and thanks for the help.
You are missing the actual column and row arguments:
http://effbot.org/tkinterbook/grid.htm#patterns
take this example to achieve what you want .Using the row and column works like excel worksheet so you can increase the value position it where you want it.
btn= tki.Button(self.root, text="Snapshot!", command=self.takeSnapshot)
btn.grid(row=1 , column=2, sticky = tki.S)
btnturnl= tki.Button(self.root, text="Left", command = self.EinsRechts)
btnturnl.grid(row=3 , column=5, sticky = tki.SW)
Replace:
btn.grid(sticky = tki.S)
...
btnturnl.grid(sticky = tki.SW)
...
btnturnl2.grid(sticky = tki.SW)
...
btnturnr.grid(sticky = tki.SE)
...
btnturnr2.grid(sticky = tki.SE)
...
self.panel.grid(sticky = tki.N)
with:
btn.grid(row=1, column=0, sticky = tki.S)
...
btnturnl.grid(row=1, column=1, sticky = tki.SW)
...
btnturnl2.grid(row=1, column=2, sticky = tki.SW)
...
btnturnr.grid(row=1, column=3, sticky = tki.SE)
...
btnturnr2.grid(row=1, column=4, sticky = tki.SE)
...
self.panel.grid(row=0, column=0, columnspan=5, sticky = tki.N)
If you don't specify row or column numbers in a grid call row defaults to last_row_no + 1 and column defaults to 0.
Review below the code snippets that produce identical GUIs:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Label")
button = tk.Button(root, text="Button")
label.grid() # implicit
button.grid()
root.mainloop()
is identical to:
import tkinter as tk
root = tk.Tk()
label = tk.Label(root, text="Label")
button = tk.Button(root, text="Button")
label.grid(row=0, column=0) # explicit
button.grid(row=1, column=0)
root.mainloop()
It is suggested to be explicit, latter is the better code, to quote zen of python(import this):
"Explicit is better than implicit."
I started using TK in python to build a graphical interface for my program.
I'm not able to fix 2 issues concerning (1) the position of a button in the window and (2) use a value of a radiobutton inside a fucntion.
This is my current code:
root = tk.Tk()
root.title("START")
root.geometry("500x200+500+200")
v = tk.IntVar()
v.set(0) # initializing the choice
my_choise = [
("Basic",1),
("Advanced",2),
('Extreme',3)
]
def ShowChoice():
print(v.get())
tk.Label(root,
text="""Choose your configuration:""",
justify = tk.LEFT,
padx = 20).pack()
val = 0
for val, choise in enumerate(my_choise):
tk.Radiobutton(root,text=choise,padx = 20,variable=v,command=ShowChoice,value=val).pack(anchor=tk.W)
def star_program(value):
os.system("ifconfig")
def open_comments_file():
os.system("gedit /home/user/Desktop/comments.txt")
def open_links_file():
os.system("gedit /home/user/Desktop/links.txt")
frame = tk.Frame(root)
frame.pack()
open_file_c = tk.Button(frame,
text="Comments",
command=open_comments_file)
open_file_f = tk.Button(frame,
text="Links",
command=open_links_file)
button = tk.Button(frame,
text="Start",
command=star_program(v.get()))
button.pack(side=tk.LEFT)
open_file_f.pack(side=tk.LEFT)
open_file_c.pack(side=tk.LEFT)
slogan = tk.Button(frame,
text="Cancel",
command=quit)
slogan.pack(side=tk.LEFT)
root.mainloop()
I would like that the buttons "Links" and "Comments" were positioned below the radiobutton, one below the other. Now, all buttons are in line, but I would like to have "start" and "cancel" at the bottom of my window.
Then I tried to use the value of the radiobutton (choice) inside the star_program function. It does not work. My idea is, based on the choice selected in the radiobutton, perform different actions when I click the button "start":
def star_program(value):
if value == 0:
os.system("ifconfig")
else:
print "Goodbye"
In addition, concerning "start" button, I have a strange behavior. The program runs "ifconfig" command also if I don't click on "start". And If I click "start" it does not perform any action.
Any suggestion?
Thanks!!!
i'm assuming this is more like what you're after:
root = tk.Tk()
root.title("START")
root.geometry("500x200+500+200")
v = tk.IntVar()
v.set(0) # initializing the choice
my_choise = [
("Basic",1),
("Advanced",2),
('Extreme',3)
]
def ShowChoice():
print(v.get())
tk.Label(root,
text="""Choose your configuration:""",
justify = tk.LEFT,
padx = 20).grid(column=1, row=0, sticky="nesw") # use grid instead of pack
root.grid_columnconfigure(1, weight=1)
val = 0
for val, choise in enumerate(my_choise):
tk.Radiobutton(root,text=choise,padx = 20,variable=v,command=ShowChoice,value=val).grid(column=1, row=val+1, sticky="nw")
def star_program(value):
os.system("ifconfig")
def open_comments_file():
os.system("gedit /home/user/Desktop/comments.txt")
def open_links_file():
os.system("gedit /home/user/Desktop/links.txt")
frame = tk.Frame(root)
frame.grid(column=1, row=4, sticky="nesw")
open_file_c = tk.Button(frame,
text="Comments",
command=open_comments_file)
open_file_f = tk.Button(frame,
text="Links",
command=open_links_file)
button = tk.Button(frame,
text="Start",
command=lambda: star_program(v.get()))
# use lambda to create an anonymous function to be called when button pushed,
needed for functions where arguments are required
button.grid(column=2, row=3, sticky="nesw")
open_file_f.grid(column=1, row=1, sticky="nesw")
open_file_c.grid(column=1, row=2, sticky="nesw")
slogan = tk.Button(frame,
text="Cancel",
command=quit)
slogan.grid(column=4, row=3, sticky="nesw")
root.mainloop()
The problem with the "start" button is due to the function definition.
This is the right code that does not trigger any action if you don't click the button:
button = tk.Button(frame,
text="Start",
command=star_program)
I'm trying to add a hovering option for multiple buttons which I have already achieved, but I would like to do it in a class to save me adding the option to each button individually.
I'm coding in python and using tkinter for my GUI.
class GUIButtons():
def __init__(self, window):
self.window = window
self.Calculate = Button(window, command=GetUnits, text="Calculate", width = 19, background = "dark blue", fg="white")
self.Calculate.grid(row=1, column=4, sticky=NSEW)
self.ShowMethod = Button(window, command=ShowMethod, text="Show method", width = 19, background = "darkblue", fg="white")
self.ShowMethod.grid(row=1, column= 5, sticky=NSEW)
self.Submit = Button(window, command = lambda: GetCoordinate(Message), text="Submit", width = 6, height = 1, background = "dark blue", fg="white", font = 11)
self.Submit.grid(row=3, column = 3, sticky = NSEW)
self.Displacement = Button(window, text="Displacement", background = "Dark Blue", fg="white", font=11)
self.Displacement.grid(row=2, column=1, sticky= N)
Not sure how to bind the hover option just once for it to apply for all my buttons.
Any help would be highly appreciated!
See Instance and Class Bindings
But Tkinter also allows you to create bindings on the class and
application level; in fact, you can create bindings on four different
levels:
the widget class, using bind_class (this is used by Tkinter to provide
standard bindings)
and example
By the way, if you really want to change the behavior of all text
widgets in your application, here’s how to use the bind_class method:
top.bind_class("Text", "", lambda e: None)
So using bind_class with <Enter> and <Leave> you can do it.
--
EDIT: example - when mouse enter/hover any button then test() will be called.
from tkinter import *
# ---
def test(event):
print(event)
# ---
window = Tk()
# created befor binding
Button(window, text="Button #1").pack()
Button(window, text="Button #2").pack()
Button(window, text="Button #3").pack()
window.bind_class('Button', '<Enter>', test)
# created after binding
Button(window, text="Button #4").pack()
window.mainloop()
--
You can also create own Widget to change existing Widget.
Red button:
from tkinter import *
# ---
class RedButton(Button):
def __init__(self, parent, **options):
Button.__init__(self, parent, **options)
self['bg'] = 'red'
# or
#self.config(bg='red')
# ---
window = Tk()
RedButton(window, text="Button #1").pack()
RedButton(window, text="Button #2").pack()
RedButton(window, text="Button #3").pack()
window.mainloop()
or
class RedButton(Button):
def __init__(self, parent, **options):
Button.__init__(self, parent, bg='red', **options)
--
EDIT:
If you need to change only button colors on hover then you don't need to bind function. Button has activebackground= and activeforeground=.
import tkinter as tk
root = tk.Tk()
btn = tk.Button(root, text="HOVER", activebackground='blue', activeforeground='red')
btn.pack()
root.mainloop()
see Button
EDIT: it can behave different on Windows, Linux and OS X