tkinter pack() method not working for one label - python

import tkinter as tk
win = tk.Tk()
win.title('使用者登入')
win.geometry('300x200')
lb1 = tk.Label(win,text='使用者帳號資料',font=('微軟正黑體',16),fg='yellow',bg='black')
lb1.pack(fill='x')
lb2 = tk.Label(win,text='帳號 : ABCDEF',height=4,width=26,font=('標楷體',14),bg='lightblue')
lb2.pack(side='left',anchor='nw',fill='x')
lb3 = tk.Label(win,text='注意',height=50,width=3,font=('微軟正黑體',12),bg='pink')
lb3.pack(anchor='se',fill='y',expand=True)
lb4 = tk.Label(win,text='密碼 : 123456',height=4,width=15,font=('標楷體',14),bg='lightgreen')
lb4.pack(anchor='sw',side='left')
win.mainloop()
The variable lb4 could not be shown on the tkinter window even though I have used pack() method. I would like to put the lb4 widget below lb2 and I had tried using anchor='sw' still not showing so any possible methods to have that widget be shown properly?

The pack method works properly, check that:
import tkinter as tk
win = tk.Tk()
win.title('使用者登入')
win.geometry('300x200')
# lb1 = tk.Label(win,text='使用者帳號資料',font=('微軟正黑體',16),fg='yellow',bg='black')
# lb1.pack(fill='x')
#
# lb2 = tk.Label(win,text='帳號 : ABCDEF',height=4,width=26,font=('標楷體',14),bg='lightblue')
# lb2.pack(side='left',anchor='nw',fill='x')
#
# lb3 = tk.Label(win,text='注意',height=50,width=3,font=('微軟正黑體',12),bg='pink')
# lb3.pack(anchor='se',fill='y',expand=True)
lb4 = tk.Label(win,text='密碼 : 123456',height=4,width=15,font=('標楷體',14),bg='lightgreen')
lb4.pack(anchor='sw',side='left')
win.mainloop()
If it does show anything is because the pack method add widget to the right of the previous on if it's anchored to "S"(outh), even if the new widget it's anchored to 'w' and sided to 'left'.
Since lb3 is anchor at 'se', any other widget is displayed outside the windows.
You shoud use .grid to properly design your window:
import tkinter as tk
win = tk.Tk()
win.title('使用者登入')
lb1 = tk.Label(win, text='使用者帳號資料', font=('微軟正黑體', 16), fg='yellow',
bg='black')
lb1.grid(row=0, column=0, columnspan=3, sticky='WE')
lb2 = tk.Label(win, text='帳號 : ABCDEF', height=4, width=26, font=('標楷體', 14),
bg='lightblue')
lb2.grid(row=1, column=0, sticky='WE')
lb3 = tk.Label(win, text='注意', width=3, font=('微軟正黑體', 12), bg='pink')
lb3.grid(row=1, column=2, rowspan=2, sticky='NS')
#
lb4 = tk.Label(win, text='密碼 : 123456', height=4, width=15, font=('標楷體', 14),
bg='lightgreen')
lb4.grid(row=2, column=0, sticky='w')
win.mainloop()
It looks like this:
Here, I removed the height of lb3 since it's not required (sticky 'NS' allow us to extend the widget to top and down of the rowspan).
You can change column, row, columnspan, rowspan as you want to create the layout you desire.

Each time you use pack, it allocates an entire side for the widget. Thus, the order in which you call pack matters. For example, once you put widget along the top, you can no longer put something to the right.
This is usually much easier to visualize when you group all of your pack statements together for all children in the same parent widget. I also recommend always explicitly defining the side parameter so that your intentions are crystal clear.
This is the proper order to use pack to get lb4 below lb2, with lb1 along the top and lb3 along the right side:
lb1.pack(side="top", fill='x')
lb3.pack(side="right", fill='y')
lb2.pack(side="top", fill='x')
lb4.pack(side="top", fill='x')

