Tkinter widgets not resizing as expected - python

Sorry if it's an easy fix - I'm new to tkinter (and graphical applications in general), and on my way up the learning curve.
I have a simple window in grid layout, with a canvas and a few labels to the right of it. They're positioned and sized correctly - but when I resize the window to the right, they DO expand over, but only about half way (i.e., for every 2 pixels to the right I expand the window, they widgets only expand by 1). I have their respective columns weighted, as well as the parent frame's column weighted. I'm not sure how to remedy this, and haven't found anything similar through Googling. Below I've posted my code, and screenshots of the widgets when the application is launched vs. when I resize.
CODE
from tkinter import *
root = Tk()
root.title("title")
mainframe = Frame(root)
mainframe.grid(column=0, row=0, sticky=(N, W, E, S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)
canvas = Canvas(mainframe, width=800, height=800)
canvas.grid(row=1, column=1, rowspan=3)
info_label = Label(mainframe, text='Info Label', bg='white', relief='solid', borderwidth=1)
info_label.grid(row=1, column=2, columnspan=2)
chatbox = Label(mainframe, text='Welcome to the application.', bg='white', relief='solid', borderwidth=1)
chatbox.grid(row=2, column=2, columnspan=2, sticky=(N,S,E,W))
chat_entry = Entry(mainframe)
chat_entry.grid(row=3, column=2)
chat_send = Button(mainframe, text='Send')
chat_send.grid(row=3, column=3)
mainframe.rowconfigure(1, weight=1)
mainframe.rowconfigure(2, weight=1)
mainframe.columnconfigure(2, weight=1)
root.columnconfigure(1, weight=1)
root.mainloop()
SCREENSHOTS

The only positioning command that resizes according to the window size is pack().
As known, you have the following functions:
pack()
grid()
place()
By the way, I recommend using the place function and use this:
window.resizable(width=False, height=False)
This function prevent from the client the ability to resize the tkinter window.

Related

Tkinter Python - How to delete blank in label

I have an issue with a label on tkinter. I would like to know if it's possible to "occupy space", when I insert long text my label become huge and I have a lot of blank around my text. Is it possible to delete this blank ?
action=customtkinter.CTkLabel(master=frame_right, width=400, height=150, text="", justify=tkinter.LEFT, text_font=("Roboto Medium", -10), fg_color="white")
action.grid(row=4, column=2, padx=15, pady=15, sticky='')
Label from custom tkinter
Here the code to reproduct what happen :
import customtkinter
from tkinter import *
class App(customtkinter.CTk):
WIDTH = 850
HEIGHT = 620
app = customtkinter.CTk() # create CTk window like you do with the Tk window (you can also use normal tkinter.Tk window)
app.geometry(f"{App.WIDTH}x{App.HEIGHT}")#taille de la fenetre graphique
app.grid_rowconfigure(0, weight=1)
app.grid_columnconfigure(1, weight=1)
frame_right = customtkinter.CTkFrame(master=app)
frame_right.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
# configure grid layout (3x7)
frame_right.rowconfigure((0, 1, 2, 3), weight=1)
frame_right.rowconfigure(7, weight=10)
frame_right.columnconfigure((0, 1), weight=1)
frame_right.columnconfigure(2, weight=0)
action=customtkinter.CTkLabel(master=frame_right, width=400, height=150, text="", justify="center", text_font=("Roboto Medium", -10), fg_color="white")
action.grid(row=4, column=2, padx=15, pady=15, sticky="n")
action.configure(text="CustomTkinter is a python UI-library based on Tkinter, which provides new, modern and fully customizable widgets.\nThey are created and used like normal Tkinter widgets and can also be used in combination with normal Tkinter")
app.mainloop()
You've given an explicit width and height to the label, so tkinter is trying to honor that size. Since your text doesn't fill the space, the extra space is going to appear blank.
If you remove width=400, height=150, from where you create the label, the label will be just big enough to fit the text.
The following screenshot shows what I get when I remove the explicit width and height:
I finally resolved my problem, I replaced this
frame_right.columnconfigure((0, 1), weight=1)
frame_right.columnconfigure(2, weight=0)
by this :
frame_right.grid_columnconfigure(0, weight=1)
frame_right.grid_columnconfigure(1, weight=10)

Python tk scrollbar on listbox not working in windows 10

I have python3 tk code that seems to work okay in linux (ubuntu) but bizarely does not work in windows 10. The scrollbar on the listbox doesn't scroll in windows ...
import tkinter as tk
root = tk.Tk()
root.title("My MHT")
root.geometry("500x500")
# create all of the main containers
toppest_frame = tk.Frame(root, bg='thistle3', width=500, height=25, pady=3)
top_frame = tk.Frame(root, bg='cyan', width=500, height=250, pady=3)
bottom_frame = tk.Frame(root, bg='lavender', width=500, height=250, pady=3)
# layout all of the main containers
root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=1)
root.grid_rowconfigure(2, weight=1)
root.grid_columnconfigure(0, weight=1)
toppest_frame.grid(row=0, sticky="nesw")
top_frame.grid(row=1, sticky="nesw")
bottom_frame.grid(row=2, sticky="nesw")
#create scrollbar
sb1 = tk.Scrollbar(top_frame,orient="vertical")
sb1.grid(row=0,column=5)
sb2 = tk.Scrollbar(top_frame,orient="horizontal")
sb2.grid(row=1,columnspan=5)
# create the widgets for the top frame
listBox = tk.Listbox(top_frame, relief="sunken",bd=2,selectmode="single")
# layout the widgets in the top frame
top_frame.grid_rowconfigure(0,weight=1)
top_frame.grid_columnconfigure(0,weight=1)
listBox.grid(row=0,sticky="nesw",columnspan=5)
#populate listbox
listBox.delete(0, "end")
for values in range(100):
listBox.insert("end", values)
#attach scrollbar to listbox
listBox.configure(xscrollcommand=sb1.set)
sb1.configure(command=listBox.yview)
listBox.configure(yscrollcommand=sb2.set)
sb2.configure(command=listBox.xview)
root.mainloop()
Am I doing something wrong?
Many thanks.
I do not know how you got this to work in Linux with tkinter, but anyway you are setting the scrollbar for the wrong axis.
listBox.configure(yscrollcommand=sb1.set) # Was xscrollcommand
sb1.configure(command=listBox.yview)
listBox.configure(xscrollcommand=sb2.set) # Was yscrollcommand
sb2.configure(command=listBox.xview)
Then you also need the scrollbar to expand along its field, with grid you use sticky, if you were using pack then an appropriate combination of fill and side, sometimes expand too:
sb1 = tk.Scrollbar(top_frame,orient="vertical")
sb1.grid(row=0,column=5,sticky='ns') # Expand north to south
sb2 = tk.Scrollbar(top_frame,orient="horizontal")
sb2.grid(row=1,columnspan=5,sticky='ew') # Expand east to west
I also hope you have a good reason to use columnspan=5 and did not get it confused with column. Ideally in this situation, it should be column 1 and 0 for sb1 and sb2 respectively.

