Managing column width tkinter - python

I have reviewed the documentation on rowconfugre and columnconfigure, and I just do not quite understand how to get it working properly. With the following code, how can I get the 'src_entry' Entry box directly against the 'src' Checkbutton, regardless of what other widget is in column 1? Essentially, I need the size of the column to form to the width of whatever widget is in that space on the grid.
Thanks,
from tkinter import *
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent, background="white")
self.parent = parent
self.parent.title("TCPDUMP Creator")
self.centerWindow()
self.pack(fill=BOTH, expand=1)
menubar = Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Menu(menubar)
fileMenu.add_command(label="Exit", command=self.quit)
menubar.add_cascade(label="File", menu=fileMenu)
self.columnconfigure(2, weight=5)
int_lbl = Label(self, text="Interface")
int_lbl.grid(row=1, column=0, sticky=W+E)
self.int_entry = Entry(self, width=15)
self.int_entry.grid(row=1, column=1)
self.anyInt = BooleanVar()
Checkbutton(self, text="Any", variable = self.anyInt).grid(row=1, column=2)
int_lbl = Label(self, text="")
int_lbl.grid(row=2, column=0, columnspan=99, sticky=W+E)
self.notSrc = BooleanVar()
Checkbutton(self, text = "Not--", variable = self.notSrc).grid(row=3, column=0, sticky=W+E)
self.srcIP = BooleanVar()
Checkbutton(self, text="Src", variable = self.srcIP).grid(row=3, column=1)
src_entry = Entry(self, width=15)
src_entry.grid(row=3, column=2)
self.AndOr = StringVar()
self.AndOr.set(None)
Radiobutton(self, text = "And", variable = self.AndOr, value = "And").grid(row=3, column=3, pady=5, padx=2, sticky=E)
Radiobutton(self, text = "Or", variable = self.AndOr, value = "Or").grid(row=3, column=4, pady=5, padx=10, sticky=W)
self.notDst = BooleanVar()
Checkbutton(self, text = "Not--", variable = self.notDst).grid(row=3, column=5, sticky=W+E)
self.dstIP = BooleanVar()
Checkbutton(self, text="Dst", variable = self.dstIP).grid(row=3,column=6, sticky=E, padx=0)
dst_entry = Entry(self, width=15)
dst_entry.grid(row=3, column=7)
int_lbl = Label(self, text="")
int_lbl.grid(row=4, column=0, columnspan=99, sticky=W+E)
self.srcordst = StringVar()
self.srcordst.set(None)
Radiobutton(self, text = "And", variable = self.srcordst, value = "And").grid(row=4, column=1, pady=5, padx=2, sticky=E)
Radiobutton(self, text = "Or", variable = self.srcordst, value = "Or").grid(row=4, column=2, pady=5, padx=10, sticky=W)
def centerWindow(self):
w = 600
h = 300
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw - w)/2
y = (sh - h)/2.7
self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))
def main():
root = Tk()
app = Example(root)
root.mainloop()
if __name__ == '__main__':
main()

The best way to do layouts is to break your UI into sections, and then layout each section independently.The reason you're having difficulty is that you're trying to force everything into a single grid, but you don't have items that naturally fit into a grid. You can make it work by using lots of invisible columns and clever use of columnspan, but there are easier ways.
In this specific case, pack and a few intermediate frames is a better solution in my opinion.
From what I see, your UI is made up of four areas:
A row that has an entry for int_entry and a checkbutton
A row that has several checkboxes and radiobuttons, along with an entry
A row with an 'And' and 'Or' radiobutton
A big blank area
The way I would do it is create four frames, one for each area:
frame1 = Frame(self, ...)
frame2 = Frame(self, ...)
frame3 = Frame(self, ...)
frame4 = Frame(self, ...)
You can then use pack to stack those frames horizontally. All of them fill their area in the horizontal direction, and the last frame takes up all of the rest of the data.
frame1.pack(side="top", fill="x")
frame2.pack(side="top", fill="x")
frame3.pack(side="top", fill="x")
frame4.pack(side="top", fill="both", expand=True)
Now, you can add widgets to each frame with little concern for how they affect the rest of the display.
For example, the "Interface" label, the entry and the "Any" checkbutton can go in frame1. pack makes for a sensible choice since you want these aligned to the left of the area (I assume...).
int_lbl = Label(frame1, text="Interface")
self.int_entry = Entry(frame1, width=15)
any_cb = Checkbutton(frame1, text="Any", ...)
int_lbl.pack(side="left")
self.int_entry.pack(side="left")
any_cb.pack(side="left")
Do the same for the other frames. Within each frame you can choose to use pack or grid, as long as you consistently use pack or grid for every widget within the frame. pack is a very natural choice when you want all of your widgets aligned in one direction in the parent widget.

