tkinter align button within frame with grid() - python

I'm creating small scratchpad app. The entire app is single column and 3 rows. The row0 will have a close button aligned to the right, row1 is the Text area and row2 will have a few buttons to format the text + 1 button to delete/clear the text area. I want that delete/clear button to align to the right while the rest of the buttons will align to the left such that there's a space between the format buttons and the delete button. So that you don't accidentally clear the text. Here is the code:
import tkinter as tk
from tkinter import ttk
wn = tk.Tk()
wn.attributes('-type', 'splash')
style = ttk.Style()
style.configure('top.TFrame', border=0, borderwidth=0, background='green')
style.configure('bottom.TFrame', border=0, borderwidth=0, background='blue')
style.configure('button.TButton', border=5, borderwidth=5, background='#e6e497', bd=5)
root = ttk.Frame(wn, style='top.TFrame', borderwidth=5, relief='ridge')
button = ttk.Button(root, text='X', width=3, command=lambda: wn.destroy(), style='button.TButton')
txt = tk.Text(root, width=40, background='light yellow', bd=5)
bottom = ttk.Frame(root, style='bottom.TFrame', width=2000, borderwidth=5, relief='ridge')
bottombuttona = ttk.Button(bottom, width=3, text='A')
bottombuttonb = ttk.Button(bottom, width=3, text='B')
bottombuttonc = ttk.Button(bottom, width=3, text='C')
bottombuttond = ttk.Button(bottom, width=3, text='D')
bottombuttone = ttk.Button(bottom, width=3, text='E')
root.grid()
button.grid(column=0, row=0, sticky=tk.E, ipady=4)
txt.grid(column=0, row=1, sticky=tk.NSEW)
bottom.grid(column=0, row=2, sticky=tk.NSEW)
bottombuttona.grid(column=0, row=2, ipady=5)
bottombuttonb.grid(column=1, row=2, ipady=5)
bottombuttonc.grid(column=2, row=2, ipady=5)
bottombuttond.grid(column=3, row=2, ipady=5)
bottombuttone.grid(column=4, row=2, ipady=5, sticky=tk.E)
txt.focus_force()
wn.bind('<Escape>', lambda x: wn.destroy())
wn.mainloop()
This is the result:
Question: How do I move the bottombuttone (E) to the right of the bottom frame it is in (blue colored)? sticky doesn't seem to work
secondary question: what's the purpose of the width option in the Frame class? doesn't seem to have any impact on the size of the frame itself, despite setting it to 2000.

You can use grid_columnconfigure to get it to work:
...
bottombuttond.grid(column=3, row=2, ipady=5)
bottom.grid_columnconfigure(4, weight = 1)
bottombuttone.grid(column=4, row=2, ipady=5, sticky=tk.E)
...
Setting the weight of the last item to 1 allows it to expand to fill it's parent. Using sticky = tk.E, it will stick to the right of it's parent.
I made this to demonstrate how grid weights work. The blue is the parent, C1-3 are the child widgets.

Related

layout buttons within frame nested in tkk.Notebook

