Here is an example of my code
import tkinter as tk
from tkinter import ttk
class gui_programming(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="left", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, Page1):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
##number 1
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
c = tk.Canvas(self, bg="red", width=75, height=100)
c.place(x=0, y=0)
butt0 = ttk.Button(self, text="Next.", command=lambda:controller.show_frame(Page1))
controller.bind("1", lambda x: controller.show_frame(StartPage))
controller.bind("2", lambda x: controller.show_frame(Page1))
controller.bind("3", lambda x: controller.show_frame(Page2))
class Page1(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
lambda x: gui_programming().geometry("75x100+10+10")
c = tk.Canvas(self, bg="blue", width=300, height=200)
c.place(x=0, y=0)
app = gui_programming()
app.geometry("75x100+10+10")
app.mainloop()
So, how should I go about changing the window that each class appears in from 75x100 to something else, is there a command to resize the window? I would like to be able to resize it for each class.
You already resized the app window from its default with
app.geometry("75x100+10+10")
Repeat this with a different size.
I recommend to always use variables in geometry
e.g
w=500
h=500
master.geometry(('{}x{}').format(w,h))
Call geometry inside __init__ method:
class gui_programming(tk.Tk):
def __init__(self, *args, **kwargs):
...
self.geometry("75x100+10+10")
Related
So I have my Tkinter application that consist of multiple frame
All these multiple frames contain the same basic structure of many buttons; the only difference is that the buttons have a different bg on each page.
In my actual project, these buttons contain so many options, and so having to write the same basic code each time for all pages makes my code look unnecessarily long.
So I'm thinking: Is there a way to put all these buttons into a dictionary or list, and pack them onto each separate frame? (Bear in mind the button will need to inherit the bg variable from the specific frame.)
I've created a minimal example to illustrate what I mean:
import tkinter as tk
from tkinter import *
listt = []
self = None
bg_colour_for_this_frame = None
button1 = Button(self,text="Button 1",bg=bg_colour_for_this_frame,fg='white')
button2 = Button(self,text="Button 2",bg=bg_colour_for_this_frame,fg='blue')
button3 = Button(self,text="Button 3",bg=bg_colour_for_this_frame,fg='orange')
listt.append(button1)
listt.append(button2)
listt.append(button3)
class Tkinter(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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, SecondPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.winfo_toplevel().geometry("860x864")
frame.configure(bg='#000000')
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Button(self,text='SecondPage',command=lambda:controller.show_frame(SecondPage)).pack()
for s in listt:
s.pack()
class SecondPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Button(self,text='StartPage',command=lambda:controller.show_frame(StartPage)).pack()
for s in listt:
s.pack()
app = Tkinter()
app.mainloop()
Or maybe, instead of having a list, use a dictionary:
listt = {'button1':'Button[root,text="Button 1",bg=bg_colour_for_this_frame,fg="white"]',
'button2':'Button[root,text="Button 2",bg=bg_colour_for_this_frame,fg="red"]',
'button3':'Button[root,text="Button 3",bg=bg_colour_for_this_frame,fg="blue"]',
}
I get the error:
s.pack()
AttributeError: 'str' object has no attribute 'pack'
Since you can't create the Buttons before the page they're on exists, It would be simpler to make a function and call it during the initialization of each of the page classes — like the make_buttons() shown below:
import tkinter as tk
from tkinter import *
# Button options for all pages.
BTN_OPTS = [dict(text="Button 1", fg='white'),
dict(text="Button 2", fg='blue'),
dict(text="Button 3", fg='orange')]
def make_buttons(parent, bg_colour):
return [Button(parent, bg=bg_colour, **opts) for opts in BTN_OPTS]
class Tkinter(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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, SecondPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.winfo_toplevel().geometry("860x864")
frame.configure(bg='#000000')
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Button(self, text='SecondPage',
command=lambda: controller.show_frame(SecondPage)).pack()
for btn in make_buttons(self, 'Pink'):
btn.pack()
class SecondPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
Button(self, text='StartPage',
command=lambda: controller.show_frame(StartPage)).pack()
for btn in make_buttons(self, 'green'):
btn.pack()
app = Tkinter()
app.mainloop()
A more sophisticated and object-oriented approach would be to define a base class for all page classes that had a method in it something like the function above, and then derive the concrete subclasses from that allowing them just inherit the method. It also gets rid of the global data because the button options are now in a (base) class attribute.
Here's a runnable example of how it could be done that way. Note: it requires Python 3.6+ because it uses object.__init_subclass__() which was added in that version:
import tkinter as tk
class Tkinter(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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, SecondPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.winfo_toplevel().geometry("860x864")
frame.configure(bg='#000000')
class BasePage(tk.Frame):
# Button options common to all pages.
BTN_OPTS = [dict(text="Button 1", fg='white'),
dict(text="Button 2", fg='blue'),
dict(text="Button 3", fg='orange')]
#classmethod
def __init_subclass__(cls, /, bg_color, **kwargs):
super().__init_subclass__(**kwargs)
cls.bg_color = bg_color
def __init__(self, parent, controller, text, command):
super().__init__(parent)
tk.Button(self, text=text, command=command).pack() # Next page button.
for btn in (tk.Button(self, bg=self.bg_color, **opts) for opts in self.BTN_OPTS):
btn.pack()
class StartPage(BasePage, bg_color='pink'):
def __init__(self, parent, controller):
super().__init__(parent, controller, text='SecondPage',
command=lambda: controller.show_frame(SecondPage))
class SecondPage(BasePage, bg_color='green'):
def __init__(self, parent, controller):
super().__init__(parent, controller, text='StartPage',
command=lambda: controller.show_frame(StartPage))
app = Tkinter()
app.mainloop()
I'm using a listbox with a scrollbar with Tkinter in python. I'm trying to put the scrollbar on the right of the page and allow it to expand if the user expands the window, and also have the listbox placed in the middle of the window, but for some reason the listbox is just stretching to the right and bottom of the page permanently, even when its not expanded
Here's my code, thanks for any help in advance.
from tkinter import *
import tkinter as tk
class SeaofBTCapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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,Task):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
frame.winfo_toplevel().geometry("1024x720")
frame.configure(bg='#333130')
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
global listboxz
listboxz = Listbox(self,height='500',width='400')
listboxz.place(x=10, y=120)
scrollbar = Scrollbar(self)
scrollbar.pack(side=RIGHT, fill=Y)
listboxz.configure(yscrollcommand=scrollbar.set)
scrollbar.configure(command=listboxz.yview)
class Task(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
app = SeaofBTCapp()
app.mainloop()
To place something in the middle of the page with place() you need to use relx and rely, like this:
listboxz.place(relx=.5, rely=.5, anchor='c')
Using the method suggested in Switch between two frames in tkinter I have tried to switch between a login frame and a register frame. Nevertheless, when showFrame(register) is called after the register button is pressed on the login screen, an attribute error occurs:
(frame=self.frames[pageName]; AttributeError:'loginScreen' object has no
attribute 'frames')
class mainActivity(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 (loginScreen, register):
frame = F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="snew")
self.showFrame(loginScreen)
def showFrame(self, pageName):
frame=self.frames[pageName]
frame.tkraise()
#-------------------------------------------------
class loginScreen(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller=controller
self.regBtn =Button(self, text="Register", command=self.regBtnClicked)
self.regBtn.grid(row=2,column=1)
self.grid()
def regBtnClicked(self):
mainActivity.showFrame(self, register)
#send to register screen
#-------------------------------------------------
class register(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller=controller
self.grid(row=0, column=0)
self.cancelBtn = Button(self, text="Cancel",command=self.cancelBtnClicked)
self.cancelBtn.grid(row=4, column=1)
def cancelBtnClicked(self):
#return to login screen
mainActivity.showFrame(self, loginScreen)
app = mainActivity()
app.mainloop()
There are several issues with your code. First you are missing an important potion of the for F in (loginScreen, register): for loop.
You need to have:
page_name = F.__name__
This is the line of code that is used to provide the string name for the key portion of the self.frames dictionary.
So instead of doing:
self.frames[F]=frame
Do this instead:
self.frames[page_name] = frame
Try to use the print statement while troubleshooting. All it took was for me to add print(self.frames) right before the error was occurring to have an idea of what is going wrong here.
You will also need to change self.showFrame(loginScreen) to self.showFrame("loginScreen") as well as any other call to showFrame() to reflect the same change.
Another issue you were having was this line:
mainActivity.showFrame(self, loginScreen)
You need to reference the controller instead here like this:
self.controller.showFrame("loginScreen")
You do not need self.grid(row=0, column=0) in your frame class's because these have already been set in your for loop. No need to do it again.
With all that take a look at the below code:
from tkinter import *
class mainActivity(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container=Frame(self)
container.pack(side="top", fill="both", expand=True)
self.frames={}
for F in (loginScreen, register):
page_name = F.__name__
frame = F(container, self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="snew")
print(self.frames)
self.showFrame("loginScreen")
def showFrame(self, pageName):
frame=self.frames[pageName]
frame.tkraise()
#-------------------------------------------------
class loginScreen(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller=controller
self.regBtn = Button(self, text="Register", command=self.regBtnClicked)
self.regBtn.grid(row=2,column=1)
def regBtnClicked(self):
self.controller.showFrame("register")
#-------------------------------------------------
class register(Frame):
def __init__(self, parent, controller):
Frame.__init__(self, parent)
self.controller=controller
self.cancelBtn = Button(self, text="Cancel",command=self.cancelBtnClicked)
self.cancelBtn.grid(row=4, column=1)
def cancelBtnClicked(self):
self.controller.showFrame("loginScreen")
app = mainActivity()
app.mainloop()
I have a problem with my code:
I want that the OK-button (tkinter) in a popup-window (exp_Name) makes three things when it gets pressed:
First it should store a string from the Entry (in the popup-window) in a global variable
exp_name = entry.get()
Second it should open another window
app.show_frame(PageOne)
Third it should close the popup-window
popup.destroy
I tried to call a function, but I have no idea how I should close the popup window in a separate function. And also how I should store the Entry in a global variable in this separate function.
Thanks a lot!!
Here the whole code:
import tkinter as tk
from tkinter import ttk
global exp_name
exp_name = "Hello"
def exp_Name():
popup = tk.Tk()
popup.geometry("800x400")
label=ttk.Label(popup, text="Enter Something:")
label.pack(side="top", fill="x", pady=10)
entry = ttk.Entry(popup)
entry.pack()
##Here is the problem...
OK_btn=ttk.Button(popup, text="OK", command= lambda: [app.show_frame(PageOne),exp_name = entry.get(), popup.destroy])
OK_btn.pack()
Close_btn=ttk.Button(popup, text="Close",command = popup.destroy)
Close_btn.pack()
popup.mainloop()
class Steppermovementsapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="images/Icon_fly.ico")
tk.Tk.wm_title(self, "Drosophila ADF apparatus")
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, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
exp_btn = ttk.Button(self, text="Start experiment",command=exp_Name)
exp_btn.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label =ttk.Label(self, text=exp_name)
label.pack()
app = Steppermovementsapp()
app.geometry("{0}x{1}".format(app.winfo_screenwidth(),app.winfo_screenheight()))
app.mainloop()
This is how I tried it with a function:
import tkinter as tk
from tkinter import ttk
global exp_name
exp_name = "Hello"
class sidefunctions(tk.Tk):
def func_three(self):
app.show_frame(PageOne)
exp_name = self.entry.get()
popup.destroy
def exp_Name(self):
self.popup = tk.Tk()
self.popup.geometry("800x400")
self.label=ttk.Label(self,text="Enter Something:")
self.label.pack(side="top", fill="x", pady=10)
self.entry = ttk.Entry(self)
self.entry.pack()
self.OK_btn=ttk.Button(self,text="OK", command= self.func_three)
self.OK_btn.pack()
self.Close_btn=ttk.Button(self,text="Close",command =
self.popup.destroy)
self.Close_btn.pack()
self.popup.mainloop()
class Steppermovementsapp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.iconbitmap(self, default="images/Icon_fly.ico")
tk.Tk.wm_title(self, "Drosophila ADF apparatus")
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, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
exp_btn = ttk.Button(self, text="Start experiment",command=sidefunctions().exp_Name)
exp_btn.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label =ttk.Label(self, text=exp_name)
label.pack()
app = Steppermovementsapp()
app.geometry("{0}x{1}".format(app.winfo_screenwidth(),app.winfo_screenheight()))
app.mainloop()
When I try to execute my Tkinter application created in python, it is giving me a blank application window. No Buttons/Labels are displaying. What may be the Issue ?
Codes are as follows:
import tkinter as tk
from tkinter import ttk
LARGE_FONT=("Verdana", 18)
class VNMSapp(tk.Tk):
def __int__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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, AdminPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text="THIS IS HOME PAGE", font=LARGE_FONT)
label.pack()
btn1 = tk.Button(self, text="Enter ADMIN PAGE",
command=lambda: controller.show_frame(AdminPage))
btn1.pack()
class AdminPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(text="THIS IS ADMIN PAGE", font=LARGE_FONT)
label.pack()
btn1 = tk.Button(self, text="Enter HOME PAGE",
command=lambda: controller.show_frame(StartPage))
btn1.pack()
app = VNMSapp()
app.mainloop()
It is not giving me any error also.
There is a typo in the definition of the __init__() method for class VNMSapp:
def __int__(self, *args, **kwargs):
should be
def __init__(self, *args, **kwargs):
As a result your __init__() method is not being called, so your widgets are not created.
Once you correct that you will find an additional problem where you are using a list, but I think that you meant to use a dictionary:
self.frames= []
...
self.frames[F] = frame
the second line will fail raising a TypeError exception because list indices must be integers, which frame objects are not.
Fix that by initialising self.frames to an empty dict:
self.frames= {}