Related

How to add a Scrollbar on the main window when only Label and Button are used

I know how to add a scrollbar on a tkinter window, frame, canvas.
I also know how to do it on a listbox.
Problem is, I have a window that doesn't have any of those, and only use Label and Button:
from tkinter import *
test1 = 100
test2 = 100
test3 = 100
test4 = 100
root = Tk()
root.title("Program")
root.geometry('350x250')
# first group of labels & buttons
label = Label(root, text="test1")
label.grid(row=0, column=0, columnspan=2)
label = Label(root, text=test1)
label.grid(row=1, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=2, column=0)
button = Button(root, text="Down")
button.grid(row=2, column=1)
#
label = Label(root, text="test2")
label.grid(row=3, column=0, columnspan=2)
label = Label(root, text=test2)
label.grid(row=4, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=5, column=0)
button = Button(root, text="Down")
button.grid(row=5, column=1)
#
label = Label(root, text="test3")
label.grid(row=6, column=0, columnspan=2)
label = Label(root, text=test3)
label.grid(row=7, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=8, column=0)
button = Button(root, text="Down")
button.grid(row=8, column=1)
#
label = Label(root, text="test4")
label.grid(row=9, column=0, columnspan=2)
label = Label(root, text=test4)
label.grid(row=10, column=0, columnspan=2)
button = Button(root, text="Up")
button.grid(row=11, column=0)
button = Button(root, text="Down")
button.grid(row=11, column=1)
root.mainloop()
The above has a small window resolution on purpose, because, while it may work in maximizing the window, once there are too many Label's text or Button, then a Scrollbar will be needed. This is intended to test that.
How can I add a scrollbar to the above code?
You need a scrollable frame. See example here: https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01
And for buttons and labels, instead of using root as parent, use the scrollable frame as parent. For example:
from tkinter import *
c1 = "#999999"
c2 = "#000000"
class ScrollFrame(Frame):
"""
A simple scrollable frame class for tkinter
Source: https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01
"""
def __init__(self, parent):
# create a frame (self)
super().__init__(parent, background=c1)
# place canvas on self
self.canvas = Canvas(
self, bd=0, bg=c1, relief="flat", highlightthickness=0
)
# place a frame on the canvas, this frame will hold the child widgets
self.viewPort = Frame(self.canvas, background=c1)
self.viewPort.grid_columnconfigure(0, weight=1)
# place a scrollbar on self
self.vsb = Scrollbar(self, orient="vertical", command=self.canvas.yview)
# attach scrollbar action to scroll of canvas
self.canvas.configure(yscrollcommand=self.vsb.set)
# pack scrollbar to right of self
self.vsb.pack(side="right", fill="y")
# pack canvas to left of self and expand to fil
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas_frame = self.canvas.create_window(
(0, 0),
window=self.viewPort,
anchor="nw", # add view port frame to canvas
tags="self.viewPort",
)
# bind an event whenever the size of the viewPort frame changes.
self.viewPort.bind("<Configure>", self.onFrameConfigure)
self.canvas.bind("<Configure>", self.FrameWidth)
self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
def _on_mousewheel(self, event):
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
def FrameWidth(self, event):
canvas_width = event.width
self.canvas.itemconfig(self.canvas_frame, width=canvas_width)
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
# whenever the size of the frame changes, alter the scroll region respectively.
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
tests = [100, 99, 98, 101]
root = Tk()
root.title("Program")
root.geometry('350x250')
scroll_frame = ScrollFrame(root)
for i, testi in enumerate(tests):
# grouping labels and buttons together in a subframe
# so that the row numbers of the labels and buttons
# are always 0 to 2 within the sub-frame
f1 = Frame(scroll_frame.viewPort)
# first group of labels & buttons
label = Label(f1, text=f"test{i}")
label.grid(row=0, column=0, columnspan=2)
label = Label(f1, text=testi)
label.grid(row=1, column=0, columnspan=2)
button = Button(f1, text="Up")
button.grid(row=2, column=0)
button = Button(f1, text="Down")
button.grid(row=2, column=1)
# defining this group to have 2 columns with equal weight
f1.grid_columnconfigure(0, weight=1)
f1.grid_columnconfigure(1, weight=1)
# expand this sub-frame horizontally to it's parent, sticking to West and East of parent frame
f1.grid(sticky="we", ipadx=2)
# adding a separator
Frame(f1, height=1, background=c2).grid(
sticky="we", pady=5, padx=5, columnspan=2
)
# expand the scroll_frame in all 4 directions to fill the parent frame, sticking to West, East, North and South of parent frame
scroll_frame.grid(sticky="wens", row=0, column=0)
# set root frame only has 1 column (filled by scroll_frame)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
I recently stumbled on an easier way to do that (also use less code to do so):
import tkinter as tk
root = tk.Tk()
text = tk.Text(wrap="none")
vsb = tk.Scrollbar(orient="vertical", command=text.yview)
text.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
text.pack(fill="both", expand=True)
for i in range(30):
test1 = "test" + str(i)
test2 = "Button" + str(i)
c = tk.Label(text=test1)
k = tk.Label(text=i)
b = tk.Button(text=test2)
d = tk.Button(text=test2)
text.window_create("end", window=c)
text.insert("end", "\n")
text.window_create("end", window=k)
text.insert("end", "\n")
text.window_create("end", window=b)
text.window_create("end", window=d)
text.insert("end", "\n")
text.configure(state="disabled")
root.mainloop()
This is based on this answer. It doesn't use a canvas.
There is also another similar answer to the one I accepted on this post, here.

