How can I access button click from main in python, tkinter? - python-3.x

I'm new to python and tkinter GUI, I need to access button click action from the main function, is there any possibility to do that? any way I can access it in click function inside the class that I have comment it. what is the correct method to do it? thank you
from tkinter import *
class Youtube:
def __init__(self,master):
self.master = master
master.title('Youtube_Downloder')
self.screen = Entry(master, state='normal', width=25, background="White", foreground="blue",
font=('Arial', 12))
self.screen.grid(row=1, column=0, columnspan=4, padx=5, pady=5)
self.layout = Label(master, text='Past the Link below', font=('Arial', 16),foreground="red")
self.layout.grid(row=0, column=1)
self.create_button('Add Link',1,30)
def create_button(self,val,row,column,width=12):
button = Button(self.master, text=val, width=width, command=lambda: self.click(val))
return button.grid(row=row,column=column)
def click(self,clicked_button=None):
if clicked_button == 'Add Link':
#self.create_label(self.screen.get(), 3, 1) #this methord working
return 'Add Link'
def create_label(self,text,row,column,font=('Arial',8)):
return Label(self.master, text=text, font=font).grid(row=row, column=column)
def main():
root = Tk()
my_gui = Youtube(root)
if my_gui.click() == 'Add Link':
my_gui.create_label(my_gui.screen.get(), 3, 1)
root.mainloop()
if __name__ == '__main__':
main()

I'm assuming it could be this button:
def create_button(self,val,row,column,width=12):
button = Button(self.master, text=val, width=width, command=lambda: self.click(val))
return button.grid(row=row,column=column)
Change button to self.button. When you've done that you can access it in main by using my_gui.button.
If you ever decide to use an mvc model, this will be the approach as well.

Related

How to create a class to close GUI and exit Python

I have been trying to find a way to do this for a while to no avail. I would like to create a class to completely close my GUI in tkinter and I'm not having much luck. I've tried sys.exit and .destroy() a few different ways. I can manage to do what I want without using classes but I'm rather new to OOP. Here is my code:
import sys as system
import tkinter as tk
from tkinter import ttk
class headerFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
#setup the grid layout manager
self.columnconfigure(0, weight=1)
self._create_widgets()
def _create_widgets(self):
#header bar
canvas = tk.Canvas(self, bg='#0066cc', highlightthickness=0, height=45, width=600)
canvas.grid(column=0, row=0, sticky=tk.W)
label = ttk.Label(self, text='Production Assistant', background='#0066cc', foreground='White', font=('calibri', 18, 'bold'))
label.grid(row=0, column=0)
class loginFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
#setup the grid layout manager
self.columnconfigure(0, weight =1)
self.columnconfigure(0, weight=3)
self._create_widgets()
def _create_widgets(self):
#username
ttk.Label(self, text='Username: ', justify='right').grid(row=0, column=0, sticky=tk.E)
username = ttk.Entry(self, width=33)
username.focus()
username.grid(row=0, column=1, sticky=tk.W)
#password
ttk.Label(self, text='Password: ', justify='right').grid(row=1, column=0, sticky=tk.E)
password = ttk.Entry(self, width=33, show='*')
password.grid(row=1, column=1, sticky=tk.W)
#add padding
for widget in self.winfo_children():
widget.grid(padx=0, pady=5)
class loginButtonFrame(ttk.Frame):
def __init__(self, container):
super().__init__(container)
#setup the grid layout manager
self.columnconfigure(0, minsize=62)
self._create_widgets()
def _create_widgets(self):
#buttons
ttk.Button(self, text='Login', width=15).grid(row=0, column=1)
ttk.Button(self, text='Forgot Login', width=15).grid(row=0, column=2)
ttk.Button(self, text='Request Access', width=15).grid(row=1, column=1)
ttk.Button(self, text='Exit', width=15, command=exitButton).grid(row=1, column=2)
#add padding to buttons
for widget in self.winfo_children():
widget.grid(padx=3, pady=3)
class exitButton():
def exit():
#code to close gui and program
#create the main application
class mainLogin(tk.Tk):
def __init__(self):
super().__init__()
self.title('Login')
self.geometry('325x175')
self.resizable(0, 0)
self.configure(background='#444444')
#windows only (remove the minimize/maximize buttons)
self.attributes('-toolwindow', True)
#TCL to center the screen
self.eval('tk::PlaceWindow . center')
#layout on the root window
self.columnconfigure(0, weight=1)
self._create_Styles()
self._create_widgets()
def _create_Styles(self):
#create styles
s = ttk.Style()
s.configure('TFrame', background='#444444')
s.configure('TLabel', background='#444444', foreground='white')
s.configure('TButton', background='#878683', foreground='black')
def _create_widgets(self):
#create the header frame
_header_frame = headerFrame(self)
_header_frame.grid(column=0, row=0)
#create the login frame
_login_frame = loginFrame(self)
_login_frame.grid(column=0, row=1, sticky=tk.N)
#create the button frame
_login_button_frame = loginButtonFrame(self)
_login_button_frame.grid(column=0, row=2)
if __name__ == '__main__':
app = mainLogin()
app.mainloop()
class exitButton() is what I would like to call from multiple different pages in the application to close everything.
Any help is appreciated, I'm trying to learn as I build so if you have any suggested reading based around Python that would help with this I would appreciate it!