I can't properly layout buttons within frame nested in tkk.Notebook
In Main.py I create ttk.Notebook and attach mainTab instance
root = tk.Tk()
rootFrame = tk.Frame(root, width=600, height=300)
rootFrame.grid(columnspan=1, rowspan=2)
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, columnspan=1, rowspan=1)
mainTab = ttk.Frame(tabs)
mainTab.grid(columnspan=3, rowspan=6)
tabs.add(mainTab, text="Main")
rootFrame.pack(expand=1, fill="both")
mainPane = MainTab(root,mainTab)
root.mainloop()
in mainTab.py I'm trying to insert buttonFrame and layout two buttons within it
class MainTab:
...
def __init__(self, root, mainTab) -> None:
self.root = root
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, columnspan=3, rowspan=1)
self.start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font=BUTTON_FONT, bg="green", fg="white") # , height=1, width=14
self.start_btn.grid(column=0, row=0, columnspan=2)
self.reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font=BUTTON_FONT, bg="green", fg="white") # , height=1, width=1
self.reset_btn.grid(column=2, row=0)
...
As a result start button is not properly placed in the grid
It looks like buttonFrame takes full parent frame width and buttons placed in the middle regardless of their grid settings.
How I can properly layout buttons within buttonFrame?
Here is the requested "minimal reproducible example" which also look not good
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Time Tracker")
root.iconbitmap('./assets/logoTransp4icon24.ico')
rootFrame = tk.Frame(root, width=600, height=300)
rootFrame.grid(columnspan=1, rowspan=2)
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, columnspan=1, rowspan=1)
mainTab = ttk.Frame(tabs)
mainTab.grid(columnspan=3, rowspan=6)
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, columnspan=3, rowspan=1)
start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font="Arial", bg="green", fg="white") # , height=1, width=14
start_btn.grid(column=0, row=0, columnspan=2)
reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font="Arial", bg="green", fg="white") # , height=1, width=1
reset_btn.grid(column=2, row=0)
timerDisplay = tk.Label(mainTab, text="00:00:00", font="Arial")
timerDisplay.grid(columnspan=2, column=1, row=4)
tabs.add(mainTab, text="Main")
rootFrame.pack(expand=1, fill="both")
root.mainloop()
buttonFrame occupies column 0 to 2 and timerDisplay occupies column 1 to 2. So timerDisplay overlaps buttonFrame. Removing columnspan=3 in buttonFrame.grid(...) can fix the overlapping issue:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Time Tracker")
root.iconbitmap('./assets/logoTransp4icon24.ico')
rootFrame = tk.Frame(root, width=600, height=300)
#rootFrame.grid(columnspan=1, rowspan=2) # override by below line
rootFrame.pack(expand=1, fill="both")
tabs = ttk.Notebook(rootFrame)
tabs.grid(column=0, row=1, rowspan=1)
mainTab = ttk.Frame(tabs)
#mainTab.grid(columnspan=3, rowspan=6) # not necessary
buttonFrame = tk.Frame(mainTab, bg="white")
buttonFrame.grid(column=0, row=4, rowspan=1) # removed columnspan=3
start_btn = tk.Button(buttonFrame, text="Start", command=lambda:self.start_timer(), font="Arial", bg="green", fg="white") # , height=1, width=14
start_btn.grid(column=0, row=0, columnspan=2)
reset_btn = tk.Button(buttonFrame, text="X", command=lambda:self.reset_timer(), font="Arial", bg="green", fg="white") # , height=1, width=1
reset_btn.grid(column=2, row=0)
timerDisplay = tk.Label(mainTab, text="00:00:00", font="Arial")
timerDisplay.grid(columnspan=2, column=1, row=4)
tabs.add(mainTab, text="Main")
#rootFrame.pack(expand=1, fill="both") # already called above
root.mainloop()

How can I insert label in a scrollable canvas?

The scroll don't work at all. What's wrong in the code?
I'm using Python 2.7.16
I read that listbox and text widgets are used only for text. As I want to use labels, I'm trying to insert the labels in a frame, but as a Frame didn't scroll I decided to use a canvas. But I couldn't get it to work.
from Tkinter import *
root = Tk()
frame = Frame(root, width=300, height=200)
frame.grid(row=0, column=0)
canvas=Canvas(frame, bg='#FFFFFF', width=300, height=200, scrollregion=(0,0,500,500))
vbar = Scrollbar(frame, orient=VERTICAL)
vbar.pack(side=RIGHT, fill=Y)
canvas.config(width=300, height=250)
canvas.pack(side=LEFT, expand=True, fill=BOTH)
mylist = Frame(canvas, width=100)
for x in range(10):
texto = Label(mylist, text='CODE', bd=2, width=7, relief=RIDGE)
texto.grid(row=x, column=0)
texto1 = Label(mylist, text='EQUIPAMENT', bd=2, width=20, relief=RIDGE)
texto1.grid(row=x, column=1)
mylist.place(x=0, y=0)
vbar.config(command=canvas.yview)
canvas.config(yscrollcommand=vbar.set)
mainloop()

Text and entry width not the same tkinter