Off-set position of tkinter scale using the .grid manager

I am currently writing a simple piece of inventory management software for a school python assessment. My GUI involves listing out all of the items in stock, and giving the user the ability to stock/sell multiple items at once. This was achieved by placing an entry (amount to buy) and a scale widget (amount to sell) next to each item, and utilizing an "apply" button to enact the changes (For context, the scenario is a comic book store):
https://i.imgur.com/7cesQm5.png
This is the code that I have used to create the new widgets from each file (all of which are contained in a dictionary, pulled from a CSV file):
itteration = 2
labels = {}
nameTitle = Label(main, text="Title").grid(row=1, column=1, padx=5)
stockTitle = Label(main, text="Stock").grid(row=1, column=2, padx=5)
buyTitle = Label(main, text="Amount to Buy").grid(row=1, column=3, padx=5)
sellTitle = Label(main, text="Amount to Sell").grid(row=1, column=4, padx=5)
for item in comic_books:
name = item.replace(" ", "")
nameStock = "{}Stock".format(item).replace(" ", "")
nameBuy = "{}Buy".format(item).replace(" ", "")
nameSell = "{}Sell".format(item).replace(" ", "")
labels[name] = Label(main, text=item+":")
labels[name].grid(column=1, row=itteration, padx=5)
labels[nameStock] = Label(main, text=comic_books.get(item))
labels[nameStock].grid(column=2, row=itteration, padx=5)
labels[nameBuy] = Entry(main)
labels[nameBuy].grid(column=3, row=itteration, padx=20)
labels[nameSell] = Scale(main, from_=0, to=comic_books.get(item), orient=HORIZONTAL)
labels[nameSell].grid(column=4, row=itteration, padx=5)
itteration += 1
However, I am not a fan of how the the scales appear to be centering themselves in the row based on both the center of the slider, and the number on top. This makes the slider appear lower than the entry widget next to it.
https://i.imgur.com/9CQTvWS.png
My question is: how would I go about potentially offsetting the position of the scale widgets upwards by a given amount (maybe 5-10px?) from its original position, to push the actual slider in line with the entry widget before it?
Please let me know if you need any extra clarification
Cheers,
-Sean
Using sticky='s' and sticky='n' to stick to bottom (south) and top (north) of cell I got this
I didn't use different values in pady
import tkinter as tk
root = tk.Tk()
l = tk.Label(root, text='Label')
l.grid(column=1, row=0, padx=5, sticky='s', pady=10)
e = tk.Entry(root)
e.grid(column=2, row=0, padx=20, sticky='s', pady=10)
s = tk.Scale(root, from_=0, to=10, orient='horizontal')
s.grid(column=3, row=0, padx=5, sticky='n', pady=10)
root.mainloop()
Using sticky with pady=(0,20) for one widget I got this
import tkinter as tk
root = tk.Tk()
l = tk.Label(root, text='Label')
l.grid(column=1, row=0, padx=5, sticky='s', pady=10)
e = tk.Entry(root)
e.grid(column=2, row=0, padx=20, sticky='s', pady=10)
s = tk.Scale(root, from_=0, to=10, orient='horizontal')
s.grid(column=3, row=0, padx=5, sticky='n', pady=(0,20))
root.mainloop()

