Doug's Tkinter Frames Page

I want to learn Python 3, Tkinter, GUIs, and Frames

I'm not learning quickly. Don't expect this to be a source of authority. I predict it will be more a source of confusion and consternation. If my Search-Fu had been a little more developed, I probably would not need to write this. If I were a better programmer, I would have probably stolen a snippet of code off of stack overflow and never looked back. And if frogs had machine guns, snakes wouldn't mess with them. Don't be surprised if what I write in here is wrong. I will promise I will do my best to correct things when I do see a mistake.

No sense bothering with a bunch of "if's". I get to work with what I got. I'm stuck with the whole package of my curiosity, my ethics, my desire to learn, and a compulsion to build stuff I think would be interesting and useful. I would also add that I'm stuck trying to learn Python Tkinter Frames. I think writing things down will help me learn and get unstuck.

Whats So Hard About Frames?

For my Python GUIs, there are at least three kinds of Frames. Tkinter Frames, ttk frames, and tkinter labelframes. All three of these group objects. I'd explain the difference if I understood myself. Since a simple search didn't show me the similarities and differences, I thought, "I'll just mock them up and have a play." It wasn't quite as simple as I imagined it might be. Luckily, today is Sunday, and I have a little time. ttk is simply Themed Tkinter Widgets. Some of the widgets already exist in Tkinter, other are new; all of the ttk widgets are subclassed from"Widget".

I'll put in a quick table here to shortcut down to different sections that first explain, then show the code I used to learn/test/demonstrate. There are also two approaches to the code. One using classes, and one using functions. Using procedural code (simple straightforward functions) is easier to understand, but probably won't scale the best. The Object Oriented (OOP) code is larger and takes more effort to follow.

DescriptionsProcedural CodeClassful CodeExternal links
Tkinter FramesTkinter Frame(no classes)Tkinter Frame (Class-Code)
	 #this python file  implements  Frame Widgets.

# friends don't let friends import *
import tkinter as tk
# from tkinter import ttk


def clearentry1():
    #
    print("inside clear entry 1")
    print("entry 1 is ", entry1.get())
    entry1.set("")
    return

def clearentry2():   
    #
    print("inside clear entry 2")
    print("entry 2 is ", entry2.get())
    entry2.set("")
    return

rootwindow=tk.Tk()

rootwindow.title("Testing Frames")
rootwindow.geometry("800x300")
rootwindow.configure(bg="grey")
rootlabeltext = "This is the root Window"
rootlabel=tk.Label(rootwindow, text=rootlabeltext)
rootlabel.grid(row=0, column=0, sticky = tk.W + tk.E)
label1 = "Group 1 Text"
label2 = "Group 2 Text"
entry1=tk.StringVar()
entry2=tk.StringVar()

group1=tk.Frame(rootwindow)
group1.configure(bd=4, bg="blue", padx=10)
group1label1 = tk.Label(group1, text=label1)
group1entry1 = tk.Entry(group1, textvariable=entry1)
group1button1 = tk.Button(group1,text="clear", command = clearentry1)
group1button2 = tk.Button(group1, text="exit", command = rootwindow.destroy, bg="red", bd=4)

group1.grid(row=1, column=0, sticky=tk.W)   
group1label1.grid(row=1, column=5)
group1entry1.grid(row=2,column=5)
group1button1.grid(row=4, column=5)
group1button2.grid(row=4, column=6)

space = tk.Frame(width=25, height=100, bg="green3")
space.grid(row=1, column=5)

group2=tk.Frame(rootwindow)
group2.configure(bd=4, bg="khaki", padx=10)
group2label1 = tk.Label(group2, text=label2)
group2entry1 = tk.Entry(group2, textvariable=entry2)
group2button1 = tk.Button(group2,text="clear", command = clearentry2)
group2button2 = tk.Button(group2, text="exit", command = rootwindow.destroy, bg="red")

