I've switched from .grid() to .place() in my program, so I decided to remove a frame that contained the grid widgets:
BackButtonR = Button(registerPage, text="Back", command=lambda: show_frame(Menu))
BackButtonR.grid(row=0, column=0, sticky=W)
Button2F3 = Button(registerPage, text="Find")
Button2F3.grid(row=1, column=1)
Button3F3 = Button(registerPage, text="Calculate").grid(row=6, column=1)
LabelTitleF3 = Label(registerPage, text="Calculate Buy Price").grid(row=0, column=3)
label1F3 = Label(registerPage, text="Enter Ticker Symbol:").grid(row=1, column=0)
label2F3 = Label(registerPage, text="Expected CAGR").grid(row=2, column=0)
label3F3 = Label(registerPage, text="Years of Analysis").grid(row=3, column=0)
label4F3 = Label(registerPage, text="Expected PE Ratio").grid(row=4, column=0)
label5F3 = Label(registerPage, text="Desired Annual Return").grid(row=5, column=0)
entry1F3 = Entry(registerPage, width=7).grid(row=1, column=1, padx=0)
entry2F3 = Entry(registerPage).grid(row=2, column=1, pady=10, padx=0)
entry3F3 = Entry(registerPage).grid(row=3, column=1, pady=10, padx=0)
entry4F3 = Entry(registerPage).grid(row=4, column=1, pady=10, padx=0)
entry5F3 = Entry(registerPage).grid(row=, column=1, pady=10, padx=0)
But weirdly, when I rerun my program everything turns blank. This shouldn't happen, since I've removed any reference to .grid(), so the program should be working fine with .place(). Here is my full code:
print(220+135)
from tkinter import *
root = Tk()
root.title("Account Signup")
DarkBlue = "#2460A7"
LightBlue = "#B3C7D6"
root.geometry('350x230')
Menu = Frame(root)
loginPage = Frame(root)
registerPage = Frame(root)
for AllFrames in (Menu, loginPage, registerPage):
AllFrames.grid(row=0, column=0, sticky='nsew')
AllFrames.configure(bg=LightBlue)
def show_frame(frame):
frame.tkraise()
show_frame(Menu)
# ============= Menu Page =========
Menu.grid_columnconfigure(0, weight=1)
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()
Why is my program turning blank?
When you use pack and grid, these functions will normally adjust the size of a widget's parent to fit all of its children. It's one of the most compelling reasons to use these geometry managers.
When you use place this doesn't happen. If you use place to put a widget in a frame, the frame will not grow or shrink to fit the widget.
In your case you're creating Menu, loginPage and registerPage and not giving them a size so they default to 1x1 pixels. When you use place to add a widget to the frame, the frame will remain at 1x1 pixels, rendering it virtually invisible.
The solution is to either give these frames an explicit size, or add the frames to the window with options that cause them to fill the window.
For illustrative purposes I've changed the background color of the window to pink, and set the size of Menu to 200x200. As you can see in the following screenshot, the frame with the widgets is there, and becomes visible when you give it a larger size. Of course, one problem with place is it's up to you to calculate the appropriate size.
The better solution in this specific case would be to use the appropriate grid options to have the frames fill the window. You can do that by giving a weight to the row and column that the frames are in. Unused space in the parent frame will be allocated to the row and column with the widget.
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
Generally speaking, grid and pack are superior to place for implementing most layouts because they are able to automatically make all widgets fit into a window with very little work. With place it's up to you to do calculations for position and size, and to make sure that all ancestors are appropriately sized and are visible.
You need to call root.grid_rowconfigure(0, weight=1) and root.grid_columnconfigure(0, weight=1) so that the shown frame use all the space of root window, otherwise the size of those frames are 1x1.
Also Menu.grid_columnconfigure(0, weight=1) is useless because widgets inside Menu are using .place().
Related
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
So I'm trying to expand my LabelFrame named "Admin Frame" in the X and Y directions somewhat like the pack() system's fill=BOTH argument but it doesn't seem to be working. But I want to be able to do this with the grid()system because I have a complex interface.
This is my code for the LabelFrame:
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Election App Mockup")
root.geometry("800x600")
root.resizable(0,0)
frameStyle = ttk.Style().configure("my.TLabelframe.Label")
adminFrame = ttk.LabelFrame(root, text="Admin Panel", style="my.TLabelframe")
adminWinLabel = ttk.Label(adminFrame, text="Welcome Admin")
voterOpBtn = ttk.Button(adminFrame, text="Configure Voters' List", style="my.TButton")
candidateOpBtn = ttk.Button(adminFrame, text="Configure Candidates' List", style="my.TButton")
setVoteSessionBtn = ttk.Button(adminFrame, text="Setup Voting Session", style="my.TButton")
startVoterSessionBtn = ttk.Button(adminFrame, text="Start a Voting Session", style="my.TButton", padding=(25,3,25,3))
adminSettingBtn = ttk.Button(adminFrame, text="Admin Settings", style="my.TButton", )
adminLogoutBtn = ttk.Button(adminFrame, text="Logout", style="my.TButton", padding=(20,3,20,3))
adminWinLabel.grid(row=0, column=0, columnspan=2, pady=(170,5), padx=(150,0))
voterOpBtn.grid(row=1, column=0, padx=(150,5), pady=(10,10), ipadx=15)
candidateOpBtn.grid(row=1, column=1, padx=(10,5), pady=(10,10))
setVoteSessionBtn.grid(row=2, column=0, padx=(150,5), pady=(10,10), ipadx=15)
startVoterSessionBtn.grid(row=2, column=1, padx=(10,5), pady=(10,10))
adminSettingBtn.grid(row=3, column=0, padx=(130,0), pady=(10,10), columnspan=2)
adminLogoutBtn.grid(row=4, column=0, padx=(130,0), pady=(10,10), columnspan=2)
adminFrame.grid(row=0, column=0, sticky=NSEW)
adminFrame.grid_rowconfigure(0, weight=1)
adminFrame.grid_columnconfigure(0, weight=1)
root.mainloop()
I've tried adding extra arguments like ipadx and ipady in but it doesn't work:
adminFrame.grid(row=0, column=0, sticky=NSEW, ipadx=200, ipady=20)
Adding a padding argument in the adminFrame does work but it is very tricky to work with just to expand the frame to the window's full length and breadth.
Thanks in advance! Oh and do note that I did not learn object oriented programming in python, so I won't understand any answers using the class system.
So I'm trying to expand my LabelFrame named "Admin Frame" in the X and Y directions somewhat like the pack() system's fill=BOTH argument but it doesn't seem to be working.
As a rule of thumb, any time you use grid to manage widgets, you should give at least one row and one column a weight greater than zero. You are putting adminFrame in the root window with grid, but you haven't given any rows or columns in the root window a weight.
So, if you want adminFrame to expand to fill the window, you need to give a weight of 1 to row 0 and column 0. The other thing that needs to be done -- that you are already doing -- is to set the sticky attribute so that the frame "sticks" to all four sides of the space allocated to it.
adminFrame.grid(row=0, column=0, sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
Look at this:
from tkinter import *
from tkinter import ttk
root = Tk()
root.title("Election App Mockup")
root.geometry("800x600")
# root.resizable(False, False)
frameStyle = ttk.Style().configure("my.TLabelframe.Label")
adminFrame = ttk.LabelFrame(root, text="Admin Panel", style="my.TLabelframe")
adminWinLabel = ttk.Label(adminFrame, text="Welcome Admin")
# A frame for the centre 4 buttons
centre_buttons_frame = Frame(adminFrame)
voterOpBtn = ttk.Button(centre_buttons_frame, text="Configure Voters' List", style="my.TButton")
candidateOpBtn = ttk.Button(centre_buttons_frame, text="Configure Candidates' List", style="my.TButton")
setVoteSessionBtn = ttk.Button(centre_buttons_frame, text="Setup Voting Session", style="my.TButton")
startVoterSessionBtn = ttk.Button(centre_buttons_frame, text="Start a Voting Session", style="my.TButton", padding=(25,3,25,3))
adminSettingBtn = ttk.Button(adminFrame, text="Admin Settings", style="my.TButton", )
adminLogoutBtn = ttk.Button(adminFrame, text="Logout", style="my.TButton", padding=(20,3,20,3))
# I think the buttons looks better when they have an equal size so I added
# sticky="ew" to expand them in the horizontal direction.
voterOpBtn.grid(row=0, column=0, sticky="ew", padx=(0,15), pady=10, ipadx=15)
candidateOpBtn.grid(row=0, column=1, sticky="ew", padx=(15,0), pady=10)
setVoteSessionBtn.grid(row=1, column=0, sticky="ew", padx=(0,15), pady=10, ipadx=15)
startVoterSessionBtn.grid(row=1, column=1, sticky="ew", padx=(15,0), pady=10)
adminWinLabel.grid(row=1, column=1, pady=(0,5))
centre_buttons_frame.grid(row=2, column=1)
adminSettingBtn.grid(row=3, column=1, pady=10)
adminLogoutBtn.grid(row=4, column=1, pady=(10,0))
# `adminFrame` is packed in the root so it can expand. There should be a way
# to make it work with .grid, but .pack is easier in this case
adminFrame.pack(fill="both", expand=True)
# Expand the 0th and 6th row - there are no widgets
adminFrame.grid_rowconfigure((0, 6), weight=1)
adminFrame.grid_columnconfigure((0, 3), weight=1)
root.mainloop()
It looks like this on my computer:
I added a frame for the centre 4 buttons so that I can avoid columnspan. Also I used adminFrame.pack(fill="both", expand=True) because it is easier than using .grid_propagate(False) and manually setting the width and height of the frame.
Right now, the GUI should look good with any window size.
So I want to insert some objects in a frame, but when I firstly added a button the frames where were they weren't suppoused to.
Before
After
And this is the code:
import tkinter as tk
root = tk.Tk()
root.geometry("1200x700")
# Main frames
frame1 = tk.Frame(root, width=1200, height=625)
frame2 = tk.Frame(root, width=1200, bg="black", height=75)
frame1.grid(row=1, column=1)
frame2.grid(row=2, column=1)
# Secondary frames
frame1browser = tk.Frame(frame1, height=625, width=850, bg="grey")
frame1a = tk.Frame(frame1,height=625, width=(1200-850))
frame1browser.grid(row=1, column=1)
frame1a.grid(row=1, column=2)
# Last frames
frame1aa = tk.Frame(frame1a, width=(1200-850),height=525, bg="green")
frame1ab = tk.Frame(frame1a, width=(1200-850),height=100, bg="yellow")
frame1aa.grid(row=1, column=1)
frame1ab.grid(row=2, column=1, sticky="nswe")
# Elements that are not frames
Button1 = tk.Button(frame1ab, text="ur mother")
Button1.grid(column=1, row=1)
root.mainloop()
The frame ignores the width/height explicitly given if there is a widget inside it, by default. AFAIK, It finds and uses the minimum size required to fit all the widgets, also accommodating to extra properties like sticky, expand and so on.
To override this behavior, you will have to use the <grid/pack>_propagate(False) depending on whether you use pack or grid on the items inside the frame. Now the frame will grow/shrink as much as the size you specify.
frame1ab.grid_propagate(False)
I am new with tkinter.
I am trying to make GUI and for the moment I made 3 RadioBoxe and a slider. and this what I got:
The problem that I want the 3 RadioBox to be in the same line and bellow them the slider. Is it possibe?
and I want the slider to go through odd numbers only (1,3,5,7,9 ...)
This is my code so far:
window = Tk()
window.title("Welcome to LikeGeeks app")
panelA = None
menu = Menu(window)
new_item = Menu(menu)
new_item.add_command(label='Open File', command=open_file)
new_item.add_separator()
new_item.add_command(label='Save File')
new_item.add_separator()
new_item.add_command(label='Exit')
menu.add_cascade(label='File', menu=new_item)
window.config(menu=menu)
label_blur = Label(window, text="Blurring")
label_blur.pack(anchor="w", padx=10, pady=10)
blur_rad1 = Radiobutton(window, text='Average', value=0)
blur_rad2 = Radiobutton(window, text='Gaussian', value=1)
blur_rad3 = Radiobutton(window, text='Median', value=2)
blur_rad1.pack(anchor="w", padx=10, pady=0)
blur_rad2.pack(anchor="w", padx=10, pady=0)
blur_rad3.pack(anchor="w", padx=10, pady=0)
blur_slide = Scale(window, from_=1, to=31, length=600,tickinterval=5, orient=HORIZONTAL)
blur_slide.pack(anchor="w", padx=10, pady=10)
window.mainloop()
There are two simple solutions: use grid so that you can specify the row and columns, or continue to use pack, but place the radiobuttons in a separate frame.
Since you're already using pack, it's easiest to use the second method.
Create a frame for the buttons, and use pack to add it to the window where you want it to appear:
button_frame = Frame(window)
button_frame.pack(side="top", fill="x")
Make the buttons children of the frame:
blur_rad1 = Radiobutton(button_frame, ...)
blur_rad2 = Radiobutton(button_frame, ...)
blur_rad3 = Radiobutton(button_frame, ...)
Use pack to lay out the buttons left-to-right:
blur_rad1.pack(side="left", expand=True)
blur_rad2.pack(side="left", expand=True)
blur_rad3.pack(side="left", expand=True)
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.