How to do that the 'label' and the 'text' widgets fill all the space when 'root' is being resized?
I'd like to use the 'grid' method if it's possible.
from tkinter import *
root = Tk()
root.resizable(width = True, height = True)
label = Label(root, text = "Text")
label.grid()
text = Text(root)
text.grid()
root.mainloop()
It doesn't work when I try to use in a class.
Application.py
from tkinter import *
import menu
import workPlace
class Application(Frame):
def __init__(self, boss = None):
Frame.__init__(self)
self.master.title("Title")
self.master.grid_columnconfigure(0, weight = 1)
self.master.grid_rowconfigure(1, weight = 1)
self.master.resizable(width = True, height = True)
self.menu = menu.MenuBar(self)
self.menu.grid(sticky = W)
self.workPlace = workPlace.WorkPlace(self)
self.workPlace.grid(sticky = "NEWS")
if __name__ == "__main__":
Application().mainloop()
workPlace.py
from tkinter import *
import tkinter.scrolledtext as scr
class WorkPlace(Frame):
def __init__(self, boss = None):
Frame.__init__(self)
self.scrText = scr.ScrolledText(self)
self.scrText.grid()
self.label = Label(self,text = "Label")
self.label.grid()
menu.py
from tkinter import *
class MenuBar(Frame):
def __init__(self, boss = None):
Frame.__init__(self)
fileMenu = Menubutton(self, text = 'File')
fileMenu.grid(row = 0, column = 0)
me1 = Menu(fileMenu)
fileMenu.configure(menu = me1)
findMenu = Menubutton(self, text = 'Find')
findMenu.grid(row = 0, column = 1)
me1 = Menu(findMenu)
findMenu.configure(menu = me1)
optionMenu = Menubutton(self, text = 'Option')
optionMenu.grid(row = 0, column = 2)
me1 = Menu(optionMenu)
optionMenu.configure(menu = me1)
Two steps are required.
Call grid_rowconfigure and grid_columnconfigure to set the weight of each of the grid's rows and columns. Rows and columns with a weight of zero don't stretch at all during a resize. This is the default behavior.
When calling grid on your widgets, specify the sticky parameter so the widgets stretch whenever their row or column stretches.
from tkinter import *
root = Tk()
root.grid_columnconfigure(0, weight=1)
#uncomment this line if you want the Label widget to stretch vertically.
#or leave it as is if you only want the Text widget to stretch.
#root.grid_rowconfigure(0, weight=1)
root.grid_rowconfigure(1, weight=1)
root.resizable(width = True, height = True)
label = Label(root, text = "Text")
label.grid(sticky="NEWS")
text = Text(root)
text.grid(sticky="NEWS")
root.mainloop()
In the specific case of your WorkPlace object, you need to configure both the root object and the WorkPlace object, and you need to specify stickiness for the WorkPlace object and its child objects.
from tkinter import *
import tkinter.scrolledtext as scr
class WorkPlace(Frame):
def __init__(self, boss = None):
Frame.__init__(self)
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.scrText = scr.ScrolledText(self)
self.scrText.grid(sticky="NEWS")
self.label = Label(self,text = "Label")
self.label.grid()
If you are okay with using pack instead of grid, you can do
from tkinter import *
root = Tk()
root.resizable(width = True, height = True)
label = Label(root, text = "Text")
label.pack(fill=X)
text = Text(root)
text.pack(fill=BOTH, expand=True)
root.mainloop()
Related
I tried to make height of rows in a tree view taller by using ttk.Style.configure method. But, this makes other buttons invisible why does this happen? And how can I fix this?
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('My Awesome App')
self.geometry('300x300')
self.b1 = tk.Button(self, text='b1')
self.tree = ttk.Treeview(self)
self.b2 = tk.Button(self, text='b2')
style = ttk.Style(self)
style.configure('Treeview', rowheight=120) # this line makes app.b1, app.b2 invisible
self.rowconfigure(0, weight=1)
self.rowconfigure(1, weight=1)
self.rowconfigure(2, weight=1)
self.columnconfigure(0, weight=1)
self.b1.grid(row=0, column=0)
self.tree.grid(row=1, column=0)
self.b2.grid(row=2, column=0)
if __name__ == "__main__":
app = App()
app.mainloop()
In my experience place option gives move flexibility than grid. Here is an example which fixes the problem.
Divide your workspace into frames and put widgets into frames.
Pack widgets inside frame
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('My Awesome App')
self.geometry('300x300')
frame1 = tk.Frame(self, height = 50)
frame2 = tk.Frame(self, height = 200)
frame3 = tk.Frame(self, height = 50)
frame1.place(relwidth = 1, relheight = 0.1, relx = 0, rely = 0)
frame2.place(relwidth = 1, relheight = 0.8, relx = 0, rely = 0.1)
frame3.place(relwidth = 1, relheight = 0.1, relx = 0, rely = 0.9)
self.b1 = tk.Button(frame1, text='b1')
self.tree = ttk.Treeview(frame2)
self.b2 = tk.Button(frame3, text='b2')
style = ttk.Style(self)
style.configure('Treeview', rowheight=120) # this line makes app.b1, app.b2 invisible
self.b1.pack()
self.tree.pack()
self.b2.pack()
if __name__ == "__main__":
app = App()
app.mainloop()
It seems that tk.Treeview does not work well with geometry manager when it get size over master frame. So I end up make a method which recalculates column width and tree height based on the size of master and resize Treeview. Also, It needs to pack scrollbar first to prevent scrollbar from being hidden.
example:
class Treeview(ttk.Treeview):
def __init__(self, container, columns, *args, **kwargs):
super(Treeview, self).__init__(container, columns=columns, *args, **kwargs)
self.columns = columns
for column in self.columns:
self.heading(column, text=column, anchor=tk.W)
self.column(column, anchor=tk.CENTER)
def update_man(self): # call this method when treeview get update
super(Treeview, self).update()
mw, mh = self.master.winfo_width(), self.master.winfo_height()
style = ttk.Style(self)
row_height = style.lookup(self['style'], 'rowheight')
ac = 1 if 'tree' in list([str(x) for x in self['show']]) else 0
col_width = int(mw / (len(self.columns) + ac)) + 1
for cn in range(len(self.columns)+1):
self.column(f'#{cn}', width=col_width)
if type(row_height) == 'int':
row_view_height = int(mh / row_height)
if row_view_height < self['height']:
self['height'] = row_view_height
I have this reproducible code, and I cannot understand why when I set the width value to 100 in the self.display_tcm_18 variable, it still does not increase its width. This self.display_tcm_18 lies within the self.xf Frame, which I set to a width value of 300 (wide enough to host a Label widget of 100). I don't know what I am missing in the Logic of building this GUI with tkinter. Does anyone could give me some hint?
import Tkinter
from Tkinter import *
import tkFileDialog
from tkFileDialog import askopenfilename
from tkFileDialog import askdirectory
class Window(Frame):
def __init__(self, master = None):
self.master = master
path = "logo.gif"
self.image = Tkinter.PhotoImage(file=path)
self.f = Frame(master, width=300, height =70)
self.sf = Frame(master, width=300, height=70)
self.xf = Frame(self.f,width = 300, relief=GROOVE, borderwidth = 2)
self.file_name_18 = ''
self.var = IntVar()
def browse_button():
filename = askopenfilename(filetypes = (("GEOTIFF Files", "*.tif"),))
self.file_name = filename
self.display.config(text = filename)
print(self.file_name)
self.Logo = Label(self.master, image = self.image).pack(side=TOP, padx=5)
self.open_tcm_button = Button(self.xf, text = "Open..", command = browse_button).pack(side=LEFT, padx = 5, pady = 10)
self.display_tcm_18 = Label(self.xf, width = 100, bg = "white", textvariable = self.file_name_18, relief = SUNKEN, anchor = W)
self.display_tcm_18.pack(side=LEFT)
self.tcm18_label = Label(self.f, text = "Tree Cover Mask 2018 ").place(relx=0.06, rely=0.125,anchor=W)
self.xf.place(relx=0.01, rely=0.125, anchor=NW)
self.f.pack(side=TOP)
root = Tk()
root.geometry("600x400")
app = Window(root)
root.mainloop()
I am making a maze where the user enters the dimensions and can then click on a button to change the colour of that button to black. What i eventually want is to be making an ai which will try to navigate the maze the user created with the black rectangle the ai not being allowed to go on.
The problem is i dont know how to change the properties of the button clicked as due to a nested loop being used for creation they all have the same name.
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.frame1 = tk.LabelFrame(self, text="entering diemsions", width=300, height=130, bd=5)
self.frame1.grid(row=0, column=0, columnspan=3, padx=8)
self.frame2 = tk.LabelFrame(self, text="creating maze", width=300, height=130, bd=5)
self.frame2.grid(row=1, column=0, columnspan=3, padx=8)
self.create_GUI()
def create_GUI(self):
self.width_lbl = Label(self.frame1, text = "width:")
self.width_lbl.grid(row = 1 , column = 1)
self.width_txt = Entry(self.frame1)
self.width_txt.grid(row = 1, column = 2)
self.getdimensions_btn = Button(self.frame1, text = "enter dimensions",command = lambda:self.createmaze())
self.getdimensions_btn.grid(row = 1 , column = 3)
self.height_lbl = Label(self.frame1, text = "height:")
self.height_lbl.grid(row = 1 , column = 4)
self.height_txt = Entry(self.frame1)
self.height_txt.grid(row = 1, column = 5)
def createmaze(self):
width = int(self.width_txt.get())
height = int(self.height_txt.get())
for widthcount in range (width):
for heightcount in range(height):
self.maze_btn = Button(self.frame2, text = "",width = 4, height = 2)
self.maze_btn.grid(row = heightcount , column = widthcount)
self.maze_btn.bind("<Button-1>", self.disablebtn)
def disablebtn(self,event):
grid_info = event.widget.grid_info()
col = grid_info["column"]
col = int(col)
row = grid_info["row"]
row = int(row)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()
I am trying to make an entry widget display beneath a Label using the .grid() function; however, it is simply not showing up. Here is my code:
#demonstrates how to use a class with Tkinter
from Tkinter import *
import tkMessageBox
class Application(Frame):
def __init__(self, master):
""" Initializes the Frame"""
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
self.previous_trans = Text(width = 100, height = 5, wrap = WORD)
self.previous_trans.grid(row = 0, column = 0, columnspan = 2)
self.items = Text(width = 50, height = 16, wrap = WORD)
self.items.grid(row = 1, column = 1, rowspan = 14, sticky = E)
self.additem = Label(text = "Add Item")
self.additem.grid(row = 1)
self.myentry = Entry(self)
self.myentry.grid(row = 2)
root = Tk();
root.title("Work In Progress")
app = Application(root)
root.mainloop();
The reason is because:
you don't specify a row or column for app, so it defaults to 0,0
you don't specify a parent for self.previous_trans so it defaults to the root window -- the same as for the application frame
you explicitly put self.previous_trans in row zero, column zero, which overwrites the label
You need to be giving an explicit parent of self to all of the widgets inside of Application:
self.previous_trans = Text(self, ...)
self.items = Text(self, ...)
self.additem = Label(self, ...)
self.myentry = Entry(self, ...)
I'm trying to make a Tkinter window class that contains a canvas with a scrollbar based on the tkinter Toplevel class. When I run my code I don't receive any errors but the scrollbar in the window is disabled. The Frame or canvas that has the information wont stretch with the window when I stretch it manually after the program is running. Here is the bugged code:
class new_window(Toplevel):
def __init__(self,master):
Toplevel.__init__(self,master)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
s = Scrollbar(self, orient = VERTICAL)
s.grid(row = 0, column = 1, sticky = NS)
self.can = Canvas(self, yscrollcommand=s.set)
self.can.grid(row = 0, column = 0, sticky = N+S+E+W)
self.win = Frame(self.can)
self.can.create_window(0,0, window = self.win, anchor = NW)
s.config(command = self.can.yview)
size = (self.win.winfo_reqwidth(), self.win.winfo_reqheight())
self.can.config(scrollregion="0 0 %s %s" % size)
self.win.update_idletasks()
self.ca.configure(scrollregion = (1,1,win.winfo_width(),win.winfo_height()))
def create(self):
for i in range (100):
i = Label(self.win, text = str(i))
i.grid()
root = Tk()
win = new_window(root)
win.create()
root.mainloop()
It was working fine before I decided to implement classes:
from Tkinter import *
root = Tk()
window = Toplevel()
window.grid_rowconfigure(0, weight=1)
window.grid_columnconfigure(0, weight=1)
s = Scrollbar(window, orient = VERTICAL)
s.grid(row = 6, column = 1, sticky = NS)
can = Canvas(window, width = 1600, height = 700, yscrollcommand=s.set)
can.grid(row = 6, column = 0, sticky = NSEW)
win = Frame(can)
can.create_window(0,0, window = win, anchor = NW)
s.config(command = can.yview)
for i in range(100):
lbl = Label(win, text = str(i))
lbl.grid()
win.update_idletasks()
can.configure(scrollregion = (1,1,win.winfo_width(),win.winfo_height()))
root.mainloop()
Im not sure where I went wrong in the transition, any help would be greatly appreciated.
I think the issue is coming from here:
self.win.update_idletasks()
self.ca.configure(scrollregion = (1,1,win.winfo_width(),win.winfo_height()))
This is inside the initialization function, when it should be updating after the create function is called. There's still probably a more efficient way to structure this, but this should work in the meantime:
from Tkinter import *
class new_window(Toplevel):
def __init__(self,master):
Toplevel.__init__(self,master)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
s = Scrollbar(self, orient = VERTICAL)
s.grid(row = 0, column = 1, sticky = NS)
self.can = Canvas(self, yscrollcommand=s.set)
self.can.grid(row = 0, column = 0, sticky = N+S+E+W)
self.win = Frame(self.can)
self.can.create_window(0,0, window = self.win, anchor = NW)
s.config(command = self.can.yview)
size = (self.win.winfo_reqwidth(), self.win.winfo_reqheight())
self.can.config(scrollregion="0 0 %s %s" % size)
def create(self):
for i in range (100):
i = Label(self.win, text = str(i))
i.grid()
self.win.update_idletasks()
self.can.configure(scrollregion = (1,1,self.win.winfo_width(),self.win.winfo_height()))
root = Tk()
win = new_window(root)
win.create()
root.mainloop()