Introduction

Today we’ll look at how to code a minimal OOP window with a minimal OOP frame containing a minimal OOP label. It might not seem like much, but we’ll discover a number of interesting things along the way.

And Now, a Widget within a Widget within a Widget

Results of this example:
Current example output
Current example output
Terminal image
Current example terminal output (click for enlarged view)


Here’s what the code looks like:

from *tkinter* import *
from *tkinter* import ttk

def main():
	window = Window()
	window.mainloop()

class Window(Tk):
	def __init__(self):
		super().__init__()
		# object attributes
		self.mainframe = MainFrame(self)
		# configure
		#populate
		self.mainframe.grid()

class MainFrame(ttk.Frame):
	def __init__(self, window):
		super().__init__(window)
		# object attributes
		self.label = Label(self)
		# configure
		# populate
		self.label.grid()

class Label(ttk.Label):
	def __init__(self, parent):
		super().__init__(parent, text = "This is a label inside a frame inside a window.")
		
if __name__ == "__main__":
	main()

Breakdown - The Window Class

The first import line is the same one we’ve been using all along. However, the second (from *tkinter* import ttk) takes us into new territory. It gives us access to the updated ttk widgets.

In short, these widgets take on the visual appearance closer to that of the operating system your script is run on. Not all widgets have a ttk version and perhaps they never will. But, if you use ttk widgets and they still look dated, you can tell your users that it’s not your fault.

Populating the Window Class

First, we define the child:

self.mainframe = MainFrame(self)

Here we see what we were talking about last time. The parent identifies itself to tkinter as parent to the child widget being defined. That’s the right side of the equation. On the left, we use self to make sure we can access the mainframe attribute from any Window class methods we may write.

Because the layout of this demo isn’t complicated, we’ll let the children take care of their own grid() calls.

Breakdown - The Mainframe Class

class MainFrame(ttk.Frame):
	def __init__(self, window):
		super().__init__(window)
		# object attributes
		self.label = Label(self)
		# configure
		self.grid()

As usual, the first statement in __init__() calls the super-class constructor and passes along the parent. This is the line I’m talking about:

super().__init__(window)

Next, we see this line:

self.label = Label(self)

Which is a repeat of what happened in the Window class, but with a different child widget.

Lastly, we do the layout stuff:

self.grid()

Easy-peasey. Nothing complex about that layout.

Breakdown - Label Class

class Label(ttk.Label):
	def __init__(self, parent):
		super().__init__(parent, text = "This is a label inside a frame inside a window.")

By now, I’m sure you’re seeing the repetitiveness in these classes. Dull they may be, but by keeping them consistent, we make things easy on ourselves… they’re easy to understand, expand, and modify to suit a specific purpose. If we don’t have to spend even a moment understanding how a class is defined, we get to spend more time and energy doing the fun stuff and nailing down those bits of code that will be inevitably be tough.

The call to super().__init__() breaks with site conventions we’ve established, but it’s done in the name of taking things one step at a time. The second argument tells tkinter what we want the label to say. In later examples, we’ll do those things after the fact in the #configure section.

Conclusion

And that brings us to the end of another post. Hope you enjoyed it, hope it was helpful, and if you’re so inclined, you’re free to become our newest sponsor… like it says below.

Take care and next time we’ll do some


Sponsorship


Comments? Questions? Observations?

Did we miss a tidbit of information that would make this post even more informative? Let's talk about it in the comments.

Thank you very much for dropping by!

© Copyright 2021 Ronald V. Tarrant