from tkinter import *
# ==================================================Settings=======================================================
root = Tk()
root.title("Video Youtube Downloader") # set up the title and size.
root.configure(background='black') # set up background.
root.minsize(800, 500)
root.maxsize(800, 500)
# ==================================================Frames=======================================================
top = Frame(root, width=800, height=50, bg='yellow').pack(side=TOP)
bottom = Frame(root, width=800, height=50, bg='red').pack(side=BOTTOM)
left = Frame(root, width=550, height=450, bg='black').pack(side=LEFT)
right = Frame(root, width=250, height=450, bg='blue').pack(side=RIGHT)
# ==================================================Buttons=======================================================
btn_clear_url = Button(right, text="Clear Url", font=('arial', 10, 'bold')).grid(row=1, columns=1)
I am trying to add buttons to the right Frame, but for some reason when I run the program the IDE shows that it is running but there is
no window. When I delete .grid(row=1, columns=1) the window appears.
How can I fix this bug, and add btn_clear_url button to the right Frame?
First of all, you need to invoke Tk's mainloop at the end of your code (you can see here why).
Another problem is chaining method calls like that. You're actually assigning return value of the last call to the variable, which is None in case of grid() and pack() - therefore, all your variables end up having None as the value. You need to separate widget instantiating call and grid or pack call and put each on its own line.
Other than that, you're setting both minsize and maxsize to the very same size - if you're really just trying to make your window not resizable, set the size with:
root.geometry('800x500') # for instance
...and after that configure resizable attribute:
root.resizable(width=False, height=False)
Also, I suggest you get rid of from tkinter import *, since you don't know what names that imports. It can replace names you imported earlier, and it makes it very difficult to tell where names in your program are supposed to come from. Use import tkinter as tk instead.
When you place widget in a tk window you cannot use grid and pack at the same time in the same window, so you use should use pack () instead of grid()
The problem starts with this line of code:
right = Frame(root, width=250, height=450, bg='blue').pack(side=RIGHT)
With that, right is set to None because .pack(side=RIGHT) returns None.
Next, you do this:
btn_clear_url = Button(right, ...)).grid(row=1, columns=1)
Because right is None, it's the same as Button(root, ...). Since you are already using pack for a widget in root, you can't also use grid.
The solution -- and best practice -- is to separate widget creation from widget layout:
top = Frame(root, width=800, height=50, bg='yellow')
bottom = Frame(root, width=800, height=50, bg='red')
left = Frame(root, width=550, height=450, bg='black')
right = Frame(root, width=250, height=450, bg='blue')
top.pack(side=TOP)
bottom.pack(side=BOTTOM)
left.pack(side=LEFT)
right.pack(side=RIGHT)
With the above, right will be properly set to the frame instance, and adding a widget to right and using grid will no longer fail.
Related
I have a tkinter window with several images that use grid. I tried to grid a scrollbar to the right side of the window but don't know what options to use because "side = right", "fill = Y" cannot be used inside grid. Any suggestions?
Grid is row / column oriented. So each widget needs its row and column in the geometry manager set. Here is a demo that answers the question posed.
# create a widget and scrollbar
import tkinter as tk
root = tk.Tk()
text = tk.Text(root)
vs = tk.Scrollbar(root, command=text.yview)
text.configure(yscrollcommand=vs.set)
# set the row, column and expansion for each widget
text.grid(row=0, column=0, sticky='news')
vs.grid(row=0, column=1, sticky='news')
# now make the grid manager expand to fill the available space in root.
# making 0, 0 expand to use all the spare space and 0,1 be fixed
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
If you are managing a set of images on label widgets then put them in a frame to separate out the geometry management of those. You might want to consider if you should
put them into a canvas instead which has quite good scrolling support.
I know you can align a button to the left with pack(side="left"), and you can also do right top and bottom, but how would i align stuff on a new line just below a set of buttons above it?
I tried using grid but no matter how much i googled it I couldn't find out how to fix it.
What you'd want to do is create different frames, each with their own positioning logic. Take a look at this:
import tkinter
root = tkinter.Tk()
frame = tkinter.Frame(root)
frame.pack()
bottomframe = tkinter.Frame(root)
bottomframe.pack(side=tkinter.BOTTOM)
tkinter.Button(frame, text="left").pack(side=tkinter.LEFT)
tkinter.Button(frame, text="middle").pack(side=tkinter.LEFT)
tkinter.Button(frame, text="right").pack(side=tkinter.LEFT)
# what you want
tkinter.Button(bottomframe, text="top").pack(side=tkinter.TOP)
tkinter.Button(bottomframe, text="under").pack(side=tkinter.TOP)
root.mainloop()
I am just building my first tkinter window and I am a little puzzled. I created a label and a Button and set them in them same row but different columns.
Now the placement of the button changes depending on the length of the text in the label. To fix this I wanted to "stick" the label and the button to east/west respectively and add a small amount of padding.
Now the issue, no matter what variant of "sticky" I add it doesn't affect the placement of anything at all.
Below are the two code variants that all lead to the same output window:
from tkinter import *
def Btt_ShowAll_clicked():
print("klicked")
#create the window
Main_Window = Tk()
#Modify the Window
Main_Window.title("Ressourcen Verwaltung")
Lbl_Descr_a = Label(Main_Window, text = "Einträge einsehen")#Create Label
Lbl_Descr_a.grid(column=0, row=0, padx=10) #Show Label
Btt_ShowAll_a = Button(Main_Window, text="Einträge anzeigen")
Btt_ShowAll_a.bind("<Button-1>",Btt_ShowAll_clicked)#Button click starts function
Btt_ShowAll_a.grid(column=1, row=0, padx=10, pady=10, sticky=W)
#In the line above Change "W" to "E" ord delet the "sticky = W" alltogether and nothing changes in the window
Main_Window.geometry('350x200') #Window size
#Make the windows stay (loop)
Main_Window.mainloop()
What can I do to get the desired output?
Shouldn't "sticky" stick it to the given side and then with padx I should be able to choose how close it is said side?
As far as I know, you have to type sticky='w' instead of sticky=W, should work then.
I have been making some gui applications using python tkinter.In tkinter pack and grid cannot be used together.While writing a code I had to use pack and then I needed to use 2 features called 'Cloumn' and 'row' of grid but that is impossible.
from tkinter import *
root = Tk()
button = Button(root, text="Click Me")
button.pack(side="bottom") #But I want to put that button in row=3
root.mainloop()
I need to put that button in row number 3.But how can I do it?
Is there any way to do so?
In order for pack and grid to be used in the same code you need to make sure you use them on separate containers. Each container (root window, toplevel window, frame) can only have either grid() or pack().
For example if I need to use pack on a frame and then use grid inside of that frame that is ok. But I cannot use pack inside the frame and also grid inside the frame.
If you expand the window made from the below code you will see how pack and grid can work together if used properly.
import tkinter as tk
root = tk.Tk()
top_frame = tk.Frame(root)
top_frame.pack(sid="top")
bot_frame = tk.Frame(root)
bot_frame.pack(sid="bottom")
tk.Label(top_frame, text="Row 0 of top_frame").grid(row=0, column=0)
tk.Label(bot_frame, text="Row 0 of bot_frame").grid(row=0, column=0)
tk.Label(bot_frame, text="Row 1 of bot_frame").grid(row=1, column=0)
tk.Label(bot_frame, text="Row 2 of bot_frame").grid(row=2, column=0)
tk.Button(bot_frame, text="Row 3 of bot_frame").grid(row=3, column=0)
root.mainloop()
I wrote a collapsible frame widget and was hoping to give it a dock/undock property. From what I've read, widgets can't be placed "over" other widgets (except on canvases, which I wish to avoid) so I can't just "lift" the frame, and their master cannot be changed so I can't simply place the frame into a new Toplevel. The only other option I can think of is to copy the widget into the new Toplevel. Unfortunately, I don't see any options on the copy or deepcopy operations to change the Master before the new widget is created.
So, the question:
Are these assumptions accurate, or is there a way to do any of these things?
If not, do I have any other options than the solution I put together here:
def copywidget(self, frame1, frame2):
for child in frame1.winfo_children():
newwidget = getattr(tkinter,child.winfo_class())(frame2)
for key in child.keys(): newwidget[key] = child.cget(key)
if child.winfo_manager() == 'pack':
newwidget.pack()
for key in child.pack_info():
newwidget.pack_info()[key] = child.pack_info()[key]
elif child.winfo_manager() == 'grid':
newwidget.grid()
for key in child.grid_info():
newwidget.grid_info()[key] = child.grid_info()[key]
elif child.winfo_manager() == 'place':
newwidget.place()
for key in child.place_info():
newwidget.place_info()[key] = child.place_info()[key]
There is no way to reparent a widget to a different toplevel. The easiest thing is to make a method that recreates the widgets in a new parent.
Widgets can be stacked on top of each other, though it requires care. You can, for instance, use grid to place two widgets in the same cell, and you can use place to put one widget on top of another .
Using this answer you are able to copy one widget onto another master. Then, you simply forget the previous widget, and it will work as a moved widget.
Example code:
root = tk.Tk()
frame1 = tk.Frame(root, bg='blue', width=200, height=100)
frame1.grid(row=0, column=0, pady=(0, 5))
frame_to_clone = tk.Frame(frame1)
frame_to_clone.place(x=10, y= 15)
tk.Label(frame_to_clone, text='test text').grid(row=0, column=0)
frame2 = tk.Frame(root, bg='green', width=80, height=180)
frame2.grid(row=1, column=0, pady=(0, 5))
# Move frame_to_clone from frame1 to frame2
cloned_frame = clone_widget(frame_to_clone, frame2)
cloned_frame.place(x=10, y=15)
# frame_to_clone.destroy() # Optional destroy or forget of the original widget
root.mainloop()
Gives: