Label widget wont move inside of frame in tkinter - python

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

Related

How do I keep elements in a frame justified to the right while keeping the entire frame coloured, regardless of the size of the window?

I'm new to tkinter so I'm a little lost in terms of grid layout. What I'm trying to do is have a logo sit in the bottom right corner of the window, and always be in that position no matter how big the window is. I have managed to position the logo no problem, but when I justify to the right, the frame becomes white on the left side of the elements. How do I keep this part Black as it is under the logo? Left justify fills the whole frame with black, but right justify only fills from the logo/text onward.
This is what I am getting
Here is my current code:
from tkinter import *
root = Tk()
# GUI attributes
root.title('Lantern')
root.geometry('800x600')
root.iconbitmap('iconrl.ico')
# main containers
topFrame = Frame(root, bg='#000000', width=800, height=100, pady=3)
center = Frame(root, bg='#181818', padx=3, pady=3)
btmFrame = Frame(root, bg='#000000', width=800, height=90, padx=10)
# layout all of the main containers
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
topFrame.grid(row=0, sticky='ew')
center.grid(row=1, sticky='nsew')
btmFrame.grid(row=2, sticky='e')
# topFrame Widgets
rlLabel = Label(topFrame, text='Lantern ', font=('Verdana', 12), fg='red', bg='#000000', width=10)
# topFrame Layout
rlLabel.grid(row=0, columnspan=3)
# center Widgets
# center Layout
# btmFrame Widgets
powered = Label(btmFrame, text='Powered by: ', font=('Verdana', 12), fg='#FFF204', bg='#000000', width=15)
sLogo = PhotoImage(file='slogo.png')
sLogoLabel = Label(btmFrame, image=sLogo, bg='#000000')
# btmFrame Layout
powered.grid(row=0, column=1, sticky='e')
sLogoLabel.grid(row=0, column=2, sticky='e')
root.mainloop()
First you need to change btmFrame.grid(row=2, sticky='e') to btmFrame.grid(row=2, sticky='ew'), so that the frame fills all the space horizontally.
Then add btmFrame.columnconfigure(0, weight=1) to push the powered and sLogoLabel to the right of the frame.
Or you can use pack() on powered and sLogoLabel:
sLogoLabel.pack(side='right')
powered.pack(side='right')

How can I choose coordinate of tkinter frame?

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

Put a grid vertical line between columns in the middle of the window in Python Tkinter

It's a little complicated, but I'll try my best to explain:
let's say that for example, I have a grid with 4 labels when I have 2 rows and 2 columns (see image below). I'm trying to make the vertical line between columns 1 and 2 (red line in the image) to be the line that splits the window into two equal halves.
You can see a sample of my initial code below.
Edit: note that the elements are labels just for example, but in my original code they are actually all different (some are frames, some images, some buttons, etc)
import tkinter as tk
root = tk.Tk()
label1 = tk.Label(root, text=1, width=8, height=2, bg="red")
label1.grid(row=0, column=0)
label2 = tk.Label(root, text=2, width=10, height=3, bg="green")
label2.grid(row=0, column=1)
label3 = tk.Label(root, text=3, width=5, height=4, bg="blue")
label3.grid(row=1, column=0)
label4 = tk.Label(root, text=4, width=6, height=2, bg="yellow")
label4.grid(row=1, column=1)
root.mainloop()
This code makes the vertical and horizontal center lines of each label perfect as I wanted, but the vertical line between columns 1 and 2 (red line in image) is nowhere near to be the center of the window.
Then, I have tried adding the grid_columnconfigure function to my code:
import tkinter as tk
root = tk.Tk()
root.grid_columnconfigure(0, weight=1) # the line I've added
label1 = tk.Label(root, text=1, width=8, height=2, bg="red")
label1.grid(row=0, column=0)
label2 = tk.Label(root, text=2, width=10, height=3, bg="green")
label2.grid(row=0, column=1)
label3 = tk.Label(root, text=3, width=5, height=4, bg="blue")
label3.grid(row=1, column=0)
label4 = tk.Label(root, text=4, width=6, height=2, bg="yellow")
label4.grid(row=1, column=1)
root.mainloop()
But now I have a different problem, where the columns don't touch each other.
I've also tried to fix the issue by adding the sticky arguments when I'm placing the elements in the grid, and also tried putting every row and every column in their own frame, but all of the solutions did not work out for me.
How can I get this to work? Hope my explanation was clear, and thanks in advance (;
You could just put the four images/labels together into a Frame (or any other container element) and then have that frame horizontally and vertically centered in your root frame with place.
c = tk.Frame(root, bg='white')
c.place(relx=0.5, rely=0.5, anchor='center')
Don't forget to change the parent of the labels from root to c, i.e. Label(c, ...).
Update: But this does not center the line between the red and the green block to the frame. You could combine this with uniform to make the columns equal width, but then there will be some padding between the center and the thinner column...
for n in (0, 1):
c.grid_columnconfigure(n, uniform="foo")
You can use a ttk.Separator widget.
You should use the following code part:
import tkinter.ttk
import tkinter as tk
root = tk.Tk()
---etc---
---etc---
---etc---
tkinter.ttk.Separator(master, orient=VERTICAL).grid(column=1, row=0, rowspan=2, sticky='ns')
root.mainloop()
You can get the grid info of a widget with "grid_info" method.
row = widget.grid_info()['row'] # Row of the widget
column = widget.grid_info()['column'] # Column of the widget
Since there are 2 columns, root.grid_columnconfigure(0, weight=1) only affects the first column.
Try
for n in range(2):
root.grid_columnconfigure(n, weight=1)
or
root.grid_columnconfigure(0, weight=1)
root.grid_columnconfigure(1, weight=1)

How to make a widget occupy the same width as that of its master frame when using columnspan?

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)

Python Tkinter setting an inactive border to a text box?

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

Categories

Resources