I tried running your code and using lb4 before lb3 fixes the problem, but it won't display below lb2 as you have already used side='left' in lb2 so it acquires the whole left side, to pack it below lb2 remove the side='left' in lb2 and put it in lb4.
It doesn't display lb4 at first because it packs it outside of the TKinter window .
Instead of using .pack() use .grid() to better place the labels in the window.
This works:
import tkinter as tk
win = tk.Tk()
win.title('使用者登入')
win.geometry('300x200')
lb1 = tk.Label(win,text='使用者帳號資料',font=('微軟正黑體',16),fg='yellow',bg='black')
lb1.pack(fill='x')
lb2 = tk.Label(win,text='帳號 : ABCDEF',height=4,width=26,font=('標楷體',14),bg='lightblue')
lb2.pack(anchor='nw',fill='x')
lb4 = tk.Label(win,text='密碼 : 123456',height=4,width=15,font=('標楷體',14),bg='lightgreen')
lb4.pack(side='left',anchor='sw')
lb3 = tk.Label(win,text='注意',height=50,width=3,font=('微軟正黑體',12),bg='pink')
lb3.pack(anchor='se',fill='y',expand=True)
win.mainloop()

Related

Why does removing grid() make my program turn blank?

I'm using .place() in my tkinter program, so I wanted to remove references to grid(). So far my program works but for some reason there's a single .grid() line that makes my whole program turn blank if it's removed. This shouldn't happen, since I'm entirely using .place(). Here is that line:
AllFrames.grid(row=0, column=0, sticky='nsew')
And here is my full code:
from tkinter import *
root = Tk()
root.title("Account Signup")
DarkBlue = "#2460A7"
LightBlue = "#B3C7D6"
root.geometry('350x230')
Menu = Frame()
loginPage = Frame()
registerPage = Frame()
for AllFrames in (Menu, loginPage, registerPage):
AllFrames.grid(row=0, column=0, sticky='nsew')
AllFrames.configure(bg=LightBlue)
def show_frame(frame):
frame.tkraise()
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
show_frame(Menu)
# ============= Menu Page =========
menuTitle = Label(Menu, text="Menu", font=("Arial", 25), bg=LightBlue)
menuTitle.place(x=130, y=25)
loginButton1 = Button(Menu, width=25, text="Login", command=lambda: show_frame(loginPage))
loginButton1.place(x=85, y=85)
registerButton1 = Button(Menu, width=25, text="Register", command=lambda: show_frame(registerPage))
registerButton1.place(x=85, y=115)
# ======== Login Page ===========
loginUsernameL = Label(loginPage, text='Username').place(x=30, y=60)
loginUsernameE = Entry(loginPage).place(x=120, y=60)
loginPasswordL = Label(loginPage, text='Password').place(x=30, y=90)
loginPasswordE = Entry(loginPage).place(x=120, y=90)
backButton = Button(loginPage, text='Back', command=lambda: show_frame(Menu)).place(x=0, y=0)
loginButton = Button(loginPage, text='Login', width=20).place(x=100, y=150)
# ======== Register Page ===========
root.mainloop()
I've also noticed that changing anything in the parentheses causes the same result. For example, if I change sticky='nsew' to sticky='n' or row=0 to row=1 it will show a blank page.
How do I remove .grid() from my program without it turning blank?
The place() manager does not reserve any space, unless you tell it directly.
The grid(sticky='nsew') makes the widget expand to fill the entire available space, in this case the containing widget. The widgets inside all use place() which will not take any space. When you change to grid(sticky='n') you place the zero size widget at the top of the containing widget.
But, for your current problem you can assign a size to the widgets:
AllFrames.place(relwidth=1, relheight=1) # w/h relative to size of master
I would recommend using the grid() geometry manager if you are going to make any more complicated layouts.
For more info have a look at effbot on archive.org

how do i use expand on entrys while i can position them python 3 tkinter