group2.grid(row=1, column=10, sticky=tk.E)   
group2label1.grid(row=1, column=10)
group2entry1.grid(row=2,column=10)
group2button1.grid(row=4, column=10)
group2button2.grid(row=4, column=12)

rootwindow.mainloop()
#this python file  implements  Frame Widgets using classes.

# friends don't let friends import *
import tkinter as tk
#from tkinter import ttk



class TestTkFrame(tk.Frame):
    def __init__(self,parent,label="test",color="tan"):
        super().__init__(parent)
    #my frame needs a label and one entry
        self.textvar = tk.StringVar()
        print("parent is ", parent)
        print("label is ", label)

        self.configure(bd=4, bg=color, padx=10)
        self.grouplabel=tk.Label(self, text=label)
        self.groupentry = tk.Entry(self, textvariable = self.textvar)
        self.clearButton = tk.Button(self,text="clear", command = self.clearentry)
        self.exitButton = tk.Button(self, text="exit", command = rootwindow.destroy, bg="red", bd=4)

        self.grouplabel.grid(row=0, column=0)
        self.groupentry.grid(row=1, column = 0)
        self.clearButton.grid(row=1, column=1)
        self.exitButton.grid(row=2,column=0)

    def clearentry(self):
        #it wasn't working because of self. You know what I mean. 
              
        print("inside clear entry ")
        print("textvar is ", self.textvar)
        print("entry  is ", self.textvar.get())
        self.textvar.set("")
        return


 
if __name__=="__main__":
    rootwindow=tk.Tk()

    rootwindow.title("Testing Frames")
    rootwindow.geometry("800x300")
    rootwindow.configure(bg="grey")
    rootlabeltext = "This is the root Window"
    rootlabel=tk.Label(rootwindow, text=rootlabeltext)
    rootlabel.grid(row=0, column=0, sticky = tk.W + tk.E)

    testwidget=TestTkFrame(rootwindow, label="testwidget")
    testwidget.grid(row=1, column=0)

    rootwindow.mainloop()

A little more about Frames

Frames group things. It could be like a little group of things, a little bucket of things, a little collection of things. A frame sounds like a Div in HTML, or a class in OOP. A frame as I understand it, is more than this. A frame is a new object that has built-in methods and attributes that can be changed. I put the no-classes frames next to the class-based frame test. the class-based one is a lot easier for me to follow. The class-based test also is easier to add on to. If I wanted to implement three or four more frames, it would be the same pattern of two lines of code.

I'm using Visual Studio Code for the convenience right now. Before that, I was perfectly happy to write in Notepad++ or Vim and run Python from the command line.

For my sample, I'm starting out with Three Frames; Two frames containing a Label, Text Entry, and two buttons (clear and exit). The other frame is to serve as a spacer between the other two frames. The program doesn't need to do much to show me how a frame is meant to work. I still don't understand the difference between a frame and labelframe. The Labelframe appears to be more difficult to work with

I think to try out ttk frame, as opposed to tk frame, is just replacing the tk with ttk. To take advantage of the Themed part of the Themed Tk Frame, it has a different method call to set options.

A little more about Themed Tk Widgets

from Python Software Foundation docs "ttk comes with 18 widgets, twelve of which already existed in tkinter: Button, Checkbutton, Entry, Frame, Label, LabelFrame, Menubutton, PanedWindow, Radiobutton, Scale, Scrollbar, and Spinbox. The other six are new: Combobox, Notebook, Progressbar, Separator, Sizegrip and Treeview. And all them are subclasses of Widget."