How do I align something to the bottom left in Tkinter using either .grid() or .pack()?

I am currently trying to make a game in Tkinter which uses multiple different windows.
However, as I am trying to create the layout of a secondary window, I can't seem to get my Return to Menu button underneath the list box, and aligned to the left. I have tried it using .pack() and .grid() methods, but they don't make sense to me.
I've tried using .pack():
header = Frame(wn).pack()
title = Label(header, text='Single-Player',font=('Arial bold',20),bg=bgcolor).pack(anchor='center')
footer = Frame(wn).pack(side=BOTTOM)
return_to_menu = Button(footer, text='Return to Main Menu',font=('Arial',16),bg=bgcolor,command=lambda: menu()).pack(side=BOTTOM,padx=20,pady=250)
# body frame (left side)
bodyL = Frame(wn).pack(side=LEFT)
#output box
output = Listbox(bodyL, width=50, font=("Arial", 20)).pack(side=LEFT,padx=15)`
And I've tried using .grid():
header = Frame(wn).grid(sticky=N)
title = Label(header, text='Single-Player',font=('Arial bold',20),bg=bgcolor).grid(sticky=N+E+W,row=0,column=0)
footer = Frame(wn).grid(sticky=S)
return_to_menu = Button(footer, text='Return to Main Menu',font=('Arial',16),bg=bgcolor,command=lambda: menu()).grid(sticky=S,padx=20,row=0,column=0)
# body frame (left side)
bodyL = Frame(wn).grid(sticky=W)
#output box
output = Listbox(bodyL, width=50, font=("Arial", 20)).grid(sticky=W,padx=15, )`
However using .grid() doesn't align my title to the center of the screen anymore.
Is there a way to center it more efficiently - I didn't like using padx=450 to get it centered.
What happens with the button and the list box, is the button appears to the left of the list box, instead of on the bottom. I have attempted several other methods, such as incrementing row numbers, but my script doesn't appear to do what I anticipated.
Here is an example of how you can set up the weight of specific columns and row to get widgets to stick to a specific location on the screen.
With the use of grid() we need to use columnconfigure() and rowconfigure() to make this work.
These 2 methods are used to define at what ratio the column or row will expand in relation to the columns or rows around it as the container grows or shrinks.
See below example and let me know if you have any questions:
import tkinter as tk
root = tk.Tk()
for i in range(3):
root.columnconfigure(i, weight=1)
root.rowconfigure(1, weight=1)
tk.Label(root, text='Top left').grid(row=0, column=0, sticky='w')
tk.Label(root, text='Top center').grid(row=0, column=1)
tk.Label(root, text='Top right').grid(row=0, column=2, sticky='e')
tk.Label(root, text='center').grid(row=1, column=1)
tk.Label(root, text='Bottom left').grid(row=2, column=0, sticky='w')
tk.Label(root, text='Bottom center').grid(row=2, column=1)
tk.Label(root, text='Bottom right').grid(row=2, column=2, sticky='e')
root.mainloop()
Example:
Here is another example but this time I have a title label outside of a frame so that we can make it easier to manage the title being centered and then working with all the other content of the frame is separate from the title label.
import tkinter as tk
root = tk.Tk()
root.columnconfigure(0, weight=1)
root.rowconfigure(1, weight=1)
frame = tk.Frame(root)
frame.grid(row=1, column=0, sticky='nsew')
for i in range(3):
frame.columnconfigure(i, weight=1)
frame.rowconfigure(1, weight=1)
tk.Label(root, text='Title centered').grid(row=0, column=0)
tk.Label(frame, text='Top left').grid(row=0, column=0, sticky='w')
tk.Label(frame, text='Top center').grid(row=0, column=1)
tk.Label(frame, text='Top right').grid(row=0, column=2, sticky='e')
tk.Label(frame, text='Center').grid(row=1, column=1)
tk.Label(frame, text='Bottom left').grid(row=2, column=0, sticky='w')
tk.Label(frame, text='Bottom center').grid(row=2, column=1)
tk.Label(frame, text='Bottom right').grid(row=2, column=2, sticky='e')
tk.Label(root, text='Footer centered').grid(row=2, column=0)
root.mainloop()
Example:
To address your problem in the comments you cannot use grid() or any other geometry manager for that matter on the same line you create your container. This will always cause the variable for that frame to return None as the geometry managers return None when called.
See this image as to what happens when you use grid() on the same line you create your container.
Now if you delete the grid() part on the row that your container is created and then write it on the next line as the commented out section of the above images shows it will work as expected. See below image of proper use of grid() for containers.
To address your 2nd question in the comments you can add this line to provide a button at the bottom left.
tk.Button(root, text='Bottom left button').grid(row=3, column=0, sticky='w')
Example:

