I am experimenting with Tkinter, as I was trying to place tree frames. Two frames must be placed side by side: the red one and the blue one. (see frame image). I place this two frames with this istructions:
redFrame = tk.Frame(master=masterFrame, bg='red')
redFrame.pack_propagate(0)
redFrame.pack(fill='both', side='left', expand='True')
blueFrame = tk.Frame(master=masterFrame, bg='blue')
destFrame.pack_propagate(0)
destFrame.pack(fill='both', side='right', expand='True')
Now I want to put another frame (green) inside the red one, placed on the left side of the main interface:
greenFrame = tk.Frame(master=masterFrame, width=100, height=100, bg='green')
greenFrame.pack_propagate(0)
greenFrame.pack(side='bottom', padx=0, pady=0)
The problem is that I can't choose its position. It still remain in the top side of the window and centered.
If I change the padx parameter nothing change.
If i change the pady parameter, the frame change its Y position. Why this not appened with the X posistion?
Widgets will by default be centered in their allocated space within the container.
Your code at the moment doesn't work, so I've changed it to this (I think it mimics what you're saying you currently have):
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
redFrame = tk.Frame(root, bg='red')
redFrame.pack_propagate(0)
redFrame.pack(fill='both', side='left', expand='True')
blueFrame = tk.Frame(root, bg='blue')
blueFrame.pack_propagate(0)
blueFrame.pack(fill='both', side='right', expand='True')
greenFrame = tk.Frame(redFrame, width=100, height=100, bg='green')
greenFrame.pack_propagate(0)
greenFrame.pack(side='top', padx=0, pady=0)
root.mainloop()
If you run this code, the greenFrame will appear as your image shows, at the top and centered inside redFrame.
If you want greenFrame to appear at the top left of redFrame, you can change the anchor point of the frame:
greenFrame = tk.Frame(redFrame, width=100, height=100, bg='green')
greenFrame.pack_propagate(0)
greenFrame.pack(side='top', padx=0, pady=0, anchor='w')
That is because when you do side="top" using pack, the widget gets allocated an entire strip of horizontal space. It gets centered within that space by default:
If you do side="left", then the widget gets allocated an entire strip of vertical space, and it gets centered in that space by default.
However in both cases you can change the anchor point, so that your component is placed differently within that allocated spaces.
This is the code which achieves what (I think) you want:
import tkinter as tk
root = tk.Tk()
root.geometry("600x400")
redFrame = tk.Frame(root, bg='red')
redFrame.pack_propagate(0)
redFrame.pack(fill='both', side='left', expand='True')
blueFrame = tk.Frame(root, bg='blue')
blueFrame.pack_propagate(0)
blueFrame.pack(fill='both', side='right', expand='True')
greenFrame = tk.Frame(redFrame, width=100, height=100, bg='green')
greenFrame.pack_propagate(0)
greenFrame.pack(side='top', padx=0, pady=0, anchor='w')
root.mainloop()
Related
I am trying to display another frame in the bottom left corner, however when I .pack() it, it does not display.
Here is my code:
import tkinter as tk
import customtkinter
window = customtkinter.CTk()
window.geometry("1900x980")
#customtkinter.set_appearance_mode("dark")
mainFrame = customtkinter.CTkFrame(window, width=1900, height=980)
mainFrame.pack()
mainFrame.pack_propagate(0)
topFrame = customtkinter.CTkFrame(mainFrame, width=1870, height=110, corner_radius=10)
topFrame.pack(side=tk.TOP, padx=10, pady=10)
topFrame.pack_propagate(0)
leftFrame = customtkinter.CTkFrame(mainFrame, width=400, height=825, corner_radius=10)
leftFrame.pack(side=tk.LEFT, padx=15, pady=5)
leftFrame.pack_propagate(0)
rightFrame = customtkinter.CTkFrame(mainFrame, width=1460, height=825, corner_radius=10)
rightFrame.pack(side=tk.RIGHT, padx=15, pady=5)
rightFrame.pack_propagate(0)
bottomLeftFrame = customtkinter.CTkFrame(mainFrame, width=400, height=20, corner_radius=10, bg_color="red")
bottomLeftFrame.pack(side=tk.LEFT)
bottomLeftFrame.pack_propagate(0)
window.mainloop()
To my understanding, if two objects are assigned side=tk.LEFT, then the second will be placed below the first one on the left hand side. However, this does not happen. Please see my output here.
Does any one know why this is? I have adjusted the height of both the left hand side frames so they should fit in the window.
I have an example code that use the Tkinter grid manager for creating and allocating four squares:
root=tk.Tk()
root.rowconfigure(0,weight=1)
root.rowconfigure(1,weight=1)
root.columnconfigure(0,weight=1)
root.columnconfigure(1,weight=1)
canv1=tk.Canvas(root, bg="blue")
canv2 = tk.Canvas(root, bg="yellow")
canv3 = tk.Canvas(root, bg="red")
canv4 = tk.Canvas(root, bg="green")
canv1.grid(row=0, column=0, sticky="nsew")
canv2.grid(row=0, column=1, sticky="nsew")
canv3.grid(row=1, column=0, sticky="nsew")
canv4.grid(row=1, column=1, sticky="nsew")
root.mainloop()
After the main window is created, the squares are proportionally expanding and shrinking when the window size is changed by mouse dragging. Squares are always changed proportionally whenever the windows change their size by dragging and moving any of its edge or window corners.
I'm trying to get this same effect with pack manager. So I have the code:
root=tk.Tk()
upper=tk.Frame(root)
lower=tk.Frame(root)
canv1=tk.Canvas(upper,bg="blue")
canv2 = tk.Canvas(upper, bg="yellow")
canv3 = tk.Canvas(lower, bg="red")
canv4 = tk.Canvas(lower, bg="green")
canv1.pack(side='left', fill='both', expand=True)
canv2.pack(side='right', fill='both', expand=True)
canv3.pack(side='left', fill='both', expand=True)
canv4.pack(side='left', fill='both', expand=True)
upper.pack(side='top', fill='both', expand=True)
lower.pack(side='bottom', fill='both', expand=True)
root.mainloop()
When the pack manager is used the squares are only expanded proportionally, when the size of window is changed. During the shrinking (by dragging some edge or corner), the squares not change their size proportionally.
I would like to ask - is it possible to make the squares shrink proportionally while changing windows size using pack manager?
The packer tries to preserve the original size of the widgets as long as possible. If a widget isn't large enough to fit, it only shrinks the widget that won't fit in its preferred size. Thus, if you shrink the window horizontally, the widgets on the right will shrink so that the size of the widgets on the left are preserved.
I think the only workaround is to give every canvas a preferred size of 1x1. If you do that, and then give your window as a whole a geometry (so that the entire window isn't just a couple pixels in size) you will get the behavior you want.
root.geometry("800x800")
...
canv1 = tk.Canvas(upper,bg="blue", width=1, height=1)
canv2 = tk.Canvas(upper, bg="yellow", width=1, height=1)
canv3 = tk.Canvas(lower, bg="red", width=1, height=1)
canv4 = tk.Canvas(lower, bg="green", width=1, height=1)
For this specific problem, I see no advantage to using pack over grid, since you are in fact creating a grid of widgets.
Given the following grid layout configuration:
It was generated through code:
from Tkinter import *
master = Tk()
frame1 = Frame(master, width=100, height=100, bg="red")
frame1.grid(sticky="nsew", columnspan=4)
frame2 = Frame(master, width=100, height=100, bg="blue")
frame2.grid()
frame3 = Frame(master, width=100, height=100, bg="green")
frame3.grid(row=1, column=1)
frame4 = Frame(master, width=100, height=100, bg="yellow")
frame4.grid(row=1, column=2)
frame4 = Frame(master, width=100, height=100, bg="purple")
frame4.grid(row=1, column=3)
master.mainloop()
I tried to insert a Entry in frame1 so it extends to the whole frame1 width with the following code:
e1 = Entry(frame1)
e1.grid(sticky="we", columnspan=4)
However, I have got the following result:
How can I make the Entry widget occupy the same width as the frame1?
The entry is inside frame1, so the grid it is in is completely unrelated to the grid in the root window.
Since you didn't tell tkinter what to do with extra space inside frame1, it left it unused. If you want the entry widget which is in column 0 to fill the frame, you need to give its column a weight.
frame1.grid_columnconfigure(0, weight=1)
If this is the only widget going in frame1, you might want to consider using pack since you can do it all in one line of code:
e1.pack(side="top", fill="x", expand=True)
I'm quite new to Tkinter but I have been practicing it for a bit now but whenever I try to move a label in a frame with grid geometry by specifying row and column, the label just stays in the middle.
In the code below, I try specifying the row and column for the name label which is in the top middle frame but it never moves. It just stays in the middle.
from tkinter import*
root=Tk()
frame_topleft = Frame(root, height=150, width=50, bg = "green")
frame_topmiddle = Frame(root, height=150, width=250, bg="red")
frame_topright = Frame(root, height=150, width=250, bg="green")
frame_bottomleft = Frame(root, height=300, width=50, bg="blue")
frame_bottommiddle = Frame(root, height=300, width=250, bg="yellow")
frame_bottomright = Frame(root, height=300, width=250, bg="blue")
label_name=Label(frame_topmiddle, text="Name", font="halvetica")
label_phone=Label(frame_topmiddle, text="Phone", font="halvetica")
frame_topmiddle.grid(row=0, column=1)
frame_topleft.grid(row=0, column=0)
frame_topright.grid(row=0, column=2)
frame_bottomleft.grid(row=1, column=0)
frame_bottommiddle.grid(row=1, column=1)
frame_bottomright.grid(row=1, column=2)
label_name.grid(row=0, column=0)
root.mainloop()
So, I'm just wondering how I can fix this. I want the name label at the top left of the top middle frame.
The frame_topmiddle shrinks to the size of label_name and is, by default, displayed at the center of (row 0, column 1).
If you set the sticky option of the grid method to 'nw':
frame_topmiddle.grid(row=0, column=1, sticky='nw')
then frame_topmiddle will be in the top left corner of (row 0, column 1) instead of the center.
If you want frame_topmiddle to keep its initial size, you need to do
frame_topmiddle.grid_propagate(False).
Is it possible to get a text box to have a border even when inactive?
I am not sure I know what "border when inactive" means, but you can certainly add a border to a Text in TkInter. The following code creates two outer frames and two inner frames, then adds a Text to each inner frame. The frames are given a border of 5 px on all sides.
from Tkinter import *
root = Tk()
left_outer = Frame(root, bd=1)
left_outer.pack(side=LEFT, fill=Y, pady=5, padx=5)
right_outer = Frame(root, bd=1)
right_outer.pack(side=LEFT, fill=Y, pady=5, padx=5)
left = Frame(left_outer, bd=2, relief=SUNKEN)
right = Frame(right_outer, bd=2, relief=SUNKEN)
left.pack(fill=Y)
right.pack(fill=Y)
t_start = Text(left, width=20, height=200)
t_start.pack(side=LEFT, fill=Y)
s_start = Scrollbar(left)
s_start.pack(side=RIGHT, fill=Y)
s_start.config(command=t_start.yview)
t_start.config(yscrollcommand=s_start.set)
t_end = Text(right, width=20, height=200)
t_end.pack(side=LEFT, fill=Y)
s_end = Scrollbar(right)
s_end.pack(side=RIGHT, fill=Y)
s_end.config(command=t_end.yview)
t_end.config(yscrollcommand=s_end.set)
root.geometry("400x200")
root.mainloop()
odie5533's answer covers giving a border to a frame that contains only a Text object. This is a great way to give a 2D around a text object, but adds another widget in the mix. I think the original question was related to setting both the border width and relief type of the Text object. This snippet gives a relief to the Text object without involving another frame.
from Tkinter import *
root = Tk()
text_top = Text(root, relief=GROOVE, height=5, width = 40, borderwidth=2)
text_top.pack()
text_bottom = Text(root, relief=RIDGE, height=5, width = 40, borderwidth=2)
text_bottom.pack()
root.geometry("400x200")
root.mainloop()