Updating text on a label

I am working through an Oreilly Tutorial on tkinter, but the code provided in the tutorial doesn't work for me. The "Choose one" message doesn't show, instead it shows: PY_VAR0. When I click the hello button nothing happens. When I click the goodbye button the window closes as expected but no message is shown.
Of note, prior I had:
def say_hello(self):
self.label.configure(text="Hello World!")
def say_goodbye(self):
self.label.configure(text="Goodbye! \n (Closing in 2 seconds)")
self.after(2000, self.destroy)
And received an attribute error: attributeerror: '_tkinter.tkapp' object has no attribute 'label' site:stackoverflow.com.
I am uncertain what is wrong as I have followed the example explicitly in both cases.
My code is below:
import tkinter as tk
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.title('Hello Tkinter')
self.label_text = tk.StringVar()
self.label_text.set("Choose One")
label = tk.Label(self, text=self.label_text)
label.pack(fill=tk.BOTH, expand=1, padx=100, pady=30)
hello_button = tk.Button(self, text='Say Hello',
command=self.say_hello)
hello_button.pack(side=tk.LEFT, padx=(20, 0), pady=(0, 20))
goodbye_button = tk.Button(self, text ='Say Goodbye',
command=self.say_goodbye)
goodbye_button.pack(side=tk.RIGHT, padx=(0, 20), pady=(0, 20))
def say_hello(self):
self.label_text.set("Hello World!")
def say_goodbye(self):
self.label_text.set("Goodbye! \n (Closing in 2 seconds)")
self.after(2000, self.destroy)
if __name__ == "__main__":
window = Window()
window.mainloop()
You need to set the label textvariable=self.label_text instead of text=self.label_text
import tkinter as tk
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.title('Hello Tkinter')
self.label_text = tk.StringVar()
self.label_text.set("Choose One")
label = tk.Label(self, textvariable=self.label_text)
label.pack(fill=tk.BOTH, expand=1, padx=100, pady=30)
hello_button = tk.Button(self, text='Say Hello',
command=self.say_hello)
hello_button.pack(side=tk.LEFT, padx=(20, 0), pady=(0, 20))
goodbye_button = tk.Button(self, text ='Say Goodbye',
command=self.say_goodbye)
goodbye_button.pack(side=tk.RIGHT, padx=(0, 20), pady=(0, 20))
def say_hello(self):
self.label_text.set("Hello World!")
def say_goodbye(self):
self.label_text.set("Goodbye! \n (Closing in 2 seconds)")
self.after(2000, self.destroy)
if __name__ == "__main__":
window = Window()
window.mainloop()

Is it possible to grab input from the topview tkinter window and retrieve saved entry field value from within master tk window

