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.
Related
In my code, I'm creating an object called a HistoryFrame that is supposed to inherit from tkinter.Frame. I want to change the background color of my HistoryFrame as a parameter that's passed in on its creation, and when I print kwargs, it accurately reflects a that I've passed in {'bg':'blue', etc...}, but it doesn't change the actual color of the background of the frame.
How do I fix this? and why is this happening?
Picture of Application resulting from code below.
Code below. V---V
import tkinter as tk
class HistoryFrame(tk.Frame):
def __init__(self, parent, *args, **kwargs):
print(kwargs)
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
button = tk.Button(self, text="hello", fg="blue")
button.pack(side=tk.TOP, fill=tk.X)
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
self.width, self.height = max(parent.winfo_screenwidth(), 200), max(
parent.winfo_screenheight(), 200
)
self.history_frame = HistoryFrame.HistoryFrame(
self, width=max(20, self.width // 4), height=self.height, bg="blue"
)
self.history_frame.pack(side=tk.LEFT, fill=tk.X)
if __name__ == "__main__":
root = tk.Tk()
root.geometry("650x250")
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
Your color is working fine. By default, when you add one or more widgets to a frame with pack or grid, the frame will shrink to fit its children. The color is there, it's just that the frame is hidden by the button.
You can observe this by changing how you pack the frame:
self.history_frame.pack(side=tk.LEFT, fill="both", expand=True)
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)
I've been doing a Gui multiple windows quest but Tkinter doesn't seem to have Tk. My full error is
Traceback (most recent call last):
File "/Users/connorsmacbook/PycharmProjects/2.8/2.8 Internal/TextTypers 2.2.py", line 6, in <module>
class TextTypers(tk.TK):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/tkinter/__init__.py", line 2101, in __getattr__
return getattr(self.tk, attr)
AttributeError: '_tkinter.tkapp' object has no attribute 'TK'
My code is
from tkinter import *
tk=Tk()
# Classes
class TextTypers(tk.TK):
def __init__(self, *args, **kwargs): # Runs when our class is called and allows almost anything to be passed
tk.Tk.__init__(self, *args, **kwargs) # Initialise Tk
window = tk.Frame(self) # Creates the container the windows/frames will populate
window.pack()
self.frames = {} # Creates a dictionary for the frames
frame = MenuScreen(window, self)
self.frames[MenuScreen] = frame
frame.grid(row=0, column=0, sticky="nswe")
self.show_frame(MenuScreen) # Shows the menu screen as this is initialising
def show_frame(self, cont):
frame = self.frames[cont] # Grabs value of self.frames and puts in in frame
frame.tkraise() # Raises frame to the front
class MenuScreen(tk.frame): # Inherits everything from the frame
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent) # Inherits from main class
label = tk.Label(self, text="Menu")
label.pack()
run = TextTypers()
run.mainloop()
If any wizards could help I would be grateful :).
The line
tk=Tk()
creates an instance of Tk() with the name tk.
When you create the class
class TextTypers(tk.TK):
you are trying to inherit an attribute called TK from the instance tk.
In general, I would not use the name tk for the root window as tk is usually used as an alias for the tkinter module.
I think what you are after is something like this:
import tkinter as tk
# Classes
class TextTypers(tk.Tk):
def __init__(self, *args, **kwargs): # Runs when our class is called and allows almost anything to be passed
tk.Tk.__init__(self, *args, **kwargs) # Initialise Tk
window = tk.Frame(self) # Creates the container the windows/frames will populate
window.pack()
self.frames = {} # Creates a dictionary for the frames
frame = MenuScreen(window, self)
self.frames[MenuScreen] = frame
frame.grid(row=0, column=0, sticky="nswe")
self.show_frame(MenuScreen) # Shows the menu screen as this is initialising
def show_frame(self, cont):
frame = self.frames[cont] # Grabs value of self.frames and puts in in frame
frame.tkraise() # Raises frame to the front
class MenuScreen(tk.Frame): # Inherits everything from the frame
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent) # Inherits from main class
label = tk.Label(self, text="Menu")
label.pack()
run = TextTypers()
run.mainloop()
Have a look at Best way to structure a tkinter application were you can find some suggestions and discussion.
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()
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()