Resizing in a grid manager tkinter

Using tkinter, I wanted to make an interface containing a few buttons on the left, which would be fairly static and align with the widgets on the right fairly nicely.
On the right, I wanted an Entry widget above a Text widget, both of which would resize accordingly (the Entry widget only on the X axis).
This code accomplishes most of that, except the Text widget does not resize and the Entry widget only resizes to align with the Text widget. Upon trying to column/rowconfigure the root, the top frame resizes awkwardly.
Here's a picture of the tkinter interface from this code:
from tkinter import *
def main():
root = Tk()
root.geometry("300x400")
framet = Frame(root)
frameb = Frame(root)
framet.grid(row=0, column=0, sticky='ew')
frameb.grid(row=1, column=0, sticky='news')
button1 = Button(framet, text='one', width=8)
button1.grid(row=0, column=0)
button2 = Button(frameb, text='two', width=8)
button2.grid(row=1, column=0, sticky='n')
entry1 = Entry(framet)
entry1.grid(row=0, column=1, sticky='ew')
text1 = Text(frameb, highlightbackground='black', highlightthickness=1)
text1.grid(row=1, column=1, sticky='news')
framet.columnconfigure(1, weight=1)
if __name__ == '__main__':
main()
As you can see, the Entry and Text widgets do not resize. How could I accomplish this whilst still having the Buttons remain static, and not moving anything (only resizing)?
Would this work for you? I changed the lines with # comments, I think, I can't really remember what I did I just tryed to get it working, one problem which I'm not happy with though is the entry widget is not the same height as the button, I guess you could manually set its height but..
from tkinter import *
def main():
root = Tk()
root.grid_columnconfigure(1,weight=1) # the text and entry frames column
root.grid_rowconfigure(0,weight=1) # all frames row
buttonframe = Frame(root)
buttonframe.grid(row=0, column=0, sticky="nswe")
entry_text_frame = Frame(root)
entry_text_frame.grid(row=0, column=1, sticky="nswe")
entry_text_frame.grid_columnconfigure(0,weight=1) # the entry and text widgets column
entry_text_frame.grid_rowconfigure(1,weight=1) # the text widgets row
button1 = Button(buttonframe, text='one', width=8)
button1.grid(row=0, column=0, sticky='nswe')
button2 = Button(buttonframe, text='two', width=8)
button2.grid(row=1, column=0, sticky='nswe')
entry1 = Entry(entry_text_frame)
entry1.grid(row=0, column=0, sticky='nswe')
text1 = Text(entry_text_frame, highlightbackground='black', highlightthickness=1)
text1.grid(row=1, column=0, sticky='news')
root.geometry("300x400")
if __name__ == '__main__':
main()

Tkinter Label Overwrite