Is it possible to make 'dynamically' adjustable widgets in Tkinter/ttk

I'm developing very simple GUI for my DB. It shows record's list/tree in DB on left panel and (if user clicks on some record) shows the record on the right panel.
Here some bit of code which creates GUI
from Tkinter import *
import ttk
master = Tk()
reclist = ttk.Treeview(columns=["TIME STAMP","HASH","MESSAGE"])
ysb = ttk.Scrollbar(orient=VERTICAL, command= reclist.yview)
xsb = ttk.Scrollbar(orient=HORIZONTAL, command= reclist.xview)
reclist['yscroll'] = ysb.set
reclist['xscroll'] = xsb.set
reclist.grid(in_=master, row=0, column=0, sticky=NSEW)
ysb.grid(in_=master, row=0, column=1, sticky=NS)
xsb.grid(in_=master, row=1, column=0, sticky=EW)
Comment = Text(master)
Comment.tag_configure("center", justify='center')
ysc = ttk.Scrollbar(orient=VERTICAL, command= Comment.yview)
xsc = ttk.Scrollbar(orient=HORIZONTAL, command= Comment.xview)
Comment.grid(in_=master,row=0,column=2,sticky=W+E+N+S)#, columnspan=5)
ysc.grid(in_=master, row=0, column=3, sticky=NS)
xsc.grid(in_=master, row=1, column=2, sticky=EW)
master.rowconfigure(0, weight=3)
master.columnconfigure(0, weight=3)
master.columnconfigure(2, weight=3)
master.mainloop()
Everything works pretty well, except that two panels are not adjustable. I cannot move border between them to make list of records or record panel bigger or smaller. I'm pretty sure in is possible (for example in gitk you can move the border between the list of commits and a displaied commit). I've search quite a lot with no luck.
What you are looking for is called a "PanedWindow". Both the tkinter and ttk modules have one, and they work almost identically. The general idea is that you create a PanedWindow instance, and then you add two or more widgets to it. The PanedWindow will add a movable slider between each widget. Typically you would use frames, which you can then fill up with other widgets.
Here is an example using the one in Tkinter:
import Tkinter as tk
root = tk.Tk()
pw = tk.PanedWindow()
pw.pack(fill="both", expand=True)
f1 = tk.Frame(width=200, height=200, background="bisque")
f2 = tk.Frame(width=200, height=200, background="pink")
pw.add(f1)
pw.add(f2)
# adding some widgets to the left...
text = tk.Text(f1, height=20, width=20, wrap="none")
ysb = tk.Scrollbar(f1, orient="vertical", command=text.yview)
xsb = tk.Scrollbar(f1, orient="horizontal", command=text.xview)
text.configure(yscrollcommand=ysb.set, xscrollcommand=xsb.set)
f1.grid_rowconfigure(0, weight=1)
f1.grid_columnconfigure(0, weight=1)
xsb.grid(row=1, column=0, sticky="ew")
ysb.grid(row=0, column=1, sticky="ns")
text.grid(row=0, column=0, sticky="nsew")
# and to the right...
b1 = tk.Button(f2, text="Click me!")
s1 = tk.Scale(f2, from_=1, to=20, orient="horizontal")
b1.pack(side="top", fill="x")
s1.pack(side="top", fill="x")
root.mainloop()

Tkinter Button Alignment in Grid

I am attempting to fit two buttons on a grid within a frame, that takes up the entire row, no matter the size of the root frame. So essentially one button takes up half of the row, while the other takes the other half. Here's my code:
self.button_frame = tk.Frame(self)
self.button_frame.pack(fill=tk.X, side=tk.BOTTOM)
self.reset_button = tk.Button(self.button_frame, text='Reset')
self.run_button = tk.Button(self.button_frame, text='Run')
self.reset_button.grid(row=0, column=0)
self.run_button.grid(row=0, column=1)
Not really sure where to go from here. Any suggestions would be greatly appreciated. Thanks!
Use columnconfigure to set the weight of your columns. Then, when the window stretches, so will the columns. Give your buttons W and E sticky values, so that when the cells stretch, so do the buttons.
import Tkinter as tk
root = tk.Tk()
button_frame = tk.Frame(root)
button_frame.pack(fill=tk.X, side=tk.BOTTOM)
reset_button = tk.Button(button_frame, text='Reset')
run_button = tk.Button(button_frame, text='Run')
button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
reset_button.grid(row=0, column=0, sticky=tk.W+tk.E)
run_button.grid(row=0, column=1, sticky=tk.W+tk.E)
root.mainloop()
Result:

Categories