How to place widgets into different frames in Tkinter, using OOP
Solution 1
I finally found the answer. From what I have found (feel free to edit this if it is wrong) is that there are only two ways that a Frame
can be inherited in Tkinter: from the class itself and from the method that a widget is currently in. To solve the issue, I set up the class Application
as a frame, and then place other frames within it. Here is a basic rendition of what I did:
#Import Tkinter
from Tkinter import *
#Main Frame
class Application(Frame):
def __init__(self, master): #initialize the grid and widgets
Frame.__init__(self,master)
self.grid()
self.redFUN() #initialize the red frame's Function
self.greenFUN() #initialize the green frame's Function
self.widgets() #To show that you can still place non-Frame widgets
def widgets(self):
self.mylabel = Label (self, text = "Hello World!")
self.mylabel.grid()
def redFUN(self): #The 'self' means that it is an instance of the main frame
#Init the red frame
self.redFrame = Frame(root, width = 100, height = 50,pady = 5,
bg = "red")
self.redFrame.grid()
def greenFUN(self): #Child of the mainframe
self.greenFrame = Frame(root, width = 100, height = 50,pady = 5,
bg = "green") #it is green!
self.greenFrame.grid()
#These lines of code are used for the grid
root = Tk()
root.title("Frame Example")
root.geometry("300x300")
app = Application(root)
root.mainloop()
I hope this helps everyone - if you have any questions, feel free to comment!
Solution 2
Problem 1:
A widget can only have one immediate parent. There's no syntax for passing in two parents. You seem to be passing in both self
and self.toolbar
as parents of self.saveButton
, for example.
myButton = Button(self.toolbar, text="Blah", command=self.someCommand)
is the form you should use.
Problem 2:
Let's say that you instead wanted Application
(AKA the self
in Button(self, self.toolbar...)
) to be the parent of myButton
. This won't work either, because in order to be the hierarchical parent of a Tk widget, a class must also be an instance of Widget
. Usually, what you do if you want this is to inherit tk.Tk()
in Application
as follows:
class Application(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs) #It's important that you call the parent class's __init__ method first
self.createWidgets()
def createWidgets(self):
self.myButton = Button(self, text="Blah", command=lambda x: print "x")
#this is ok, because now self (AKA Application) is a valid instance of Tk
xxmbabanexx
I am just starting out with programming, and the StackOverflow website is epic! I head the Python Programming Club at my middle school and am learning alongside my friends. My languages: Python (Including Tkinter) HTML (A little bit) I have the Tumbleweed badge due to this lovely post on Super User (Which is actually relevant.) My 'greatest' answer ever!
Updated on June 04, 2022Comments
-
xxmbabanexx almost 2 years
Background
Hello everyone! I am currently working on a basic GUI text editor which can load and save text files. I want to use multiple frames for the toolbar and the textbox as I learned here. I am using OOP, and have set up my frames in the
__init__
method, and the widgets in thewidget
method. For some reason, the widgets are unable to be placed within their respective Frames.Code
from Tkinter import * class Application: def __init__(self,parent): #initialize the grid and widgets self.myParent = parent #Init the toolbar self.toolbar = Frame(parent) self.toolbar.grid(row = 0) #Init frame for the text box self.mainframe = Frame(parent) self.toolbar.grid(row = 1) def widget(self):#Place widgets here #Save Button self.saveButton = Button (self, self.toolbar, text = "Save", command = self.saveMe) self.saveButton.grid(column = 0, row = 0, sticky = W) #Open Button self.openButton = Button (self, self.toolbar, text = "Open", command = self.openMe) self.openButton.grid(column = 0, row = 1, sticky = W) #Area where you write self.text = Text (self, self.mainframe, width = (root.winfo_screenwidth() - 20), height = (root.winfo_screenheight() - 10)) self.text.grid(row = 2)
Questions
-
Still using different methods, how can I make sure that each widget is placed in the correct Frame?
- If this is not possible, please just show me how to do it using OOP - I am most comfortable with Tkinter in that setting and have promised myself to improve.
Please explain your answer. I need to cognate - not simply nod my head at the computer and go right along.
-
Extra Credit: How would I initialize multiple windows (each window being a different class) using Tkinter in OOP? For instance, if this was my code:
class MainWindow(Frame): ---init stuff--- def widget(self): newWindow = Button(self, text = "click for a new window", command = self.window) newWindow.grid() def window(self): #What would I put in here to initialize the new window?? class theNextWindow(Frame):
What would I put in the
window.self
method to make thetheNextWindow
window visible?
Thanks for everyone's help!
EDIT 1
I added the line
self.widget()
in the__init__
method, and I was rewarded with this "wonderful" error:Traceback (most recent call last): File "D:\Python Programs\Text Editor\MyTextv2.py", line 67, in <module> app = Application(root) File "D:\Python Programs\Text Editor\MyTextv2.py", line 14, in __init__ self.widget() File "D:\Python Programs\Text Editor\MyTextv2.py", line 24, in widget text = "Save", command = self.saveMe) File "C:\Python27\lib\lib-tk\Tkinter.py", line 2044, in __init__ Widget.__init__(self, master, 'button', cnf, kw) File "C:\Python27\lib\lib-tk\Tkinter.py", line 1965, in __init__ BaseWidget._setup(self, master, cnf) File "C:\Python27\lib\lib-tk\Tkinter.py", line 1943, in _setup self.tk = master.tk AttributeError: Application instance has no attribute 'tk'
As the error log clearly references my mainloop here:
File "D:\Python Programs\Text Editor\MyTextv2.py", line 67, in <module> app = Application(root)
I decided to add it:root = Tk() root.title("My Text Editor") #This is wierd - it gets the computer windows dimensions w, h = root.winfo_screenwidth(), root.winfo_screenheight() root.overrideredirect(0) #And then applies them here root.geometry("%dx%d+0+0" % (w, h)) app = Application(root) root.mainloop()
-