Tk grid won't resize properly - python

I'm trying to write a simple ui with Tkinter in python and I cannot get the widgets within a grid to resize. Whenever I resize the main window the entry and button widgets do not adjust at all.
Here is my code:
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master, padding=(3,3,12,12))
self.grid(sticky=N+W+E+S)
self.createWidgets()
def createWidgets(self):
self.dataFileName = StringVar()
self.fileEntry = Entry(self, textvariable=self.dataFileName)
self.fileEntry.grid(row=0, column=0, columnspan=3, sticky=N+S+E+W)
self.loadFileButton = Button(self, text="Load Data", command=self.loadDataClicked)
self.loadFileButton.grid(row=0, column=3, sticky=N+S+E+W)
self.columnconfigure(0, weight=1)
self.columnconfigure(1, weight=1)
self.columnconfigure(2, weight=1)
app = Application()
app.master.title("Sample Application")
app.mainloop()

Add a root window and columnconfigure it so that your Frame widget expands too. That's the problem, you've got an implicit root window if you don't specify one and the frame itself is what's not expanding properly.
root = Tk()
root.columnconfigure(0, weight=1)
app = Application(root)

I use pack for this. In most cases it is sufficient.
But do not mix both!
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack(fill = X, expand =True)
self.createWidgets()
def createWidgets(self):
self.dataFileName = StringVar()
self.fileEntry = Entry(self, textvariable=self.dataFileName)
self.fileEntry.pack(fill = X, expand = True)
self.loadFileButton = Button(self, text="Load Data", )
self.loadFileButton.pack(fill=X, expand = True)

A working example. Note that you have to explicitly set the configure for each column and row used, but columnspan for the button below is a number greater than the number of displayed columns.
## row and column expand
top=tk.Tk()
top.rowconfigure(0, weight=1)
for col in range(5):
top.columnconfigure(col, weight=1)
tk.Label(top, text=str(col)).grid(row=0, column=col, sticky="nsew")
## only expands the columns from columnconfigure from above
top.rowconfigure(1, weight=1)
tk.Button(top, text="button").grid(row=1, column=0, columnspan=10, sticky="nsew")
top.mainloop()

Related

Why doesn't the column width fill the frame using `weight` in tkinter?

I have run in to a diffuctly where despite using the sticky and weight options from the grid and columnconfigure methods respectively, I am unable to make the column expand the entire width of my frame.
I have read through this post which explains things well, however I haven't had any luck. Below is a simplified example of my code, where the desired result can be achieved by uncommenting the lines using the pack method, which I'd like to replicate using the grid method as well.
import tkinter as tk
class myGUI(tk.Frame):
class ScrollableFrame(tk.Frame):
def __init__(self, parent):
# Create scrollbar
self.frame = tk.Frame(parent)
self.canvas = tk.Canvas(self.frame)
self.yscrollbar = tk.Scrollbar(self.canvas, orient='vertical', command=self.canvas.yview)
tk.Frame.__init__(self, self.canvas)
self.canvas.create_window((0, 0), window=self, anchor='nw')
# Configure scrollbar
self.canvas.configure(yscrollcommand=self.yscrollbar.set)
self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion=self.canvas.bbox('all')))
# Pack scrollbar
self.canvas.pack(side='left', fill='both', expand=True)
self.yscrollbar.pack(side='right', fill='y')
# Configure placement
self.pack = self.frame.pack
self.place = self.frame.place
self.grid = self.frame.grid
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.wrap = tk.LabelFrame(parent)
self.myFrame = self.ScrollableFrame(parent)
for i in range(50):
tk.Button(self.myFrame, text='My Button - '+str(i)).pack()
# self.myFrame.pack(fill='both', expand='yes')
# self.wrap.pack(fill='both', expand='yes')
self.myFrame.grid(row=0, column=0, sticky = 'news')
self.wrap.grid(row=1, column=0, sticky = 'news')
parent.columnconfigure(0, weight=1)
parent.columnconfigure(1, weight=1)
parent.rowconfigure(0, weight=1)
parent.rowconfigure(1, weight=1)
if __name__ == "__main__":
root = tk.Tk()
root.geometry('500x500')
root.title('Scrollbar Test')
myGUI(root)
root.mainloop()

Expanding widgets to fill the panel in Tkinter?