I'm using Tkinter to do a small project. Long story short, I want a label to generate some stuff on creation.
Later on, I want to print a label in the same spot but with different text.
I cannot for the life of me figure out how to remove the previous text.
What I wind up with in this example is the text "Does this even work" printed on top of "ALL I WANT IS A VERY LONG AND ANNOYING SENTENCE FOR TESTING"
Thanks!
from Tkinter import *
import pygal
class Application(Frame) :
def __init__(self, root) :
Frame.__init__(self, root)
self.root = root
self.grid()
self.create_widgets()
def create_widgets(self) :
queryLabel = Label(self, text = "Enter your query :")
queryLabel.grid(row=0, column=0, sticky=W)
self.userQuery = StringVar()
qEntry = Entry(self, textvariable=self.userQuery)
qEntry.grid(row=0, column=1, sticky=W)
queryTypeLabel = Label(self,text="Selecting query type: ")
queryTypeLabel.grid(row=2, column=0, sticky=W)
self.searchType = StringVar()
authorButton = Radiobutton( self, text="Author", variable=self.searchType, value="author")
authorButton.grid(row=3,column=0,sticky=W)
memberButton = Radiobutton( self, text="PC Member", variable=self.searchType, value="pcmember")
memberButton.grid(row=3,column=1,sticky=W)
affilButton = Radiobutton( self, text="Affiliation", variable=self.searchType, value="affiliation")
affilButton.grid(row=3,column=2,sticky=W)
self.conference = BooleanVar()
confCheck = Checkbutton(self, text="Select Conference?", variable = self.conference)
confCheck.grid(row=4,column=0,sticky=W)
self.conferenceName = StringVar()
self.conferenceName.set('No Preference')
confDropDown = OptionMenu(self, self.conferenceName, *conferenceOptions)
confDropDown.grid(row=4,column=1,sticky=W)
submit_button = Button( self, text="Submit", command = self.reveal)
submit_button.grid(row=5, column = 0, sticky = W)
#self.graphics_button = Button( self, text="I want Statistics!", command=self.graphics)
#self.graphics_button.grid(row=5, column = 1, sticky= W)
label1 = Label(root, text="ALL I WANT IS A VERY LONG AND ANNOYING SENTENCE FOR TESTING")
label1.grid(row=6, column=0, columnspan=5, sticky=W)
def reveal(self) :
#root.submit_button.grid_destroy()
self.label1 = Label(root, text="Does this even work?")
self.label1.grid(row=6, column=0, columnspan=5, sticky=W)
Bunch of MySQL stuff deleted
### Launch the UI
root = Tk()
root.geometry("800x800+300+300")
app = Application(root)
In reveal, you're creating a new Label which you grid in the same place as the previous label. What you want to do is use this:
# Make label1 an attribute of self to be able to reference it in reveal
self.label1 = Label(root, text="ALL I WANT IS A VERY LONG AND ANNOYING SENTENCE FOR TESTING")
self.label1.grid(row=6, column=0, columnspan=5, sticky=W)
def reveal(self) :
#root.submit_button.grid_destroy()
# Do not create a new Label, but change the existing one
self.label1.config(text="Does this even work?")
I had the exact same issue, and it was incredibly annoying--trying both grid_destroy() and grid_forget(). Neither worked. What worked for me was to call the label 2 times, the first time with many spaces, and the second with what I actually wanted to show. This way, the label content is overwriting spaces, not old content. I know this is not the best way to do this, but it gets me the result I want without a headache:
NumAssetsLabel = tk.Label(self, text="Num of Assets: ", font=('Helvetica', 10))
NumAssetsLabel.grid(row=9, column=3, pady=20, padx=10, sticky="w", columnspan=2)
NumAssetsLabel = tk.Label(self, text="Num of Assets: %s"%runCheck, font=('Helvetica', 10))
NumAssetsLabel.grid(row=9, column=3, pady=20, padx=10, sticky="w", columnspan=2)
Note that I have columnspan=2, to make sure that the number of spaces does not impact the grid.

Issues with layout management in Tkinter Python application

