I want to anchor this label but for some reason, it keeps going off the screen in my computer, i don't know if its just me but here's my code:
import tkinter as tk
root = tk.Tk()
root.attributes("-fullscreen", True)
label_frame = tk.Frame(root)
answer_label = tk.Label(label_frame, text="text")
answer_label.grid(row = 0, column = 0)
label_frame.place(anchor = "n")
root.mainloop()
Why does this label go off screen when anchored?
Consider this line of code:
label_frame.place(anchor = "n")
The anchor option tells tkinter what part of the frame is to be placed at the given coordinates. n means "north", or the top-center of the frame. So, whatever coordinates are given, the top-center portion of the frame will be at those coordinates.
Since you did not give any coordinates, they default to x=0 and y=0. Thus, the top-middle portion of the frame will be placed at 0,0. That means that the left half of the frame will be to the left of coordinate 0,0.
If you insist on using place, and if you want the frame centered, you can give a relx of .5, meaning that the anchor position (n) will be placed half-way across the width of the containing widget.
label_frame.place(relx=.5, y=0, anchor = "n")
try
label_frame.place(anchor = "nw")
Tested this and it seems to put the label in the right place.
Related
I'm struggling with Tkinter now. I wanted to create layout but if I define window dimensions (800x600) and create frame which have to be wide 800 too, it have just half.
I tried googling and changing code, if I multiply width 2 times (to 1600) then frame fit the screen perfetly.
Here is code:
import tkinter as tk
SW, SH = 800, 600
win = tk.Tk()
win.geometry(f"{SW}x{SH}")
frm_appname = tk.Frame(
master = win,
bg = 'red'
)
frm_appname.place(
anchor = tk.N,
width = 800,
relheight = (1/6)
)
Here is output:
Can anyone explain me what happened here?
The anchor of "n" (tk.N) means that the top center portion of the frame is at the given coordinate. Since you didn't provide an x and y coordinate for place it defaults to 0,0. So, the top/middle (400,0) of the frame is at coordinate 0,0.
If you set the anchor to "n" or tk.NW, the top-left corner of your frame will be in the top-left corner of the window.
On an unrelated note, experience has taught me that layouts are nearly always easier to create with pack and/or grid. In my coupe of decades of using tk and tkinter, I've never used place for more than one or two special-case widgets.
import tkinter as tk
root = tk.Tk()
root.title("window")
yellow_header = tk.Label(root, text = 'Header', bg = 'light yellow')
yellow_header.pack(side = tk.TOP, anchor = tk.N, expand = 1, fill = tk.X)
yellow_header2 = tk.Label(root, text = 'paragraph', bg = 'light yellow')
yellow_header2.pack(side = tk.TOP, anchor = tk.N, expand = 1, fill = tk.X)
root.mainloop()
For the above code I am trying to have both these labels anchored to the top and directly below one another. Although the first label (yellow_header) anchors to the top, where as the second label (yellow_header2) when expanded move towards the centre. How can I fix this?
Thank you in advance!
Don't use expand=1. From effbot:
The expand option tells the manager to assign additional space to the widget box. If the parent widget is made larger than necessary to hold all packed widgets, any exceeding space will be distributed among all widgets that have the expand option set to a non-zero value.
With expand=1, when you make the window larger, the space is distributed between the two labels. So even though you only tell them to fill it in the X direction, they are given the space in both directions. The second label is placed directly under the space that is available to the first label, which is half of the window.
I've tried to explain and visualize the difference between expand and fill in this answer.
P.S. You don't need anchor=tk.N either. When the space available to the widget and the size of the widget are the same, the anchor option makes no difference. Also, side=tk.TOP is the default so you could decide to omit that too, leaving you with only fill=tk.X.
Looking at the docs I see:
The Text widget is used to display text in multiple lines.
and this seems to work:
import tkinter as tk
root = tk.Tk()
root.title("window")
yellow_header = tk.Label(root, text = 'Header\nParagraph', bg = 'light yellow')
yellow_header.pack(side = tk.TOP, anchor = tk.N, expand = 1, fill = tk.X)
That might be a bit OS specific and perhaps the proper way would be:
import os
...
yellow_header = tk.Label(root, text = 'Header' + os.linesep + 'Paragraph', bg = 'light yellow')
When increasing the length of the first string the second still remains in the center.
I was trying out something new on Tkinter (I am still a newbie), but it keeps failing...maybe someone could help out?
I wanted to create a window with several Frames, so that I can open and close them and show that way different content. However I am already stuck with not being able to "place" the, in this case a button, to the frame. Instead I get a blank frame with nothing inside...
The reason I want to use the place manager is so that I can easily choose the x and y coordinates. I don't want to create empty columns just in order to get a button appear in the middle of the screen.
Here the code:
from Tkinter import *
root = Tk()
root.title("Tkinter window")
root.geometry("800x600")
StartFrame = Frame(root)
StartFrame.pack()
Button1 = Button(StartFrame, command = StartTkinter, text = "Start", bg = "white", fg = "black", height = 2, width = 15)
Button1.place(x=0, y=50)
root.mainloop()
The problem is that you forgot to specify the dimensions of the frame. So, by default, it is created to be just 1 pixel high and 1 pixel wide. This means that its contents will not be visible on the window.
To fix the problem, you can either set exact values for these dimensions when you create the frame:
StartFrame = Frame(root, height=600, width=800)
or you can do:
StartFrame.pack(expand=True, fill="both")
to have the frame fill all available space.
Relevant code:
self.propertyListWrapper = ttk.Frame(self.propertyMenu)
self.propertyListWrapper.pack( fill = tk.BOTH, expand = tk.YES )
self.propertyListCanvas = tk.Canvas(self.propertyListWrapper)
self.propertyListCanvas.pack( fill = tk.BOTH, expand = tk.YES, side = tk.LEFT )
self.propertyGrid = ttk.Frame(self.propertyListCanvas)
self.propertyListScrollbar = ttk.Scrollbar(self.propertyListWrapper)
self.propertyListScrollbar.config(command = self.propertyListCanvas.yview)
self.propertyListCanvas.config(yscrollcommand = self.propertyListScrollbar.set)
self.propertyListScrollbar.pack(side = tk.RIGHT, fill = tk.Y)
...
# where stuff is added to self.propertyGrid
...
self.propertyListCanvas.config( scrollregion = (0, 0, self.propertyGrid.winfo_width(), self.propertyGrid.winfo_height()))
self.propertyListCanvas.create_window((0,0), window = self.propertyGrid, anchor='nw')
This is what is currently happening:
As you can see, the scrollbar doesn't have a bar. Not very useful.
What am I doing wrong?
Here's a simplified Github Gist that duplicates the problem. 20 labels should be there, and you should be able to scroll through them, but the scrollbar doesn't appear.
The default for pack is to put something along the top edge. When you packed the canvas you're using the default, so it takes up the top of the gui, leaving blank space below. When you packed the scrollbar, you told it to go to the right, so it is at the right edge of the empty space below the canvas. If you want the scrollbar and canvas side-by-side, pack both on the right, or pack one on the right and one on the left.
The problem with your gist is that you're trying to get the width and height of the frame before it has been drawn. Since the frame hasn't been mapped to the screen (because you haven't added it to the canvas yet) it's width and height is 1 (one). You must make a widget visible before you can measure its width and height. That means to add it to a canvas or pack/place/grid it to a visible window and then wait for a screen repaint.
hi is there any way to change width and height of widget even if there's widget?
i have code like this
form = Tk()
form.geometry("500x500")
def click():
global frame
frame.config(height = 0 ,width = 0)
frame = LabelFrame(form , text = "vaaja")
frame.place(x = 20 , y = 30)
Label(frame, text ="1").grid(row = 0,column = 0 )
Label(frame, text = "2").grid(row = 1 ,column = 0 )
Button(form , text="Click", command = click).place(x = 200 , y = 200)
form.mainloop()
and when I click the button the size of the frame is the same ( I'cant use grid_forget() for labels and then change the size of frame)
Because you are using place, you have two solutions: you can use place to set the width and height to zero, or you can turn geometry propagation off.
Using place to set the width and height
place allows you to define the width and the height of the placed widget, so in your click function you can do this:
def click():
frame.place_configure(width=0, height=0)
Turning geometry propagation off
A frame is resized to fit its contents by something called "geometry propagation". If you turn this off, you can control the size of the frame with the width and height options of the frame itself. Usually it's better to let Tkinter decide the size for you, but sometimes there's a need to have an explicit size, which is why it's possible to turn geometry propagation off.
Since you are using grid to manage the widgets internal to the frame, you need to use grid_propagate(False) to turn geometry propagation off for that frame:
frame.grid_propagate(False)
By doing so, you're responsible for setting the initial width and height of the widget, though you could leave propagation on to get the initial size, then turn it off with the button click in order to work around that issue.
There's an interesting bug (or feature...) in that if you set the width and height to zero, Tkinter won't redraw the window. At least, it doesn't on the Mac. I don't recall the workaround for that because I never, ever need to set a widget to a zero size, but setting it to 1x1 pixel makes it nearly invisible.