In the code below, app is an instance of mainWindow, which inherits from Tkinter.Frame. I am trying to use the Frame.Configure method to change the background color of the Frame.However, calling self.configure(background="yellow") doesn't work. Can someone help me understand what mistake I am making?
import Tkinter
class mainWindow(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, master=parent)
self.parent=parent
self.button1=Tkinter.Button(master=self.parent, text='ONE', command=self.change)
self.button1.pack()
self.pack()
def change(self):
self.parent.wm_title("Changed")
self.configure(background="yellow")
root = Tkinter.Tk()
root.geometry("600x600+50+50")
app=mainWindow(root)
root.mainloop()
It does not work, because your Frame is "tiny". It does not contain any widgets (button's parent is the top window, not the frame). So to make frame big, thus visible, you need to expand it:
import Tkinter
class mainWindow(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, master=parent)
self.parent=parent
self.button1=Tkinter.Button(master=self.parent,
text='ONE',
command=self.change)
self.button1.pack()
self.pack(fill=Tkinter.BOTH, expand=1) #<--- expand frame
def change(self):
self.parent.wm_title("Changed")
self.configure(background="yellow")
root = Tkinter.Tk()
root.geometry("600x600+50+50")
app=mainWindow(root)
root.mainloop()
Try self.parent.configure(background="yellow")
I'm new to Tkinter (few-minute new), so my guess based on your code is that the frame is not showing at all. The frame's parent is root, which is also the button's parent.
So here, I'm changing the root's (top level widget) background
Edited:
Base on my reasoning above, and Marcin's answer, I deduce that the frame simply just does not have a size. So here's an edited version of your code with the frame expanded, and the frame will contain the button.
import Tkinter
class mainWindow(Tkinter.Frame):
def __init__(self, parent):
Tkinter.Frame.__init__(self, master=parent)
self.parent=parent
self.button1=Tkinter.Button(master=self, text='ONE', command=self.change)
self.button1.pack()
self.pack(fill=Tkinter.BOTH, expand=True)
def change(self):
self.parent.wm_title("Changed")
self.configure(background="yellow")
root = Tkinter.Tk()
root.geometry("600x600+50+50")
app=mainWindow(root)
root.mainloop()
Related
I have a main class for my gui and I added a ttk.NoteBook after a label:
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('1000x500')
self.configure(background='#F0F8FF')
#TOP LABEL
load = Image.open("my_image")
load = load.resize((200, 67), Image.ANTIALIAS)
self.render = ImageTk.PhotoImage(load)
self.Label_top = tk.Label(self, image=self.render, compound=tk.LEFT, text="TOOL")
self.Label_top.pack()
#--Notebook---------
self.notebook = ttk.Notebook(self)
self.Page1 = Page1(self.notebook)
self.Page2 = Page2(self.notebook)
self.Page3 = Page3(self.notebook)
self.Page4 = Page4(self.notebook)
self.notebook.add(self.Page1, text='PAGE1')
self.notebook.add(self.Page2, text='PAGE2')
self.notebook.add(self.Page3, text='PAGE3')
self.notebook.add(self.Page4, text='PAGE4')
self.notebook.pack(fill='x', side=TOP)
#expand=True create empty space between my top label and my notebook, even with side=TOP
And I defined each frame in a class like this :
class Page1(ttk.Frame):
def __init__(self, container):
super().__init__()
self.(width=400, height=280) #Error message
self.pack(expand=True) #Doesn't work
Do you know how can I expand my frame for that it fills my page and pack the notebook just after my top label
I think this will do what you want. I've incorporated most of the things #Bryan Oakley mentioned in his answer except I also added a BasePage class and derived all the other Page classes from it. This was done to provide a place to put code that would otherwise need to be repeated each of the subclasses.
I also changed some of your variable names to conform to PEP 8 Naming Conventions.
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *
class BasePage(ttk.Frame):
def __init__(self, container):
super().__init__(container, width=400, height=280)
classname = type(self).__name__
tk.Label(self, text=f'Welcome to {classname}').place(relx=0.5, rely=0.25,
anchor=CENTER)
class Page1(BasePage):
def __init__(self, container):
super().__init__(container)
class Page2(BasePage):
def __init__(self, container):
super().__init__(container)
class Page3(BasePage):
def __init__(self, container):
super().__init__(container)
class Page4(BasePage):
def __init__(self, container):
super().__init__(container)
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('1000x500')
self.configure(background='#F0F8FF')
#--Notebook---------
self.notebook = ttk.Notebook(self)
self.page1 = Page1(self.notebook)
self.page2 = Page2(self.notebook)
self.page3 = Page3(self.notebook)
self.page4 = Page4(self.notebook)
self.notebook.add(self.page1, text='Page1')
self.notebook.add(self.page2, text='Page2')
self.notebook.add(self.page3, text='Page3')
self.notebook.add(self.page4, text='Page4')
self.notebook.pack(expand=True, fill=BOTH)
app = MainApplication()
app.mainloop()
I see three problems.
First, each "page" needs to be a child of the notebook. You do that by making sure the notebook is passed to the __init__ of the frame:
class Page1(ttk.Frame):
def __init__(self, container):
super().__init__(container)
Second, you need to not call pack on the page. self.notebook.add is already adding the frame to the notebook. So, remove the line self.pack(expand=True) from each page.
Third, self.(width=400, height=280) needs to be self.configure(width=400, height=280)
So I want to just change the background of my frames so I can layout them properly and I can't seem to change styles for my frames.
style.configure('TFrame', background='red')
style.configure('Blue.TFrame', background='blue')
main_window = MainWindow(root, style='Blue.TFrame')
The above code resuslts in a red background, while I need it to change to blue, and if I don't change TFrame background, there is just no backgound color at all.
My MainWindow class does inherit from ttk.Frame, so I don't know if that is what's causing it...
Minimal Reproducible Example:
import tkinter as tk
from tkinter import ttk
class MainWindow(ttk.Frame):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent)
self.parent = parent
# Search_company shortcut
self.search_comp = ttk.Entry(self)
self.search_comp.grid(row=0, column=0)
def main():
root = tk.Tk()
root.state('zoomed')
# Configuring styles
style = ttk.Style()
style.configure('TFrame', background='red')
style.configure('Blue.TFrame', background='blue')
main_window = MainWindow(root, style='Blue.TFrame')
main_window.grid(row=0, column=1, sticky='nsew')
root.mainloop()
if __name__ == "__main__":
main()
You aren’t passing the style option to the superclass. It needs to be this:
super().__init__(parent, *args, **kwargs)
As the title says, I've created a class that inherits from tkinter's LabelFrame (BatteryCapacityLFrame), and I'm trying to initialize it such that it will display like a LabelFrame. However, when I run the code the Battery tab doesn't display a LabelFrame. How do I fix this (what I presume to be) inheritance issue?
Code:
import tkinter as tk
from tkinter import ttk
from tkinter import *
class PanelManager(tk.Tk):
def __init__ (self):
#initializing tkinter within initialization function
tk.Tk.__init__(self)
self.title("Combat Robotics Calculator")
self.panel_manager = ttk.Notebook(self)
self.add_battery_tab("Batteries")
self.add_tab("Pulleys")
self.add_tab("Drive System")
self.add_tab("Weapon System")
def add_tab(self, title):
tab_frame = Frame(self.panel_manager)
self.panel_manager.add(tab_frame, text = title)
self.panel_manager.pack()
def add_battery_tab(self, title):
battery_tab = BatteryTab(self)
self.panel_manager.add(battery_tab, text = title)
self.panel_manager.pack()
def run(self):
self.mainloop()
class BatteryTab(tk.Frame):
def __init__ (self, master):
tk.Frame.__init__(self, master)
#Capacity Calculator
capacity_calcf = BatteryCapacityLFrame(self)
capacity_calcf.grid(column = 1, row = 1, sticky = "news")
#I'm trying to initialize the class here, not sure what's going wrong
class BatteryCapacityLFrame(tk.LabelFrame):
def __init__ (self, master):
tk.LabelFrame.__init__(self, master)
self.config(text = "Battery Capacity Calculator")
root_window = PanelManager()
root_window.run()
Thank you all so much for your time!
You need to add something to the labelframe for it to show up.
class BatteryCapacityLFrame(tk.LabelFrame):
def __init__(self, master):
tk.LabelFrame.__init__(self, master)
self.config(text="Battery Capacity Calculator")
tk.Label(self, text='Test message.').grid()
I'm trying to learn OOP using tkinter. I want to create two classes, one for the main Frame and the other for a simple Label, and then grid the Label to the Frame with an OOP approach.
Something like...
import tkinter as tk
class main_frame(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self)
class label1(tk.Label):
def __init__ (self, *args, **kwargs):
tk.Label.__init__(self)
#label = tk.Label(main_frame, text='lol')???
root = tk.Tk()
main_frame(root).grid(row = 0, column = 0)
#label1(main_frame).grid(row=1,column=0) ???
root.mainloop()
My code might not be making any sense compared to a correct OOP approach to this. I appreciate any help.
The main_frame widget needs to be a child of the Tk window, and then the label1 widget needs to be a child of the of the main_frame widget. Here is my solution:
import tkinter as tk
class main_frame(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master)
self.label = label1(self)
self.label.grid(row = 0, column = 0)
class label1(tk.Label):
def __init__ (self, master, *args, **kwargs):
tk.Label.__init__(self, master, text="test")
root = tk.Tk()
root.mainframe = main_frame(root)
root.mainframe.pack()
root.mainloop()
Note how each widget passes itself as master to each other widget.
I posted a question about this topic a few days ago but since my sample code in that question was wrong I deleted that topic to come up with a cleaner sample code.
what's the best practice to navigate through different pages/windows in a GUI built by Tkinter? simply, I want to be able to go through different pages in my App, via commands from my menubar. I want to avoid stacking pages on top of each other and a method in which you use grid_remove() or pack_forget() is preferable to me.
The only other tutorial which I found here uses the stacking method and lift(). is there any other better way?
import tkinter as tk
from tkinter import *
class MainWin(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.page_1 = Page1(self.parent)
self.page_2 = Page2(self.parent)
self.init_UI()
def init_UI(self):
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
self.parent.title('Frame Switching test app')
file_menu = Menu(menubar)
pages_menu = Menu(menubar)
menubar.add_cascade(label='File', menu=file_menu)
file_menu.add_command(label='Exit', command=self.on_exit)
menubar.add_cascade(label='Pages', menu=pages_menu)
pages_menu.add_command(label='Pages 1', command=self.page_1.show)
pages_menu.add_command(label='Page 2', command=self.page_2.show)
def on_exit(self):
self.quit()
class Page1(LabelFrame):
def __init__(self, parent):
LabelFrame.__init__(self, parent)
self.parent = parent
self.config(text='This is page 1 label Frame')
self.sample_text = Label(self, text='You are viewing Page 1')
def show(self):
self.pack(fill=BOTH, expand=1)
self.sample_text.grid(in_=self)
self.lift()
def close(self):
self.pack_forget()
class Page2(LabelFrame):
def __init__(self, parent):
LabelFrame.__init__(self, parent)
self.parent = parent
self.config(text='This is page 2 label Frame')
self.sample_text = Label(self, text='You are viewing Page 2')
def show(self):
self.pack(fill=BOTH, expand=1)
self.sample_text.grid(in_=self)
self.lift()
def close(self):
self.pack_forget()
def main():
root = tk.Tk()
app = MainWin(root)
root.mainloop()
if __name__ == '__main__':
main()
There's already a question and answer that shows how to stack frames. To switch to a mode where you use grid_forget or pack_forget you only have to change the code that calls lift to instead call the appropriate "forget" method on the current page (which you'll need to keep track of), and then add the new window.
If you want to create the pages on demand, and destroy them when they aren't in use, that's easy too. The only real difference is that you don't create the page until it is asked for, and delete it when you are done. Otherwise the implementation is identical.
Following is an example of creating the pages on demand. Starting with the code in this answer, modify the SampleApp class to look like this:
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
# the container is where we'll pack the current page
self.container = tk.Frame(self)
self.container.pack(side="top", fill="both", expand=True)
self.current_frame = None
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
# destroy the old page, if there is one
if self.current_frame is not None:
self.current_frame.destroy()
# create the new page and pack it in the container
cls = globals()[page_name]
self.current_frame = cls(self.container, self)
self.current_frame.pack(fill="both", expand=True)