Reputation: 65
I am trying to build a GUI which basically has a single window. This window is a combination of different frames. What I want to do is to arrange these frames (Each of the frames further comprise of multiple widgets) together in a certain format:
Below, I have added a simple minimalistic code for the problem. To keep it simple, I have used the same FRAME class and created 4 instances of this class to be added in the main window. I use Tkinter's grid manager to organise the widgets in the frame and then again use grid manager to pack these frames into the main window.
import Tkinter as tk
# Test frame class. The same frame is used to create 4 instances.
class TestFrame(tk.Frame):
def __init__(self, master=None, *args, **kwargs):
tk.Frame.__init__(self, *args, **kwargs)
super().__init__(master)
# Test Entry fields
test_label_1 = tk.Label(master, text="Test Label 1").grid(row=0, column=0)
test_label_1_entry = tk.Entry(master, bd=5).grid(row=0, column=1)
test_label_2 = tk.Label(master, text="Test Label 2").grid(row=0, column=2)
test_label_2_entry = tk.Entry(master, bd=5).grid(row=0, column=3)
# Test checkbox fields
test_checkbox_1_label = tk.Label(master, text="Test check button 1").grid(row=2, column=0)
test_checkbox_1_entry = tk.Checkbutton(master, bd=5).grid(row=2, column=1)
test_checkbox_2_label = tk.Label(master, text="Test check button 2").grid(row=2, column=2)
test_checkbox_2_entry = tk.Checkbutton(master, bd=5).grid(row=2, column=3)
# Test dropdowns
test_dropdown_label = tk.Label(master, text="Test dropdown 1").grid(row=3, column=0)
list_of_options = ["first option", "second option", "third option", "forth option"]
first_option = tk.StringVar(master)
first_option.set(list_of_options[0])
test_dropdown_label = tk.OptionMenu(master, first_option, *list_of_options).grid(row=3, column=1)
test_dropdown_label = tk.Label(master, text="Test dropdown 1").grid(row=3, column=0)
list_of_options = ["first option", "second option", "third option", "forth option"]
first_option = tk.StringVar(master)
first_option.set(list_of_options[0])
test_dropdown_label = tk.OptionMenu(master, first_option, *list_of_options).grid(row=3, column=1)
pass
pass
class TestMainApplication(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
super().__init__(master)
title = "Test Application"
self.grid()
# Assign the weight to each row and column as 1. This is required to align the parameters in grid.
for r in range(3):
self.master.rowconfigure(r, weight=1)
for c in range(8):
self.master.columnconfigure(c, weight=1)
self.master.title(title)
# Add two instances of the class TestFrame
self.testFrame1 = TestFrame(master)
self.testFrame2 = TestFrame(master)
self.testFrame3 = TestFrame(master)
self.testFrame4 = TestFrame(master)
self.testFrame1.grid(row=0, column=0, rowspan=3, columnspan=3, sticky=tk.W+tk.E+tk.N+tk.S)
self.testFrame2.grid(row=3, column=0, rowspan=3, columnspan=3, sticky=tk.W+tk.E+tk.N+tk.S)
self.testFrame3.grid(row=0, column=3, rowspan=2, columnspan=3, sticky=tk.W+tk.E+tk.N+tk.S)
self.testFrame4.grid(row=2, column=3, rowspan=4, columnspan=3, sticky=tk.W+tk.E+tk.N+tk.S)
pass
pass
# Main application is created here.
root = tk.Tk()
mainApplication = TestMainApplication(root)
root.mainloop()
I would expect after running this code, a window split into 4 parts organised in the format as discussed above. However, what I see is all the frames overlapped on top of each other.
Enviroment: MacOS, tkinter 8.6, python 3.6.7
Upvotes: 2
Views: 6395
Reputation: 15226
Ok so a few problems here.
Your code is somewhat messy. Please consider using the PEP8 standard. Link here
If you are going to use class inherency for your frames why not do the same for your root window. I have edited your code to inherit from Tk()
.
The reason for overlap is because in your TestFrame
class you are telling your widgets they belong to master
instead of self
(IE the TestFrame class itself). To correct this simply replace all master
calls in your TestFrame to self
.
You use both tk.Frame.__init__(self)
and super().__init__(master)
. You really only need to use super().__init__()
when using this kind of inherency.
See example code below:
import tkinter as tk
class TestFrame(tk.Frame):
def __init__(self):
super().__init__()
list_of_options = ["first option", "second option", "third option", "forth option"]
first_option = tk.StringVar(self)
first_option.set(list_of_options[0])
tk.Label(self, text="Test Label 1").grid(row=0, column=0)
tk.Entry(self, bd=5).grid(row=0, column=1)
tk.Label(self, text="Test Label 2").grid(row=0, column=2)
tk.Entry(self, bd=5).grid(row=0, column=3)
tk.Label(self, text="Test check button 1").grid(row=2, column=0)
tk.Checkbutton(self, bd=5).grid(row=2, column=1)
tk.Label(self, text="Test check button 2").grid(row=2, column=2)
tk.Checkbutton(self, bd=5).grid(row=2, column=3)
tk.Label(self, text="Test drop down 1").grid(row=3, column=0)
tk.OptionMenu(self, first_option, *list_of_options).grid(row=3, column=1)
class TestMainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test Application")
for r in range(3):
self.rowconfigure(r, weight=1)
for c in range(8):
self.columnconfigure(c, weight=1)
self.testFrame1 = TestFrame()
self.testFrame2 = TestFrame()
self.testFrame3 = TestFrame()
self.testFrame4 = TestFrame()
self.testFrame1.grid(row=0, column=0, rowspan=3, columnspan=3, sticky='nsew')
self.testFrame2.grid(row=3, column=0, rowspan=3, columnspan=3, sticky='nsew')
self.testFrame3.grid(row=0, column=3, rowspan=2, columnspan=3, sticky='nsew')
self.testFrame4.grid(row=2, column=3, rowspan=4, columnspan=3, sticky='nsew')
TestMainApplication().mainloop()
Upvotes: 6