The program is made up of classes and I am trying to use a tkinter topview from within a function so that when it's called it is able to retrieve the entryfield value to the master class
from tkinter import
from PIL import Image, ImageTk
Below is the driver code handling the transitioning from one class to another
class SeaofBTCapp(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = 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 (
WelcomePage, Register_new_user): # ,PageThree,PageFour):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(WelcomePage)
# def show_frame(self, cont):
# frame = self.frames[cont]
# frame.tkraise()
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.update()
frame.event_generate("<<show_frame>>")
def get_page(self, cont):
for page in self.frames.values():
if str(page.__class__.__name__) == cont:
return page
return None
class Register_new_user(object):
pass
Below is the entry point of the program and is the first page to be displayed
class WelcomePage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
# self.bind("<<show_frame>>", self.main_prog)
def resize_image(event):
global photo
new_width = event.width
new_height = event.height
image = copy_of_image.resize((new_width, new_height))
photo = ImageTk.PhotoImage(image)
label.config(image=photo)
label.image = photo # avoid garbage collection
def pin_input():
top = Toplevel()
top.geometry("180x100")
top.title("toplevel")
l2 = Label(top, text="This is toplevel window")
global entry_1
global password
password = StringVar
entry_1 = None
def cleartxtfield():
global password
new = "3"
password.set(new)
# ############# Function to parse for only numerical input
def validate(input):
if input.isdigit():
return True
elif input == "":
return True
else:
return False
def enternumber(x):
global entry_1
setval = StringVar()
setval = str(x)
# print(setval)
entry_1.insert(END, setval)
entry_1 = Entry(top, textvariable=password, width=64, show='*')
entry_1.place(x=200, y=100)
entry_1.focus()
reg = top.register(validate)
entry_1.config(validate="key", validatecommand=(reg, '%P'))
def getcreds():
# check if four digit entered and is not empty
global passwd
passwd = password.get()
print(f"The Credentials are {passwd}")
def funcbackspace():
length = len(entry_1.get())
entry_1.delete(length - 1, 'end')
def killwindow():
# when the user quits it should clear all the data input fields filled in in the previous steps. and should display information that it is about to quit in a few seconds
command = top.destroy()
# Label(top,text="Goodbye\n (Closing in 2 seconds)")
top.after(2000, top.quit())
cancel = Button(top, width=8, height=3, text="Cancel", bg="red", fg="black", command=killwindow)
cancel.place(x=220, y=150)
backspace = Button(top, width=8, height=3, text="Backspace", bg="red", fg="black", command=funcbackspace)
backspace.place(x=500, y=150)
# ----number Buttons------
def enternumber(x):
global entry_1
setval = StringVar()
setval = str(x)
# print(setval)
entry_1.insert(END, setval)
btn_numbers = []
for i in range(10):
btn_numbers.append(
Button(top, width=8, height=3, text=str(i), bd=6, command=lambda x=i: enternumber(x)))
btn_text = 1
for i in range(0, 3):
for j in range(0, 3):
btn_numbers[btn_text].place(x=220 + j * 140, y=250 + i * 100)
btn_text += 1
btn_zero = Button(top, width=15, height=2, text='0', bd=5, command=lambda x=0: enternumber(x))
btn_zero.place(x=330, y=550)
clear = Button(top, text="Clear", bg="green", fg="white", width=8, height=3, command=cleartxtfield)
clear.place(x=220, y=550)
okbtn = Button(top, text="Enter", bg="green", fg="black", width=8, height=3, command=getcreds)
okbtn.place(x=500, y=550)
val = getcreds()
print("The value to be returned is %s" % val)
return val
password = pin_input()
print("Gotten password is %s" % password)
copy_of_image = Image.open("image.png")
photoimage = ImageTk.PhotoImage(copy_of_image)
label = Label(self, image=photoimage)
label.place(x=0, y=0, relwidth=1, relheight=1)
label.bind('<Configure>', resize_image)
top_left_frame = Frame(self, relief='groove', borderwidth=2)
top_left_frame.place(relx=1, rely=0.1, anchor=NE)
center_frame = Frame(self, relief='raised', borderwidth=2)
center_frame.place(relx=0.5, rely=0.75, anchor=CENTER)
Button(top_left_frame, text='REGISTER', bg='grey', width=14, height=1,
command=lambda: controller.show_frame(Register_new_user)).pack()
Button(center_frame, text='ENTER', fg='white', bg='green', width=13, height=2,
command=lambda: controller.show_frame(Register_new_user)).pack()
if __name__ == '__main__':
app = SeaofBTCapp()
app.title("Password return on topview window")
width = 1000
height = 700
screenwidth = app.winfo_screenwidth()
screenheight = app.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
app.geometry(alignstr)
# app.resizable(width=False, height=False)
app.resizable(width=True, height=True)
app.mainloop()
If I understand this correctly you want to enter a password in a dialog and then get the password from the dialog when you close it.
Have a look at Dialog Windows at effbot for a discussion about creating dialog windows.
Here is an example of how you can implement a simple dialog:
from tkinter import *
from tkinter import simpledialog
class MyDialog(simpledialog.Dialog):
def body(self, master):
'''create dialog body.
return widget that should have initial focus.
This method should be overridden, and is called
by the __init__ method.'''
Label(master, text='Value:').grid(row=0)
self.e1 = Entry(master)
self.e1.grid(row=0, column=1)
return self.e1 # initial focus
def apply(self):
'''process the data
This method is called automatically to process the data, *after*
the dialog is destroyed. By default, it does nothing.'''
value = self.e1.get()
self.result = value
def validate(self):
'''validate the data
This method is called automatically to validate the data before the
dialog is destroyed. By default, it always validates OK.'''
return 1 # override
def buttonbox(self):
'''add standard button box.
override if you do not want the standard buttons
'''
box = Frame(self)
w = Button(box, text="OK", width=10, command=self.ok, default='active')
w.pack(side='left', padx=5, pady=5)
w = Button(box, text="Cancel", width=10, command=self.cancel)
w.pack(side='left', padx=5, pady=5)
self.bind("<Return>", self.ok)
self.bind("<Escape>", self.cancel)
box.pack()
if __name__ == '__main__':
root = Tk()
root.geometry('200x100+800+50')
def do():
d = MyDialog(root)
print(d.result)
b = Button(root, text='Go!', width=10, command=do)
b.pack(expand=True)
Did that answer your question?

Ttk Frame, Background color

I'm using ttk, for my GUI. I know that it is also a very simple question ... I am trying to change the background color of the main window.
I tried to change the theme, because I am working on a Mac, (and Python 3.5) to avoid the problem with the theme 'aqua', which is the default.I've been reading about several solutions like these questions which are about the same problem... These are the numbers of the questions:
54476511,
38712352,
47327266,
23750141.
But, I haven't Solve the problem, yet.
Here it's my code.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from tkinter.scrolledtext import *
from tkinter import Tk, BOTH, W, N, E, S, messagebox, END
from tkinter.ttk import Button, Label, Style, Frame
class Example(Frame):
def __init__(self,master):
super().__init__()
self.initUI()
def initUI(self):
self.master.title("Example")
Style().theme_use("classic")
self.pack(fill=BOTH, expand=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
self.txt_Pad = ScrolledText(self)
self.txt_Pad.grid(row=1, column=0, columnspan=2, rowspan=4, padx=5, sticky=E+W+S+N)
self.txt_Pad.insert(END,'Type your info here')
btn_save = Button(self, text="Save", command=self.save_command)
btn_save.grid(row=1, column=3)
btn_close = Button(self, text="Close", command=self.onClose)
btn_close.grid(row=2, column=3, pady=4)
btn_help = Button(self, text="Help", command=self.about_command)
btn_help.grid(row=5, column=0, padx=5)
def onClose(self):
self.master.destroy()
def about_command(self):
msb = messagebox.showinfo("About", "\"Insert a useful tip Here\"")
def save_command(self):
print('Your info it\'s save now')
def open_command(self):
print('Choose your File')
def main():
root = Tk()
root.geometry("350x300+300+300")
root.configure(bg='#0059b3')
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
Any Suggestions would be appreciated.
Create a style then apply it.
from tkinter.scrolledtext import *
from tkinter import Tk, BOTH, W, N, E, S, messagebox, END
from tkinter.ttk import Button, Label, Style, Frame
class Example(Frame):
def __init__(self, master):
super().__init__()
self.initUI()
def initUI(self):
self.master.title("Example")
# create a new style
self.style = Style()
# configure it to the background you want
self.style.configure('My.TFrame', background='#0059b3')
#Style().theme_use("classic")
# apply it
self.config(style='My.TFrame')
self.pack(fill=BOTH, expand=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(3, pad=7)
self.rowconfigure(3, weight=1)
self.rowconfigure(5, pad=7)
self.txt_Pad = ScrolledText(self)
self.txt_Pad.grid(row=1, column=0, columnspan=2, rowspan=4, padx=5, sticky=E+W+S+N)
self.txt_Pad.insert(END,'Type your info here')
btn_save = Button(self, text="Save", command=self.save_command)
btn_save.grid(row=1, column=3)
btn_close = Button(self, text="Close", command=self.onClose)
btn_close.grid(row=2, column=3, pady=4)
btn_help = Button(self, text="Help", command=self.about_command)
btn_help.grid(row=5, column=0, padx=5)
def onClose(self):
self.master.destroy()
def about_command(self):
msb = messagebox.showinfo("About", "\"Insert a useful tip Here\"")
def save_command(self):
print('Your info it\'s save now')
def open_command(self):
print('Choose your File')
def main():
root = Tk()
root.geometry("350x300+300+300")
root.configure(background='#0059b3')
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()
I left comments at the parts I changed.

tkinter error calling function through entries in listbox

Recently, I tried to make a full application window with a side panel menu with separate frames running some functions and submitting forms in the canvas frame.
But I found that every time I click on any entry in listbox it runs the function or method without clearing the existing one .
I tried destroy() and forget() didn't work for me (maybe I didn't know exactly how to use it?!, and the destroy() function prevent using the function again till I close the whole application and run it again!) this is a photo of my problem
this is my code :
import tkinter as tk
from tkinter import ttk
class MainWindow() :
def __init__(self,root):
# menu left
self.menu_upper_frame = tk.Frame(root, bg="#dfdfdf")
self.menu_title_label = tk.Label(self.menu_upper_frame, text="menu title", bg="#dfdfdf")
self.menu_title_label.pack()
self.menu_left_container = tk.Frame(root, width=150, bg="#ababab")
self.menu_left_upper = tk.Frame(self.menu_left_container, width=150, height=150, bg="red")
self.menu_left_upper.pack(side="top", fill="both", expand=True)
# create a listbox of items
self.Lb1 = tk.Listbox(self.menu_left_upper,bg ="red", borderwidth=0, highlightthickness=0 )
self.Lb1.insert(1, "Python")
self.Lb1.insert(2, "Perl")
self.Lb1.insert(3, "C")
self.Lb1.insert(4, "PHP")
self.Lb1.insert(5, "JSP")
self.Lb1.insert(6, "Ruby")
self.Lb1.bind("<<ListboxSelect>>", self.OnClick ) #return selected item
self.Lb1.pack(fill="both", expand=True, pady=50 )
# right area
self.inner_title_frame = tk.Frame(root, bg="#dfdfdf")
self.inner_title_label = tk.Label(self.inner_title_frame, text="inner title", bg="#dfdfdf")
self.inner_title_label.pack()
self.canvas_area = tk.Canvas(root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)
# status bar
self.status_frame = tk.Frame(root)
self.status = tk.Label(self.status_frame, text="this is the status bar")
self.status.pack(fill="both", expand=True)
self.menu_upper_frame.grid(row=0, column=0, rowspan=2, sticky="nsew")
self.menu_left_container.grid(row=1, column=0, rowspan=2, sticky="nsew")
self.inner_title_frame.grid(row=0, column=1, sticky="ew")
self.canvas_area.grid(row=1, column=1, sticky="nsew")
self.status_frame.grid(row=2, column=0, columnspan=2, sticky="ew")
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(1, weight=1)
def OnClick(self,event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection)
if value == 'Python':
self.tabtop()
def tabtop(self):
self.tabControl = ttk.Notebook(self.canvas_area, width=400) # Create Tab Control
self.tab1 = ttk.Frame(self.tabControl) # Create a tab
self.tab2 = ttk.Frame(self.tabControl)
self.tab3 = ttk.Frame(self.tabControl)
self.tab4 = ttk.Frame(self.tabControl)
self.tab5 = ttk.Frame(self.tabControl)
self.tabControl.add(self.tab1, text='Login data' ) # Add the tab
self.tabControl.add(self.tab2, text='Permission')
self.tabControl.add(self.tab3, text='Roles')
self.tabControl.add(self.tab4, text='Personal data')
self.tabControl.add(self.tab5, text='Business data')
self.tabControl.pack(expand=1, fill="both") # Pack to make visible
self.l2 = tk.Label(self.tab2, text="label 2").pack()
self.l3 = tk.Label(self.tab3, text="label 3").pack()
root = tk.Tk()
root.title("Control Panel")
root.style = ttk.Style()
root.style.theme_use("clam")
user = MainWindow(root)
root.mainloop()
If what you're really asking is how to replace an existing notebook with a new notebook, all you need to do is call destroy() on the old notebook before creating the new one.
First, define self.tabControl to None somewhere in MainWindow.__init__. Then, in tabtop you can delete the old notebook before creating the new one:
def tabtop(self):
if self.tabControl is not None:
self.tabControl.destroy()
...

Resources