The ttk widgets were released as part of TK 8.5, released in 2007. The current version of tcl is 8.6.6 (Wikipedia , (accessed 2019 June 26th). The ttk widgets seem to have a more difficult way of setting options. Tk widgets can have many options set by using objectname.configure(options) . Such as group1.configure(bd=4, bg="blue", padx=10)

TTK widgets are "themed" and use a "style" to configure many options. to configure a custom style, you set a name for the style and then you can set configure() options for each widget. It is different to setting the options (like border, background color, padding, etc.) in Tk. As mentioned above, to make a widget a ttk widget instead of a tk widget, just change from tk to ttk. Then, change how you set options, because the two are different.

Some other good links I have been using are the TCLer's Wiki TCL Man pages How To Think Like a Computer Scientist is another good resource.

Active State had an interesting code snippet on program creek. This isn't the complete function. Just the part I was interested in.

     style = widget.cget("style")
     background = Style().lookup(style, 'background')

I would recommend setting up a function (or as part of a class) to set the options for a style, then override for special cases. I have seen this in some code snippets. It isn't my idea, but I think it is a good idea.

Really, the best way is to set up a simple program with two frames (I *know*! Thats what this page is about!) and try out changing the options, and seeing them side-by-side.

From , The Tile Widget Set by Joe English(2004)(accessed 2019 June 26th) "The Tile Theme is a collection of elements, layouts, and styles, which are combined with widget options to determine the look and feel". It was worth my time to read, but took time away from other things. A lot of the terms do not mean what I would ordinarily assume they mean. It is definitely something valuable to keep in the back of my mind when things do not display as I would expect them to display.

Here is my ttk test

It is working, but still could use some more work.

# don't import *
import tkinter as tk
from tkinter import ttk

def clearentry1():
    #
    print("inside clear entry 1")
    print("entry 1 is ", entry1.get())
    entry1.set("")
    return

def clearentry2():   
    #
    print("inside clear entry 2")
    print("entry 2 is ", entry2.get())
    entry2.set("")
    return

rootwindow=tk.Tk()

rootwindow.title("Testing Frames")
rootwindow.geometry("800x300")
rootwindow.configure(bg="grey")
rootlabeltext = "This is the root Window"
rootlabel=tk.Label(rootwindow, text=rootlabeltext)
rootlabel.grid(row=0, column=0, sticky = tk.W + tk.E)
label1 = "Group 1 Text - TTK Style"
label2 = "Group 2 Text"
entry1=tk.StringVar()
entry2=tk.StringVar()

group1style=ttk.Style()
group1style.configure("TFrame", background="blue")
group1style.configure("TButton", border=6, background="red")
group1style.configure("TEntry", border=6, background="yellow")

group1=ttk.Frame(rootwindow)
#group1.configure(bd=4, bg="blue", padx=10)
group1label1 = tk.Label(group1, text=label1)
group1entry1 = ttk.Entry(group1, textvariable=entry1)
#print(ttk.Style().lookup(group1style, TButton))
group1button1 = ttk.Button(group1,text="clear", command = clearentry1)
group1button2 = tk.Button(group1, text="exit", command = rootwindow.destroy, bg="red", bd=4)

group1.grid(row=1, column=0, sticky=tk.W)   
group1label1.grid(row=1, column=5)
group1entry1.grid(row=2,column=5)
group1button1.grid(row=4, column=5)
group1button2.grid(row=4, column=6)

space = tk.Frame(width=25, height=100, bg="green3")
space.grid(row=1, column=5)

group2=tk.Frame(rootwindow)
group2.configure(bd=4, bg="khaki", padx=10)
group2label1 = tk.Label(group2, text=label2)
group2entry1 = tk.Entry(group2, textvariable=entry2)
group2button1 = tk.Button(group2,text="clear", command = clearentry2)
group2button2 = tk.Button(group2, text="exit", command = rootwindow.destroy, bg="red")

group2.grid(row=1, column=10, sticky=tk.E)   
group2label1.grid(row=1, column=10)
group2entry1.grid(row=2,column=10)
group2button1.grid(row=4, column=10)
group2button2.grid(row=4, column=12)

rootwindow.mainloop()

Written with Notepad ++, and Vim