I'm trying to create a simple UI in Python/Tkinter with an Entry widget, a Text widget, and two Buttons side-by-side. I'd like all the widgets to expand in width as the window expands, and the Text widget to expand in height as the window expands as well.
I've searched a whole bunch and what always comes up is assigning a non-zero weight in the grid, but I think I'm doing that already; but when I resize, the widgets stay centered in the grid rather than actually expanding to meet the window size.
Here's what I have now; any suggestions?
class EditWindow(Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.grid()
self.subject_box = Entry(self)
self.subject_box.insert(0, "Some text")
self.subject_box.grid(column=0, columnspan=2, row=0, sticky="NSEW")
self.content_box = Text(self)
self.content_box.insert(END, "Other text")
self.content_box.grid(column=0, columnspan=2, row=1, sticky="NSEW")
self.done_button = Button(self)
self.done_button["text"] = "Done (Temporary Change)"
self.done_button["command"] = self.done
self.done_button.grid(column=0, row=2, sticky="NSEW")
self.done_and_save_button = Button(self)
self.done_and_save_button["text"] = "Done (Permanently Save Changes)"
self.done_and_save_button["command"] = self.done_and_save
self.done_and_save_button.grid(column=1, row=2, sticky="NSEW")
Grid.rowconfigure(self.master, 0, weight=1)
Grid.rowconfigure(self.master, 1, weight=1)
Grid.rowconfigure(self.master, 2, weight=1)
Grid.columnconfigure(self.master, 0, weight=1)
def done(self):
self.save_changes = False
self.master.destroy()
def done_and_save(self):
self.save_changes = True
self.master.destroy()
The widgets all exist inside EditWindow, so you need to call rowconfigure and columnconfigure on self, not self.master. This code shouldn't do anything with master except use it as the master for itself. This code should also not call self.pack() or self.grid().
The code which creates the instance of EditWindow needs to be responsible for calling pack, place, or grid. When a widget calls one of the geometry manager commands on itself, it requires that the widget knows how it is being used by the master. This limits reusability and too tightly binds the class to the code that uses the class.
Here's a complete example which has the following changes:
removed self.pack from __init__
removed self.grid() from create_widgets
changed the Grid commands to operate on self rather than self.master
called pack with appropriate options from the same scope that created the instance of EditWindow.
from tkinter import *
class EditWindow(Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.create_widgets()
def create_widgets(self):
self.subject_box = Entry(self)
self.subject_box.insert(0, "Some text")
self.subject_box.grid(column=0, columnspan=2, row=0, sticky="NSEW")
self.content_box = Text(self)
self.content_box.insert(END, "Other text")
self.content_box.grid(column=0, columnspan=2, row=1, sticky="NSEW")
self.done_button = Button(self)
self.done_button["text"] = "Done (Temporary Change)"
self.done_button["command"] = self.done
self.done_button.grid(column=0, row=2, sticky="NSEW")
self.done_and_save_button = Button(self)
self.done_and_save_button["text"] = "Done (Permanently Save Changes)"
self.done_and_save_button["command"] = self.done_and_save
self.done_and_save_button.grid(column=1, row=2, sticky="NSEW")
Grid.rowconfigure(self, 0, weight=1)
Grid.rowconfigure(self, 1, weight=1)
Grid.rowconfigure(self, 2, weight=1)
Grid.columnconfigure(self, 0, weight=1)
def done(self):
self.save_changes = False
self.master.destroy()
def done_and_save(self):
self.save_changes = True
self.master.destroy()
root = Tk()
ew = EditWindow(root)
ew.pack(fill="both", expand=True)
root.mainloop()

Trouble adding new elements inside a new window executed through a button

I made a button inside a class and that calls a define function which creates a new window, but whenever I try to put something inside the window like a Label, nothing appears. What is it am I doing wrong? What am I supposed to call when creating the Label because it seems like I'm not calling the right thing
from tkinter import *
class mainTitle(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
myTitle = Label(self, text="Arithmetic & Geometric Sequence", font=("bold", 15))
myTitle.grid(row=1, column=1, pady=50)
opLabel = Label(self, text="Chooose either Arithmetic & Geometric series to calculate")
opLabel.grid(row=2, column=1, pady=10)
self.ariButton = Button(self, text="Arithmetic Sequence", command=self.ariClick)
self.ariButton.grid(row=3, column=1)
self.geoButton = Button(self, text="Geometric Sequence", command=self.geoClick)
self.geoButton.grid(row=4, column=1, pady=10)
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(5, weight=1)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(2, weight=1)
def ariClick(Frame):
ariWindow = Toplevel()
ariWindow.geometry("300x300")
ariWindow.title("Arithmetic Sequence")
aLbl = Label(Frame, text="a")
aLbl.place(anchor=CENTER) #This is not appearing in the new window
def geoClick(Frame):
geoWindow = Toplevel()
geoWindow.geometry("300x300")
geoWindow.title("Geometric Sequence")
def qProgram(Frame):
root.destroy()
if __name__ == "__main__":
root = Tk()
root.geometry("450x350")
mainTitle(root).grid(sticky="nsew")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
this should work
class mainTitle(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
myTitle = Label(self, text="Arithmetic & Geometric Sequence", font=("bold", 15))
myTitle.grid(row=1, column=1, pady=50)
opLabel = Label(self, text="Chooose either Arithmetic & Geometric series to calculate")
opLabel.grid(row=2, column=1, pady=10)
self.ariButton = Button(self, text="Arithmetic Sequence", command=self.ariClick)
self.ariButton.grid(row=3, column=1)
self.geoButton = Button(self, text="Geometric Sequence", command=self.geoClick)
self.geoButton.grid(row=4, column=1, pady=10)
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(5, weight=1)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(2, weight=1)
def ariClick(Frame):
ariWindow = Toplevel()
ariWindow.geometry("300x300")
ariWindow.title("Arithmetic Sequence")
#i called as parent the toplevel() instance ariwindow
aLbl = Label(ariWindow, text="aqwertyui")
aLbl.place(anchor=CENTER) # This is not appearing in the new window
def geoClick(Frame):
geoWindow = Toplevel()
geoWindow.geometry("300x300")
geoWindow.title("Geometric Sequence")
def qProgram(Frame):
root.destroy()
if __name__ == "__main__":
root = Tk()
root.geometry("450x350")
mainTitle(root).grid(sticky="nsew")
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
vote the answer if it runs.

Resizing Canvas with Scrollbar dynamically by using the layout_manager grid

I built a canvas and I don't know why, I wont make it to resize with the frame.
Either something obvious is missing and by craftig all the stuff inside I lost my mind or something weird happens and I dont get it. Anyway here is my code, hope it can be clearify.
import tkinter as tk
root = tk.Tk()
class my_figure(tk.Frame):
def __init__(self, master,
width=450,height=590):
tk.Frame.__init__(self, master)
self.master = master
self.width=width
self.bind("<Configure>", self.update)
#DownFrame
self.body = tk.Frame(self, width=width,height=height,relief='sunken',bd=2)
self.vscrbar = tk.Scrollbar(self.body)
self.hscrbar = tk.Scrollbar(self.body,orient=tk.HORIZONTAL)
self.Display = tk.Canvas(self.body, width=width,height=height,
background='#f0f0f0',highlightthickness=0,
yscrollcommand=self.vscrbar.set,
xscrollcommand=self.hscrbar.set)
self.vscrbar.config(command=self.Display.yview)
self.hscrbar.config(command=self.Display.xview)
self.body.grid(column=0,row=1, sticky='nswe')
self.vscrbar.grid(column=1,sticky='ns')
self.hscrbar.grid(row=1,sticky='we')
self.Display.grid(column=0,row=0,
sticky='nswe')
self.grid_rowconfigure(1, weight=1)
self.columnconfigure(0, weight=1)
def update(self, event):
print(event.widget.winfo_width())
## self.Header.config(width=event.width)
## self.Button.config(width=event.width)
## self.body.config(width=event.width)
## self.Display.config(width=event.width)
figure = my_figure(root)
figure.grid(column=0, row=0)
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0,weight=1)
root.mainloop()
You used nested parent container.Your my_figure is a widget inherit from Frame.And there are also a Frame widget in your my_figure.You need to set columnconfigure and rowconfigure for both of them.
Also need to use sticky="nwes" for your figure.
Though it could work normally,pack manager would be the best choice.
Code:
import tkinter as tk
root = tk.Tk()
class my_figure(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
# self["bd"] = 10
self.bind("<Configure>", self.update)
# DownFrame
self.body = tk.Frame(self, relief='sunken')
for i in range(self.body.grid_size()[1] + 1):
self.body.grid_rowconfigure(i, weight=1)
for i in range(self.body.grid_size()[0] + 1):
self.body.grid_columnconfigure(i, weight=1)
for i in range(self.grid_size()[1] + 1):
self.grid_rowconfigure(i, weight=1)
for i in range(self.grid_size()[0] + 1):
self.grid_columnconfigure(i, weight=1)
self.vscrbar = tk.Scrollbar(self.body)
self.hscrbar = tk.Scrollbar(self.body, orient=tk.HORIZONTAL)
self.Display = tk.Canvas(self.body,
background='#f0f0f0', highlightthickness=0,
yscrollcommand=self.vscrbar.set,
xscrollcommand=self.hscrbar.set)
self.vscrbar.config(command=self.Display.yview)
self.hscrbar.config(command=self.Display.xview)
self.body.grid(column=0, row=0, sticky='nswe')
self.vscrbar.grid(row=0, column=1, sticky='ns')
self.hscrbar.grid(row=1, column=0, sticky='we')
self.Display.grid(column=0, row=0,
sticky='nswe')
def update(self, event):
print(event.widget.winfo_width())
## self.Header.config(width=event.width)
## self.Button.config(width=event.width)
## self.body.config(width=event.width)
## self.Display.config(width=event.width)
figure = my_figure(root)
figure.grid(column=0, row=0, sticky="nwes")
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0,weight=1)
root.mainloop()

Resize button in Tkinter GUI Python

I've created a simple GUI application with Tkinter.
I have two questions about this code:
import tkinter as tk
from tkinter import ttk, Grid, Frame, N, S, W, E, StringVar, Label, Entry, RAISED, Button, Checkbutton, Scrollbar
class mainApp(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.scan_button = Button(self.parent, text="Scan", command=self.scan_wifi)
self.forget_button = Button(self.parent, text="Forget", command=self.forget_wifi)
self.reboot_button = Button(self.parent, text="Reboot", command=self.reboot)
frame=Frame(self.parent)
Grid.rowconfigure(self.parent, 0, weight=1)
Grid.columnconfigure(self.parent, 0, weight=1)
frame.grid(row=0, column=0, sticky=N+S+E+W)
grid=Frame(self.parent)
grid.grid(sticky=N+S+E+W, column=0, row=7, columnspan=2)
Grid.rowconfigure(self.parent, 7, weight=1)
Grid.columnconfigure(self.parent, 0, weight=1)
headings=('Name', 'Address', 'Quality', 'Channel', 'Signal Level', 'Encryption')
row=[]
rows=[]
self.table = ttk.Treeview(show="headings", selectmode="browse")
self.table["columns"]=headings
self.table["displaycolumns"]=headings
for head in headings:
self.table.heading(head, text=head, anchor=tk.CENTER)
self.table.column(head, width=30, anchor=tk.CENTER)
self.scrolltable = tk.Scrollbar(command=self.table.yview)
self.table.configure(yscrollcommand=self.scrolltable.set)
self.scrolltable.grid(row=1, column=100, sticky=N+S)
for row in rows:
self.table.insert('', tk.END, values=tuple(row))
self.table.bind('<ButtonRelease-1>', self.OnRelease)
self.table.grid(row=0, rowspan=14, columnspan = 21, sticky=N+S+E+W)
self.scan_button.grid(row=15, column = 1, columnspan = 1, sticky=N+S+E+W)
self.forget_button.grid(row=15, column = 0, columnspan = 1 , sticky=N+S+E+W)
self.reboot_button.grid(row=15, column = 3, columnspan = 1 , sticky=N+S+E+W)
def OnRelease(self, event):
pass
def scan_wifi(self):
pass
def forget_wifi(self):
pass
def reboot(self):
pass
root=tk.Tk()
app = mainApp(root)
root.mainloop()
1) How I can move the button on the top of the window?
2) Why, if I resize the window, the button "Forget" becomes bigger than other buttons? How I can make all buttons identical size?
Because you have called columnconfigure(0, weight=1) only, therefore only the Forget button will be resized when the window is resized.
To move the buttons to the top of the window, you need to rearrange the buttons to row=0 and the Treeview to row=1. Below is modified code based on yours:
import tkinter as tk
from tkinter import ttk
class mainApp(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.parent = parent
# buttons
self.forget_button = tk.Button(self.parent, text='Forget', command=self.forget_wifi)
self.scan_button = tk.Button(self.parent, text='Scan', command=self.scan_wifi)
self.reboot_button = tk.Button(self.parent, text='Reboot', command=self.reboot)
self.forget_button.grid(row=0, column=0, sticky='nsew')
self.scan_button.grid(row=0, column=1, sticky='nsew')
self.reboot_button.grid(row=0, column=2, sticky='nsew')
# make the 3 buttons same width
for i in range(3):
self.parent.columnconfigure(i, weight=1)
# make the treeview and the scrollbar to fill the remaining space
self.parent.rowconfigure(1, weight=1)
# treeview and scrollbar
frame = tk.Frame(self.parent)
frame.grid(row=1, column=0, columnspan=3, sticky='nsew')
headings=('Name', 'Address', 'Quality', 'Channel', 'Signal Level', 'Encryption')
self.table = ttk.Treeview(frame, show='headings', selectmode='browse')
self.table['columns'] = headings
self.table['displaycolumns'] = headings
for head in headings:
self.table.heading(head, text=head, anchor=tk.CENTER)
self.table.column(head, width=30, anchor=tk.CENTER)
self.scrolltable = tk.Scrollbar(frame, command=self.table.yview)
self.table.configure(yscrollcommand=self.scrolltable.set)
self.table.pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
self.scrolltable.pack(side=tk.RIGHT, fill=tk.Y)
self.table.bind('<ButtonRelease-1>', self.OnRelease)
def OnRelease(self, event):
pass
def scan_wifi(self):
pass
def forget_wifi(self):
pass
def reboot(self):
pass
root=tk.Tk()
app = mainApp(root)
root.mainloop()

Categories