Tkinter - fit widgets inside a frame size - python

I am trying to fit widgets (e.g. buttons, labels (included images) into a Frame. Whenever I do this, the frame size changes to fit in the widget. So the widget does not 'fit' into the frame, but rather just expands the frames size.
E.g. see image below:
I have 3 frames:
root = Tk()
root.title('Model Definition')
root.geometry('{}x{}'.format(800, 600))
frame_1 = Frame(root, bg='red', pady=3)
frame_2 = Frame(root, bg='green', padx=3, pady=3)
frame_3 = Frame(root, bg='black', pady=3)
frame_1.grid(row=0, sticky='nsew')
frame_2.grid(row=1, sticky='nsew')
frame_3.grid(row=2, sticky='nsew')
# All frames expand at the same rate!
root.grid_rowconfigure(index=0, weight=1)
root.grid_rowconfigure(index=1, weight=1)
root.grid_rowconfigure(index=2, weight=1)
root.grid_columnconfigure(index=0, weight=1)
root.mainloop()
Each row has the same height when resizing the root window. If I add an image label to frame_1, the height of the frame expands to fit it in and so then when I expand the root window it disproportionately expands the size of the frame. (see below image)
Is there a way for the label to conform to the size of the frame? (i.e. to have the image within the boundaries set out of the frame)

Related

Tkinter winfo_reqwidth not proper value

I am trying to write a application where i will get the size of the screen and then resize GUI to take full screen accordingly.
Also, i have 3 frames inside that application. The three frames will have separate widgets. Now based on the screen size available i would like to change the layout of the widgets a bit and also the size of text and wrap length of the texts.
I understood that frame will not have proper size until it have a widget, so i am adding dummy canvas widget. But then also the width of the frames are not getting proper. Am i not doing the thing properly ? If you run the below code frame 1 and frame 2 are having same widths even though visually they are not at all same.
import tkinter as tk
from win32api import GetSystemMetrics
class MainApplication:
def __init__(self):
self.root = tk.Tk()
self.width = GetSystemMetrics(0)
self.height = GetSystemMetrics(1)
self.root.geometry('{}x{}'.format(self.width, self.height))
frame1 = tk.Frame(self.root,bg='blue')
frame1.grid(row=0, column=0, sticky="nsew",rowspan=2)
self.root.grid_columnconfigure(0, weight=5000)
frame1.grid_rowconfigure(0,weight=1)
frame1.grid_columnconfigure(0,weight=1)
self.canvas = tk.Canvas(frame1,bg='blue')
self.canvas.grid(row=0, column=0, sticky="nsew")
self.canvas.update()
print(frame1.winfo_reqwidth())
self.frame2 = tk.Frame(self.root,bg='red')
self.root.grid_columnconfigure(1, weight=1)
self.frame2.grid(row=0, column=1, sticky="nsew")
self.frame2.grid_rowconfigure(0, weight=1)
self.frame2.grid_columnconfigure(0, weight=1)
self.canvas1 = tk.Canvas(self.frame2,bg='red')
self.canvas1.grid(row=0, column=0, sticky="nsew")
self.canvas1.update()
print(self.frame2.winfo_reqwidth())
self.frame3 = tk.Frame(self.root, bg='green')
self.frame3.grid(row=1,column=1,sticky="nsew")
self.root.grid_rowconfigure(1,weight=5000)
self.frame3.grid_rowconfigure(0, weight=1)
self.frame3.grid_columnconfigure(0, weight=1)
self.canvas2 = tk.Canvas(self.frame3,bg='green')
self.canvas2.grid(row=0, column=0, sticky="nsew")
self.canvas2.update()
self.root.mainloop()
if __name__ == '__main__':
a = MainApplication()

Tkinter widgets not resizing as expected

Sorry if it's an easy fix - I'm new to tkinter (and graphical applications in general), and on my way up the learning curve.
I have a simple window in grid layout, with a canvas and a few labels to the right of it. They're positioned and sized correctly - but when I resize the window to the right, they DO expand over, but only about half way (i.e., for every 2 pixels to the right I expand the window, they widgets only expand by 1). I have their respective columns weighted, as well as the parent frame's column weighted. I'm not sure how to remedy this, and haven't found anything similar through Googling. Below I've posted my code, and screenshots of the widgets when the application is launched vs. when I resize.
CODE
from tkinter import *
root = Tk()
root.title("title")
mainframe = Frame(root)
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
canvas = Canvas(mainframe, width=800, height=800)
canvas.grid(row=1, column=1, rowspan=3)
info_label = Label(mainframe, text='Info Label', bg='white', relief='solid', borderwidth=1)
info_label.grid(row=1, column=2, columnspan=2)
chatbox = Label(mainframe, text='Welcome to the application.', bg='white', relief='solid', borderwidth=1)
chatbox.grid(row=2, column=2, columnspan=2, sticky=(N,S,E,W))
chat_entry = Entry(mainframe)
chat_entry.grid(row=3, column=2)
chat_send = Button(mainframe, text='Send')
chat_send.grid(row=3, column=3)
mainframe.rowconfigure(1, weight=1)
mainframe.rowconfigure(2, weight=1)
mainframe.columnconfigure(2, weight=1)
root.columnconfigure(1, weight=1)
root.mainloop()
SCREENSHOTS
The only positioning command that resizes according to the window size is pack().
As known, you have the following functions:
pack()
grid()
place()
By the way, I recommend using the place function and use this:
window.resizable(width=False, height=False)
This function prevent from the client the ability to resize the tkinter window.

Expand one widget vertically while locking another with Tkinter/ttk

I have a treeview inside of a frame that sits on top of another frame containing buttons. I would like the top frame to expand when I resize the window but keep the button frame from doing the same.
Code in Python 2.7.5:
class MyWindow(Tk.Toplevel, object):
def __init__(self, master=None, other_stuff=None):
super(MyWindow, self).__init__(master)
self.other_stuff = other_stuff
self.master = master
self.resizable(True, True)
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
# Top Frame
top_frame = ttk.Frame(self)
top_frame.grid(row=0, column=0, sticky=Tk.NSEW)
top_frame.grid_columnconfigure(0, weight=1)
top_frame.grid_rowconfigure(0, weight=1)
top_frame.grid_rowconfigure(1, weight=1)
# Treeview
self.tree = ttk.Treeview(top_frame, columns=('Value'))
self.tree.grid(row=0, column=0, sticky=Tk.NSEW)
self.tree.column("Value", width=100, anchor=Tk.CENTER)
self.tree.heading("#0", text="Name")
self.tree.heading("Value", text="Value")
# Button Frame
button_frame = ttk.Frame(self)
button_frame.grid(row=1, column=0, sticky=Tk.NSEW)
button_frame.grid_columnconfigure(0, weight=1)
button_frame.grid_rowconfigure(0, weight=1)
# Send Button
send_button = ttk.Button(button_frame, text="Send",
command=self.on_send)
send_button.grid(row=1, column=0, sticky=Tk.SW)
send_button.grid_columnconfigure(0, weight=1)
# Close Button
close_button = ttk.Button(button_frame, text="Close",
command=self.on_close)
close_button.grid(row=1, column=0, sticky=Tk.SE)
close_button.grid_columnconfigure(0, weight=1)
I make the instance elsewhere like this:
window = MyWindow(master=self, other_stuff=self._other_stuff)
What I have tried:
Tried locking resizability which only made the buttons disappear. I also tried changing weights around but my current configuration is the only way everything shows up on screen.
What it should always look like no matter how long the height:
What I want to prevent:
Thanks in advance.
The problem isn't that the button frame is growing, it's that the top frame is growing but isn't using all of it's space. This is because you are giving row 1 of top_frame a weight of 1 but you don't put anything in row 1. Extra space is being allocated to row 1 because of its weight, but row 1 is empty.
An easy way to visualize this is to change top_frame to a tk (rather than ttk) frame, and temporarily give it a distinctive background color. You will see that when you resize the window, top_frame fills the window as a whole, but that it is partially empty.
Create top_frame like this:
top_frame = Tk.Frame(self, background="pink")
... yields a screen like the following image when you resize the window. Note that the pink top_frame is showing through, and that button_frame remains its preferred size.
You can fix this by simply removing this one line of code:
top_frame.grid_rowconfigure(1, weight=1)

Tkinter button distance from window edges

Is there a way using Tkinter to have buttons so that they are always placed a certain number of pixels from the edge of the window, even when the window is resized? I've tried using anchors but that didn't seem to move the placement in the window that much.
You can anchor buttons or any other widget to the sides of a window by starting with a Frame, and configuring its rows and columns to have a weight of 1 in order for it to fill the parent window.
import Tkinter as tk
import ttk
root = tk.Tk()
frame = ttk.Frame(root)
frame.pack(fill=tk.BOTH, expand=True)
frame.columnconfigure(index=0, weight=1)
frame.columnconfigure(index=2, weight=1)
frame.rowconfigure(index=0, weight=1)
frame.rowconfigure(index=2, weight=1)
Then, for each button you want to use sticky to anchor it to the respective side, and use padx or pady to add some padding (in pixels) between the button and the window.
top_padding = 5
top = ttk.Button(frame, text="Top")
top.grid(row=0, column=1, sticky=tk.N, pady=(top_padding, 0))
left_padding = 5
left = ttk.Button(frame, text="Left")
left.grid(row=1, column=0, sticky=tk.W, padx=(left_padding, 0))
right_padding = 5
right = ttk.Button(frame, text="Right")
right.grid(row=1, column=2, sticky=tk.E, padx=(0, right_padding))
bottom_padding = 5
bottom = ttk.Button(frame, text="Bottom")
bottom.grid(row=2, column=1, sticky=tk.S, pady=(0, bottom_padding))
root.mainloop()
have you tried using the padx function?
it works like this:
button=Button(place,text="something something", padx=10)
it provides with extra horizontal padding between widgets, aditionally, you could use frames with padx and an anchor so the text is fixated to a position

A Label in a Frame in a window won't stretch, why?

I would like to display
a window
with a single Frame
and a Label in the Frame which would stretch to the whole width of the window
The following code
import Tkinter as tk
root = tk.Tk()
root.geometry("100x100")
# first column of root will stretch
root.columnconfigure(0, weight=1)
# a frame in root
upper_frame = tk.Frame(root)
# first column of upper_frame will stretch
upper_frame.columnconfigure(0, weight=1)
upper_frame.grid(row=0, column=0)
# a label in upper_frame, which should stretch
mylabel = tk.Label(upper_frame)
mylabel.grid(row=0, column=0)
mylabel.configure(text="hello", background="blue")
root.mainloop()
displays
Why isn't the Label stretching to the whole width of the window but is just as wide as the text?
Specifying sticky option when you call grid (e = east, w = west). Otherwise the widget in the cell is center-aligned.
upper_frame.grid(row=0, column=0, sticky='ew')
..
mylabel.grid(row=0, column=0, sticky='ew')

Categories