I want to make entrys move while resizing. an example is this code.
i didnt want to upload the 300 line code because it does not have to do anything with the design.
as you can see when you resize it horizontaly the entry2 is moving horizontaly how do i do the same for entry1?
i tried the pack(expand=True) on entry1 but then the entry2 is placed in the position of button.
im sorry if i cant make the problem clear this is my first time asking questions about programming...
import tkinter as tk
app = tk.Tk()
app.geometry("600x350")
Canvas = tk.Canvas(height=600, width=1000, bg="#343434")
Canvas.pack(fill="both", expand=True)
Frame = tk.Frame(Canvas, height=600, width=1000, bg="#1A1A1A")
Frame.pack(fill="both", expand=True)
large_font = ('Verdana', 17)
entry1 = tk.Entry(Frame, bg="#F7F5EB", font=large_font, width=25)
entry1.place(rely=0.3, relx=0.17)
entry1.configure(foreground="gray")
entry2 = tk.Entry(Frame, bg="#F7F5EB", width=22, font=("Verdana", 11))
entry2.pack(expand=True)
entry2.configure(foreground="gray")
generate_button_font = ('Arial', 12)
Generate_button = tk.Button(
Frame, bg="#f0f0f0", font=generate_button_font, foreground="#525252")
Generate_button.place(rely=0.7, relx=0.35, relwidth=0.31, relheight=0.12)
Generate_button.config(text="Generate")
help_button_font = ("Arial", 10)
help_button = tk.Button(Frame, bg="#F7F5EB", font=help_button_font, foreground="#525252")
help_button.place(rely=0.03, relx=0.88, relwidth=0.1, relheight=0.075)
help_button.config(text="Help")
about_button_font = ("Arial", 10)
about_button = tk.Button(Frame, bg="#F7F5EB", font=help_button_font, foreground="#525252")
about_button.place(rely=0.03, relx=0.02, relwidth=0.1, relheight=0.075)
about_button.config(text="About")
app.mainloop()
You can use the .place() geometry manager.
Read more about it here.
Place has 3 main paramaters which I think you need.
The first is relx. This places any widget at a certain position in a widget, relative to the widgets x legnth.
For example, if the relx = 0.5, then no matter how much you resize the widget, the widget stays in the middle.
The second parameter is rely, which works the same as relx, except it applies to the y axis.
The third paramater is anchor. Anchor basically tells the program which part of the widget should go to the specified coordinate. The default is "nw" or top left. You can put it as center, or anything else.
Hopefully this helps!!

Can't prevent label from extending the main window

Example
(mimics the relevant parts of the layout in my real code)
import Tkinter as tk
import ttk
# set up root
root = tk.Tk()
root.minsize(300, 50)
frame = ttk.Frame(root)
frame.grid(row=0, column=0, sticky=tk.EW)
# set up buttons that insert a short or a long string
textvar = tk.StringVar(value='foo')
def insert_short():
textvar.set('foo')
def insert_long():
textvar.set('foo'*30)
button_short = ttk.Button(frame, text='short', command=insert_short)
button_short.grid(row=0, column=0)
button_long = ttk.Button(frame, text='long', command=insert_long)
button_short.grid(row=0, column=0)
button_long.grid(row=0, column=1)
# set up label
# border for label to see its size
style = ttk.Style()
style.configure(
'Bordered.TLabel', foreground='black', borderwidth=1, relief='solid')
# make label extend to the right
frame.columnconfigure(2, weight=1)
# place label
label = ttk.Label(frame, textvariable=textvar, style='Bordered.TLabel')
label.grid(row=0, column=2, sticky=tk.EW)
# place some other widget under label to mimic my real code
ttk.Button(frame, text='some other widget').grid(row=1, column=2)
# TRIED, NOT WORKING:
#root.resizable(False, False)
#frame.propagate(False)
#frame.grid_propagate(False)
#label.propagate(False)
#label.grid_propagate(False)
root.mainloop()
Output
Question
How do I prevent label from extending the main window?
(Bonus question, but not important: is there a way to make the label scrollable if it gets too long?)
Attempts
I tried the following commands:
root.resizable(False, False)
frame.propagate(False)
frame.grid_propagate(False)
label.propagate(False)
label.grid_propagate(False)
You can create a scrollable label using an Entry in a read-only state and by using scrolling it will prevent the widget from extending the main window.
Try replacing your label definition with the following code:
child_frm = ttk.Frame(frame)
label = ttk.Entry(child_frm, textvariable=textvar, style='Bordered.TLabel', state='readonly')
scroll = ttk.Scrollbar(child_frm, orient='horizontal', command=label.xview)
label.config(xscrollcommand=scroll.set)
label.grid(row=0, sticky=tk.EW)
scroll.grid(row=1, sticky=tk.EW)
child_frm.grid(row=0, column=2)
By default, the width of a Label is calculated based on its contents. You can override this behavior by specifying a value for width when creating the Label.
label = ttk.Label(frame, textvariable=textvar, style='Bordered.TLabel', width=1)
Much to my surprise, when I update your code with this, the label doesn't shrink to a size suitable for displaying exactly one character. It appears that the sticky=tk.EW argument of your grid call ensures that the label stays as wide as the widest element in the column.

Tkinter frame problem : resizing does not work