I'm starting to learn Tkinter library and I have a problem...
I use grid to set my window the way I want but I can't figure out how I can set the width of the entry widget the same as the text widget.
When I put the same number, I don't have the same width anyway...
Here is my code :
from tkinter import *
def click():
try:
output.delete(0.0,END)
entered_text=entry.get()
output.insert(END, entered_text)
except:
output.insert(END, "")
def reset():
output.delete(0.0,END)
entry.delete(0,END)
if __name__ == '__main__':
window = Tk()
window.title("TEST")
window.geometry("500x500")
Label (window, text="Nombre de palettes :").grid(row=0, sticky=W)
Label (window, text="Prix :").grid(row=1, sticky=W)
entry = Entry (window)
entry.grid(row=0, column=2)
output = Text(window, width=8, heigh=1, wrap=WORD)
output.grid(row=1, column=2)
accepter=Button(window, text="Accepter", width=6, command=click)
accepter.grid(row=2, column=0)
restart = Button(window, text="Reset", width=6,command=reset)
restart.grid(row=2, column=1)
fin = Button(window, text="Quitter", width=6,command=window.destroy)
fin.grid(row=2, column=2)
window.grid_columnconfigure(4, minsize=100)
window.mainloop()
Thank you in advance.
One way is to expand the widgets to fill the cell:
entry = Entry(window)
entry.grid(row=0, column=2, sticky=E+W, padx=10)
output = Text(window, width=8, heigh=1, wrap=WORD)
output.grid(row=1, column=2, sticky=E+W, padx=10)
Where sticky=E+W fills the cell horizontally, and then I add some padding padx=10 to get a distance from the cell limits.
If one of the widgets always is bigger you can let that widget determine the cell width and then just expand the other widget.

Center a button widget in a column using tkinter

I have a Labelframe and inside that LabelFrame, I've placed a button. That button will always appear in the top-left corner of the LabelFrame, though I would like it to center itself within the LabelFrame. What property am I missing that will force this button to center itself inside of the LabelFrame?
self.f1_section_frame=LabelFrame(self.mass_window, text="LOCATIONS", width=300, height=998, padx=5, pady=5, bd=5)
self.f1_section_frame.grid(row=0, rowspan=6, column=1, sticky="nw", padx=(2,0))
self.f1_section_frame.grid_propagate(False)
self.button_frame1 = LabelFrame(self.f1_section_frame, width=275, height=50)
self.button_frame1.grid_propagate(False)
self.button_frame1.grid(row=1, column=0)
self.b1_scoring=Button(self.button_frame1, text="CONFIRM\nLOCATION(S)", height=2, width=10, command=self.initiate_site_scoring, justify="center")
self.b1_scoring.grid(row=0,column=0, pady=(1,0))
Thanks for the response #R4PH43L. I gave that a shot and it didn't seem to change. However, it got me thinking so I removed "grid_propagate" from the frame that encloses my buttons, which then wrapped the frame around the buttons without any space and centered the frame within the column in which IT was placed. Then I used padx=(x,0) on my leftmost button and padx=(0,x) on my rightmost button to add the space needed on the left and right side and it's working how I need it to now.
self.f1_section_frame=LabelFrame(self.mass_window, text="LOCATIONS", width=300,
height=998, padx=5, pady=5, bd=5)
self.f1_section_frame.grid(row=0, rowspan=6, column=1, sticky="nw", padx=(2,0))
self.f1_section_frame.grid_propagate(False)
self.button_frame1 = LabelFrame(self.f1_section_frame, width=275, height=50)
self.button_frame1.grid(row=1, column=0)
self.b1_scoring=Button(self.button_frame1, text="CONFIRM\nLOCATION(S)", height=2, width=10,
command=self.initiate_site_scoring, justify="center")
self.b1_scoring.grid(row=0,column=0, padx=(15,0))
self.b2_scoring=Button(self.button_frame1, text="CLEAR\nSELECTION(S)", height=2,
width=10, command=self.clear_selected_locations)
self.b2_scoring.grid(row=0,column=1)
self.b3_scoring=Button(self.button_frame1, text="UPDATE\nSELECTION(S)", height=2, width=10,
command=self.update_selected_location_details)
self.b3_scoring.grid(row=0,column=2, padx=(0,15))

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()

Categories

Resources