I am having a real issue with a little Tkinter program I'm making in Python as a frontend to my own CMS, regarding layout of the controls on the window. I am new to Tkinter but not Python but am struggling to use the grid layout manager to arrange my controls as I want them.
Here is a (terrible) mockup of what I'm aiming for:
But my code (below) only renders this:
Here is my code:
'''
Configure main window controls
'''
postTtlFrame = Frame(tkRoot, bg="red")
postTtlLbl = Label(postTtlFrame, text="Page title:").grid(row=0, column=0)
postTtlEnt = Entry(postTtlFrame).grid(row=0, column=1)
postTtlFrame.grid(row=0, column=0)
postTxtFrame = Frame(tkRoot, bg="blue")
postTxtLbl = Label(postTxtFrame, text="Page body content:").grid(row=0, column=0)
postTxtArea = Text(postTxtFrame).grid(row=1, columnspan=1)
postTxtFrame.grid(row=1, column=0)
pageConfigFrame = Frame(tkRoot, bg="green")
headerDirecLbl = Label(tkRoot, text="Page header location:").grid(row=0, column=0)
headerDirecEnt = Entry(tkRoot).grid(row=0, column=1)
footerDirecLbl = Label(tkRoot, text="Page footer location:").grid(row=1, column=0)
footerDirecEnt = Entry(tkRoot).grid(row=1, column=1)
stylesDirecLbl = Label(tkRoot, text="Page stylesheet location:").grid(row=2, column=0)
stylesDirecEnt = Entry(tkRoot).grid(row=2, column=1)
outputDirecLbl = Label(tkRoot, text="Page output location:").grid(row=3, column=0)
outputDirecEnt = Entry(tkRoot).grid(row=3, column=1)
pageConfigFrame.grid(row=2, column=0)
buttonsFrame = Frame(tkRoot, bg="orange")
postBtn = Button(tkRoot, text="Post").grid(row=0, column=0)
exitBtn = Button(tkRoot, text="Exit", command=quitTk).grid(row=0, column=1)
buttonsFrame.grid(row=3, column=0)
Please can someone explain to me what on earth is going wrong!
Thanks in advance,
Ilmiont
Yeah, I have it working now #jeanrjc, my code was FULL of errors I realise now; here is what I used in the end:
'''
Configure main window controls
'''
postTtlFrame = Frame(tkRoot)
postTtlLbl = Label(postTtlFrame, text="Page title:").grid(row=0, column=0)
postTtlEnt = Entry(postTtlFrame).grid(row=0, column=1)
postTtlFrame.grid(row=0, column=0, sticky=W)
postTxtFrame = Frame(tkRoot)
postTxtLbl = Label(postTxtFrame, text="Page body content:").grid(row=0, column=0, sticky=W)
postTxtArea = Text(postTxtFrame).grid(row=1, columnspan=1)
postTxtFrame.grid(row=1, column=0, sticky=W)
pageConfigFrame = Frame(tkRoot)
headerDirecLbl = Label(pageConfigFrame, text="Page header location:").grid(row=0, column=0, sticky=W)
headerDirecEnt = Entry(pageConfigFrame).grid(row=0, column=1)
footerDirecLbl = Label(pageConfigFrame, text="Page footer location:").grid(row=1, column=0, sticky=W)
footerDirecEnt = Entry(pageConfigFrame).grid(row=1, column=1)
stylesDirecLbl = Label(pageConfigFrame, text="Page stylesheet location:").grid(row=2, column=0, sticky=W)
stylesDirecEnt = Entry(pageConfigFrame).grid(row=2, column=1)
outputDirecLbl = Label(pageConfigFrame, text="Page output location:").grid(row=3, column=0, sticky=W)
outputDirecEnt = Entry(pageConfigFrame).grid(row=3, column=1)
pageConfigFrame.grid(row=2, column=0, sticky=W)
buttonsFrame = Frame(tkRoot)
postBtn = Button(buttonsFrame, text="Post").grid(row=0, column=0)
exitBtn = Button(buttonsFrame, text="Exit", command=quitTk).grid(row=0, column=1)
buttonsFrame.grid(row=3, column=0, sticky=E)
Now I have the following result which is what I wanted:
Thanks anyway though!
First off, it's pointless to assign a widget to a variable if you're calling grid (or pack or place) at the same time. foo=Label(..).grid(...) will always return None because grid(...) always returns None. Also, I find that layout problems are much easier to solve when you separate your layout from widget creation.
So, let's start by doing that:
'''
Configure main window controls
'''
postTtlFrame = Frame(tkRoot, bg="red")
postTxtFrame = Frame(tkRoot, bg="blue")
pageConfigFrame = Frame(tkRoot, bg="green")
buttonsFrame = Frame(tkRoot, bg="orange")
postTtlFrame.grid(row=0, column=0)
postTxtFrame.grid(row=1, column=0)
pageConfigFrame.grid(row=2, column=0)
buttonsFrame.grid(row=3, column=0)
postTtlLbl = Label(postTtlFrame, text="Page title:")
postTtlEnt = Entry(postTtlFrame).grid(row=0, column=1)
postTtlLbl.grid(row=0, column=0)
postTxtLbl = Label(postTxtFrame, text="Page body content:")
postTxtArea = Text(postTxtFrame)
postTxtLbl.grid(row=0, column=0)
postTxtArea.grid(row=1, columnspan=1)
headerDirecLbl = Label(tkRoot, text="Page header location:")
headerDirecEnt = Entry(tkRoot)
footerDirecLbl = Label(tkRoot, text="Page footer location:")
footerDirecEnt = Entry(tkRoot)
stylesDirecLbl = Label(tkRoot, text="Page stylesheet location:")
stylesDirecEnt = Entry(tkRoot)
outputDirecLbl = Label(tkRoot, text="Page output location:")
outputDirecEnt = Entry(tkRoot)
postBtn = Button(tkRoot, text="Post")
exitBtn = Button(tkRoot, text="Exit")
headerDirecLbl.grid(row=0, column=0)
headerDirecEnt.grid(row=0, column=1)
footerDirecLbl.grid(row=1, column=0)
footerDirecEnt.grid(row=1, column=1)
stylesDirecLbl.grid(row=2, column=0)
stylesDirecEnt.grid(row=2, column=1)
outputDirecLbl.grid(row=3, column=0)
outputDirecEnt.grid(row=3, column=1)
postBtn.grid(row=0, column=0)
exitBtn.grid(row=0, column=1)
Now, I think you can see more clearly what is happening. The problems I see are:
You seem to want to organize things into four main areas, but your mock-up shows that everything in the first three areas should share the same grid structure, so I'm not sure why you're creating these frames
You don't assign any weights to rows or columns, so they won't grow and shrink how you expect them to
Most of the widgets all share a common parent of tkRoot rather than the organizational frames that you create, so the frames end up serving no purpose
Because many widgets share the same parent, you end up putting several widgets on top of each other in the same grid cell.
You don't use the sticky attribute, so widgets won't fill their columns.
The fix for all this depends on exactly what effect you're trying to achieve. If you want four independent areas you need to make sure each widget has the appropriate frame for its parent, rather than lumping most widgets in the tkRoot frame. This makes it likely that, for example, the postTtlEnt won't line up with the other entry widgets.
If you don't want four independent areas and do want the postTtlEnt widget to line up with everything else, get rid of the intermediate frames and put everything into a single grid.
Likely you want a mix -- the buttons don't necessarily need to share the same grid, but all of the entry widgets should share the same grid. Here's how I would do it. Notice that I only have one extra internal frame, for the buttons. Everything else shares a common parent. Also notice that I give a weight to one row and one column so that you get the right resize behavior:
Here's a complete, working example. It doesn't precisely match your mockup: the exit and post buttons don't have their own dedicated column, but if you really want that you can do that if you want. The space above the buttons seems wasted, so I elected to put the buttons directly below the input widgets.
'''
Configure main window controls
'''
postTtlLbl = Label(tkRoot, text="Page title:")
postTxtLbl = Label(tkRoot, text="Page body content:")
headerDirecLbl = Label(tkRoot, text="Page header location:")
footerDirecLbl = Label(tkRoot, text="Page footer location:")
stylesDirecLbl = Label(tkRoot, text="Page stylesheet location:")
outputDirecLbl = Label(tkRoot, text="Page output location:")
postTtlEnt = Entry(tkRoot)
postTxtArea = Text(tkRoot)
footerDirecEnt = Entry(tkRoot)
headerDirecEnt = Entry(tkRoot)
stylesDirecEnt = Entry(tkRoot)
outputDirecEnt = Entry(tkRoot)
buttonsFrame = Frame(tkRoot, bg="orange")
postBtn = Button(buttonsFrame, text="Post")
exitBtn = Button(buttonsFrame, text="Exit")
postBtn.pack(side="right")
exitBtn.pack(side="right")
postTtlLbl.grid(row=0, column=0, sticky="w")
postTxtLbl.grid(row=1, column=0, sticky="w")
headerDirecLbl.grid(row=3, column=0, sticky="w")
footerDirecLbl.grid(row=4, column=0, sticky="w")
stylesDirecLbl.grid(row=5, column=0, sticky="w")
outputDirecLbl.grid(row=6, column=0, sticky="w")
postTtlEnt.grid(row=0, column=1, sticky="ew")
postTxtArea.grid(row=2, column=0, columnspan=2, sticky="nsew")
headerDirecEnt.grid(row=3, column=1, sticky="ew")
footerDirecEnt.grid(row=4, column=1, sticky="ew")
stylesDirecEnt.grid(row=5, column=1, sticky="ew")
outputDirecEnt.grid(row=6, column=1, sticky="ew")
buttonsFrame.grid(row=7, column=0, sticky="ew", columnspan=2)
tkRoot.grid_rowconfigure(2, weight=1)
tkRoot.grid_columnconfigure(1, weight=1)
I manage to get something pretty close to what you want :
from Tkinter import *
root = Tk()
content = Label(root, padx=30,pady=30,background = "white")
content.grid(column=0, row=0, sticky=(N, S, E, W))
title_frame = Label(content, borderwidth=5, relief="sunken", padx=30,pady=30,background = "white")
title_frame.grid(column=0, row=0, sticky=(N))
body_frame = Label(content, borderwidth=5, relief="sunken", padx=30,pady=30,background = "white")
body_frame.grid(column=0, row=1, sticky=(N,W,E))
config_frame = Label(content, borderwidth=5, relief="sunken", padx=30,pady=30,background = "white")
config_frame.grid(column=0, row=2, sticky=(N, W))
button_frame = Label(content, borderwidth=5, relief="sunken", padx=30,pady=30,background = "orange")
button_frame.grid(column=1, row=2, sticky=(S, E))
title_entry = Entry(title_frame, background="lightblue")
title_entry.grid(column=1, row=0)
title_label = Label(title_frame,text = "Page title",background = "white")
title_label.grid(column=0,row=0)
body_text = Text(body_frame, background="lightblue")
body_text.grid(column=1,row=0)
body_label = Label(body_frame,text = "Page body content",background = "white")
body_label.grid(column=0, row=0)
header_entry = Entry(config_frame, background="lightblue")
header_entry.grid(column=1, row=0)
header_label = Label(config_frame,text = "header",background = "white")
header_label.grid(column=0,row=0)
footer_entry = Entry(config_frame, background="lightblue")
footer_entry.grid(column=1, row=1)
footer_label = Label(config_frame,text = "footer",background = "white")
footer_label.grid(column=0,row=1)
postBtn = Button(button_frame, text="Post")
postBtn.grid(row=0, column=0)
exitBtn = Button(button_frame, text="Exit")
exitBtn.grid(row=0, column=1)
And it displays that :
Concerning why your code doesn't work :
I guess it's because you defined your grid position with :
postTtlLbl = Label(postTtlFrame, text="Page title:").grid(row=0, column=0)
Instead of
postTtlLbl = Label(postTtlFrame, text="Page title:")
postTtlLbl.grid(row=0, column=0)
It's a problem when you expect to create an instance of your frame (by returning the instance into the postTtlLbl variable), because the grid method doesn't return anything so these variables handling the frame are Nonetype, and you can't do anything with them.
Hope it's clear.

Categories

Resources