I want to be able to use nested frames but there is a weird behavior : when I enter the height and width parameters they seem to not work. I use .grid() Is that what is causing the problem ? I use ttk Frame, is there some behavior I do not know about ?
I looked at the documentation but nothing seemed to be helping. I tried changing the parameters but I didn't help either.
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Tk test")
root.geometry("800x800")
frame_1 = ttk.Frame(root, height=400, width=400, relief="sunken")\
frame_1.grid(row=0, column=0, rowspan=1, columnspan=1)
frame_2 = ttk.Frame(frame_1, height=200, width=200, relief="sunken")\
frame_2.grid(row=0, column=0, rowspan=1, columnspan=1, sticky="N, S, W, E")
label_1 = ttk.Label(frame_2, text="Text")
label_1.grid(row=0, column=0, sticky="S, W, N, E")
root.mainloop()
Expected result : there is a sunken frame inside another sunken frame. Inside the nested frame there is a label named "Text"
Actual result : The label is always in the upper left corner and does not want to move.
You can give cells on a grid a minimum size using the grid_columnconfigure() and grid_rowconfigure methods, as documented here.
Applied to your code (along with other corrections & improvements):
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Tk test")
root.geometry("800x800")
frame_1 = ttk.Frame(root, height=400, width=400, relief="sunken")
frame_1.grid(row=0, column=0)
frame_2 = ttk.Frame(frame_1, height=200, width=200, relief="sunken")
frame_2.grid(row=0, column=0, sticky="NSWE")
frame_2.grid_rowconfigure(0, minsize=200)
frame_2.grid_columnconfigure(0, minsize=200)
label_1 = ttk.Label(frame_2, text="Text")
label_1.grid(row=0, column=0, sticky="NW")
root.mainloop()
Since the grid manager doesn't know how many rows and columns there are to be on the main window, it doesn't allot the frames with the defined height and width.
If you add padding to each frame, you will see that the Text widget in not the upper left corner. But the Text widget will always be in the upper left corner as it has been placed on the 0th row and column.
Also, use rowconfigure and columnconfigure to ensure that the frames take the space specified by you on the main window.

Tkinkter Grid() alignment not as expected: Python 2.7

I am trying to use grid() function to align the labels and option menu side by side. Here's the code which I used to create a simple GUI:
from Tkinter import *
win1 = Tk()
win1.title("Chumma")
#Option selection frame:
f3 = Frame(win1)
f3.grid(column=0,row=0)
f3.pack()
l1 = Label(f3, text="Select the function which you want to perform: ", bg = "yellow")
moduleList = StringVar(f3)
moduleList.set("Normal Walk") #to display the default module name
o1 = OptionMenu(f3, moduleList, "Normal Walk", "Brisk Walk", "Running", "Custom")
b3 = Button(f3, text="Execute the option", fg="blue")
b4 = Button(f3, text="Stop", fg="red")
#Packing the stuffs in required order:
l1.grid(row=0, column=0, sticky=W) #E means east
l1.grid_rowconfigure(0, weight=1)
l1.grid_columnconfigure(0, weight=1)
l1.pack(fill = X, padx = 5)
o1.grid(row=0,column=1)
o1.grid_rowconfigure(0, weight=1)
o1.grid_columnconfigure(1, weight=1)
o1.pack()
b4.pack()
win1.mainloop()
The result is:
I am expecting the option menu o1 to be at the right of the l1.
If I comment the pack command [ l1.pack() and o1.pack() ], the program is not displaying any GUI at all.
After you call grid, a couple of lines later you call pack which cancels out the use of grid. Use one or the other but not both for each widget. Sinc pack defaults to side='top', your widgets appear stacked on top of each other.
The reason you see nothing if you comment out those two calls to pack is because you are still calling b4.pack(), and you can't use both pack and grid for different widgets with the same parent.
Also, the calls to rowconfigure and columnconfigure need to be on the parent widget. Calling them on the label widget will only affect widgets you put inside the label (which is possible, but unusual)
I believe Tkinter does not allow mixing up packing schemes (grid, pack, place) in one frame. Here is example how to organize three widgets.
from Tkinter import *
root = Tk()
label = Label(root, text='blablabla')
someotherwidget = Entry(root)
button = Button(root, command=lambda: None, text='Boom')
label.grid(row=0, column=0)
someotherwidget.grid(row=0, column=1)
button.grid(row=1, column=0, columnspan=2)
root.mainloop()
Option 'columspan' is like how many columns you want to join to place the widget. We have 2 columns here so if we want to see button not below label but below of both label and someotherwidget we have to specify 'columnspan' option (obviously, analog for rows is 'rowspan')

Categories

Resources