I am new to the Tkinter module. I only have experience with PyQt5. I am playing with a couple widgets in my Frame. They are three buttons, and I am trying to expand their size relative to the size of the window. To do this I am using w.columnconfigure(n, weight=1). This should spread the 3 buttons I have across the window Frame. This is the code I am running. I have tried with the w.columnconfigure before placing the widgets in the grid, and, as seen in the posted code, after the widgets are placed in the grid. I noticed no difference or functionality. Is there a convention? Anyway, appreciate any guidance!
def create_widgets(self):
""" Create three buttons that do nothing. """
self.bttn1 = Button(self, text="I do nothing")
self.bttn2 = Button(self)
self.bttn2.configure(text="Me too!")
self.bttn3 = Button(self)
self.bttn3["text"] = "Same here!"
self.bttnCt = Button(self)
self.bttnCt["text"] = "Total Clicks: 0"
self.bttnCt["command"] = self.update_count
self.bttn1.grid(row=0, column=0, sticky=W+E)
self.bttn2.grid(row=0, column=1, sticky=W+E)
self.bttn3.grid(row=0, column=2, sticky=W+E)
self.bttnCt.grid(row=1, column=1, sticky=W+E)
bttn_list = [self.bttn1, self.bttn2, self.bttn3, self.bttnCt]
for k, i in enumerate(bttn_list):
i.columnconfigure(k, weight=1)
#self.bttn1.columnconfigure(0, weight=1)
#self.bttn2.columnconfigure(1, weight=3)
#self.bttn3.columnconfigure(2, weight=1)
#self.bttnCt.columnconfigure(3, weight=1)
columnconfigure() or rowconfigure() functions are applied to the window or frame, of which the widget is a part of. Here you are applying it on the button itself. Apply it on on its parent basically.
Here is a small example.
import tkinter as tk
app = tk.Tk()
bttn1 = tk.Button(app, text="I do nothing")
bttn2 = tk.Button(app, text='Me too!')
bttn3 = tk.Button(app, text='Same here!')
bttnCt = tk.Button(app, text='Total Clicks: 0')
bttn1.grid(row=0, column=0, sticky="ew")
bttn2.grid(row=0, column=1, sticky="ew")
bttn3.grid(row=0, column=2, sticky="ew")
bttnCt.grid(row=1, column=1, sticky="ew")
bttn_list = [bttn1, bttn2, bttn3, bttnCt]
for i in range(len(bttn_list)):
app.columnconfigure(i, weight=1) ## Not the button, but the parent
app.mainloop()
Related
I want to create a GUI with two frames, one of which must be scrollable. I tried to create a scrollbar using canvas, but following the instructions from several tutorials I came to something strange:
I'm using the .grid method instead of the simple pack, because I want more control over the placement of elements (many in a row). I tried converting these tutorial methods from .pack to .grid, maybe that's why it doesn't work.
import customtkinter
import tkinter
class MyGui:
def __init__(self, app):
self.app = app
self.app.geometry("500x300")
self.app.grid_rowconfigure(0, weight=1)
self.app.grid_columnconfigure((0, 1), weight=1)
self.frame = customtkinter.CTkFrame(self.app)
self.frame.grid(
row=0, column=0, columnspan=3, padx=20, pady=(20, 5), sticky="NSEW"
)
self.canvas = customtkinter.CTkCanvas(self.frame)
self.canvas.grid(row=0, column=0, columnspan=3, sticky="NSEW")
self.scrollbar = customtkinter.CTkScrollbar(
master=self.frame, orientation="vertical", command=self.canvas.yview
)
self.scrollbar.grid(row=0, column=2, sticky="E")
self.canvas.configure(yscrollcommand=self.scrollbar.set)
self.frame_1 = customtkinter.CTkFrame(master=self.canvas)
self.frame_1.grid(
row=0, column=0, columnspan=3, padx=20, pady=(20, 5), sticky="NSEW"
)
self.canvas.create_window((0, 0), window=self.frame_1, anchor="nw")
self.frame_2 = customtkinter.CTkFrame(master=self.app)
self.frame_2.grid(
row=1, column=0, columnspan=3, padx=20, pady=(5, 20), sticky="NSEW"
)
for x in range(100):
customtkinter.CTkButton(self.frame_1, text=f"Button {x}").grid(
row=x, column=0
)
customtkinter.CTkEntry(
master=self.frame_1, placeholder_text=f"Entry {x}"
).grid(row=x, column=1)
customtkinter.CTkEntry(
master=self.frame_1, placeholder_text=f"Entry {x}"
).grid(row=x, column=2)
customtkinter.CTkButton(self.frame_2, text="Lonely button").pack(padx=5, pady=5)
app = customtkinter.CTk()
running = MyGui(app)
app.mainloop()
Also note that beside 'crashed' windows, scrollbar does not change position while scrolling because it takes up all his space and frames does not seem to expanding to fill the window.
I did search for a lot of examples before posting but still can't properly use the tkinter grid.
What I want:
my code:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
b1 = ttk.Button(root, text='b1')
b1.grid(row=0, column=0, sticky=tk.W)
e1 = ttk.Entry(root)
e1.grid(row=0, column=1, sticky=tk.EW)
t = ttk.Treeview(root)
t.grid(row=1, column=0, sticky=tk.NSEW)
scroll = ttk.Scrollbar(root)
scroll.grid(row=1, column=1, sticky=tk.E+tk.NS)
scroll.configure(command=t.yview)
t.configure(yscrollcommand=scroll.set)
root.columnconfigure(0, weight=1)
root.columnconfigure(1, weight=1)
root.rowconfigure(1, weight=1)
root.mainloop()
The quick and simple solution is to define the columnspan of the treeview. This will tell the treeview to spread across 2 columns and allow the entry field to sit next to your button.
On an unrelated note you can use strings for your sticky so you do not have to do things like tk.E+tk.NS. Instead simply use "nse" or whatever directions you need. Make sure thought you are doing them in order of "nsew".
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
b1 = ttk.Button(root, text='b1')
b1.grid(row=0, column=0, sticky="w")
e1 = ttk.Entry(root)
e1.grid(row=0, column=1, sticky="ew")
t = ttk.Treeview(root)
t.grid(row=1, column=0, columnspan=2, sticky="nsew") # columnspan=2 goes here.
scroll = ttk.Scrollbar(root)
scroll.grid(row=1, column=2, sticky="nse") # set this to column=2 so it sits in the correct spot.
scroll.configure(command=t.yview)
t.configure(yscrollcommand=scroll.set)
# root.columnconfigure(0, weight=1) Removing this line fixes the sizing issue with the entry field.
root.columnconfigure(1, weight=1)
root.rowconfigure(1, weight=1)
root.mainloop()
Results:
To fix your issue you mention in the comments you can delete root.columnconfigure(0, weight=1) to get the entry to expand properly.
Using tkinter, I wanted to make an interface containing a few buttons on the left, which would be fairly static and align with the widgets on the right fairly nicely.
On the right, I wanted an Entry widget above a Text widget, both of which would resize accordingly (the Entry widget only on the X axis).
This code accomplishes most of that, except the Text widget does not resize and the Entry widget only resizes to align with the Text widget. Upon trying to column/rowconfigure the root, the top frame resizes awkwardly.
Here's a picture of the tkinter interface from this code:
from tkinter import *
def main():
root = Tk()
root.geometry("300x400")
framet = Frame(root)
frameb = Frame(root)
framet.grid(row=0, column=0, sticky='ew')
frameb.grid(row=1, column=0, sticky='news')
button1 = Button(framet, text='one', width=8)
button1.grid(row=0, column=0)
button2 = Button(frameb, text='two', width=8)
button2.grid(row=1, column=0, sticky='n')
entry1 = Entry(framet)
entry1.grid(row=0, column=1, sticky='ew')
text1 = Text(frameb, highlightbackground='black', highlightthickness=1)
text1.grid(row=1, column=1, sticky='news')
framet.columnconfigure(1, weight=1)
if __name__ == '__main__':
main()
As you can see, the Entry and Text widgets do not resize. How could I accomplish this whilst still having the Buttons remain static, and not moving anything (only resizing)?
Would this work for you? I changed the lines with # comments, I think, I can't really remember what I did I just tryed to get it working, one problem which I'm not happy with though is the entry widget is not the same height as the button, I guess you could manually set its height but..
from tkinter import *
def main():
root = Tk()
root.grid_columnconfigure(1,weight=1) # the text and entry frames column
root.grid_rowconfigure(0,weight=1) # all frames row
buttonframe = Frame(root)
buttonframe.grid(row=0, column=0, sticky="nswe")
entry_text_frame = Frame(root)
entry_text_frame.grid(row=0, column=1, sticky="nswe")
entry_text_frame.grid_columnconfigure(0,weight=1) # the entry and text widgets column
entry_text_frame.grid_rowconfigure(1,weight=1) # the text widgets row
button1 = Button(buttonframe, text='one', width=8)
button1.grid(row=0, column=0, sticky='nswe')
button2 = Button(buttonframe, text='two', width=8)
button2.grid(row=1, column=0, sticky='nswe')
entry1 = Entry(entry_text_frame)
entry1.grid(row=0, column=0, sticky='nswe')
text1 = Text(entry_text_frame, highlightbackground='black', highlightthickness=1)
text1.grid(row=1, column=0, sticky='news')
root.geometry("300x400")
if __name__ == '__main__':
main()
Thanks for taking time to look at this. I've been struggling with this for almost a week and its driving me crazy.
I have a horizontal Paned Window which is supposed to stretch from the bottom of my toolbar to the bottom of my window, but it's sticking only to the bottom of the root window. Eventually I want to have a Treeview widget in the left pane and thumbnails in the right pane.
Can anyone help me to get the Paned Window to stick NSEW? Do I need to put it inside another frame?
I'm using Python 2.7 on Windows 7. (This isn't my whole program, just a sample to demonstrate the problem.)
#!/usr/bin/env python
# coding=utf-8
from Tkinter import *
from ttk import *
class MainWindow:
def null(self):
pass
def __init__(self):
self.root = Tk()
self.root.geometry("700x300")
self.root.resizable(width=TRUE, height=TRUE)
self.root.rowconfigure(0, weight=1)
self.root.columnconfigure(0, weight=1)
self.menubar = Menu(self.root)
File_menu = Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="Pandoras Box", menu=File_menu)
File_menu.add_command(label="Black Hole", command=self.null)
self.root.config(menu=self.menubar)
self.toolbar = Frame(self.root, relief=RAISED)
self.toolbar.grid(row=0, column=0, sticky='NEW')
self.toolbar.grid_columnconfigure(0, weight=1)
self.toolbar.rowconfigure(0, weight=1)
dummy = Button(self.toolbar, text="Tool Button")
dummy.grid(row=0, column=0, sticky='EW')
Find = Label(self.toolbar, text="Search")
Search = Entry(self.toolbar)
Find.grid(row=0, column=5, sticky='E', padx=6)
Search.grid(row=0, column=6, sticky='E', padx=8)
self.info_column = Frame(self.root, relief=RAISED, width=100)
self.info_column.grid(row=0, column=5, rowspan=3, sticky='NSW')
self.info_column.grid_rowconfigure(0, weight=1)
self.info_column.grid_columnconfigure(0, weight=1)
self.rootpane = PanedWindow(self.root, orient=HORIZONTAL)
self.rootpane.grid(row=1, column=0, sticky='NS')
self.rootpane.grid_rowconfigure(0, weight=1)
self.rootpane.grid_columnconfigure(0, weight=1)
self.leftpane = Frame(self.rootpane, relief=RAISED)
self.leftpane.grid(row=0, column=0, sticky='NSEW')
self.rightpane = Frame(self.rootpane, relief=RAISED)
self.rightpane.grid(row=0, column=0, sticky='NSEW')
''' THESE BUTTONS ARE SUPPOSED TO BE INSIDE PANED WINDOW STUCK TO THE TOP!'''
but_left = Button(self.leftpane, text="SHOULD BE IN LEFT PANE UNDER TOOLBAR FRAME")
but_left.grid(row=0, column=0, sticky='NEW')
but_right = Button(self.rightpane, text="SHOULD BE IN RIGHT PANE UNDER TOOLBAR FRAME")
but_right.grid(row=0, column=0, sticky='NEW')
self.rootpane.add(self.leftpane)
self.rootpane.add(self.rightpane)
self.SbarMesg = StringVar()
self.label = Label(self.root, textvariable=self.SbarMesg, font=('arial', 8, 'normal'))
self.SbarMesg.set('Status Bar:')
self.label.grid(row=3, column=0, columnspan=6, sticky='SEW')
self.label.grid_rowconfigure(0, weight=1)
self.label.grid_columnconfigure(0, weight=1)
self.root.mainloop()
a = MainWindow()
Short answer: the space you see between the buttons and the toolbar frame is because you allow the row containing the toolbar to resize, instead of the row containing the PanedWindow... To get what you want, replace:
self.root.rowconfigure(0, weight=1)
with
self.root.rowconfigure(1, weight=1)
Other comments:
Try to avoid wildcard imports. In this case, it makes it difficult to differentiate between tk and ttk widgets
To allow resizing of widgets aligned using grid(), .rowconfigure(..., weight=x) must be called on the widget's parent not the widget itself.
background colors are very useful to debug alignment issues in tkinter.
Code:
import Tkinter as tk
import ttk
class MainWindow:
def __init__(self):
self.root = tk.Tk()
self.root.geometry("700x300")
self.root.resizable(width=tk.TRUE, height=tk.TRUE)
self.root.rowconfigure(1, weight=1)
self.root.columnconfigure(0, weight=1)
self.toolbar = tk.Frame(self.root, relief=tk.RAISED, bg="yellow")
self.toolbar.grid(row=0, column=0, sticky='NEW')
self.toolbar.columnconfigure(0, weight=1)
dummy = ttk.Button(self.toolbar, text="Tool Button")
dummy.grid(row=0, column=0, sticky='EW')
Find = tk.Label(self.toolbar, text="Search")
Search = ttk.Entry(self.toolbar)
Find.grid(row=0, column=5, sticky='E', padx=6)
Search.grid(row=0, column=6, sticky='E', padx=8)
self.info_column = tk.Frame(self.root, relief=tk.RAISED, width=100, bg="orange")
self.info_column.grid(row=0, column=5, rowspan=2, sticky='NSW')
self.rootpane = tk.PanedWindow(self.root, orient=tk.HORIZONTAL, bg="blue")
self.rootpane.grid(row=1, column=0, sticky='NSEW')
self.leftpane = tk.Frame(self.rootpane, bg="pink")
self.rootpane.add(self.leftpane)
self.rightpane = tk.Frame(self.rootpane, bg="red")
self.rootpane.add(self.rightpane)
''' THESE BUTTONS ARE SUPPOSED TO BE INSIDE PANED WINDOW STUCK TO THE TOP!'''
but_left = ttk.Button(self.leftpane, text="SHOULD BE IN LEFT PANE UNDER TOOLBAR FRAME")
but_left.grid(row=0, column=0, sticky='NEW')
but_right = ttk.Button(self.rightpane, text="SHOULD BE IN RIGHT PANE UNDER TOOLBAR FRAME")
but_right.grid(row=0, column=0, sticky='NEW')
self.label = tk.Label(self.root, text="Status:", anchor="w")
self.label.grid(row=3, column=0, columnspan=6, sticky='SEW')
self.root.mainloop()
a = MainWindow()
I need help on this. I'm just started to learn Tkinter and I have some difficulties to do this:
Image: Main window with a new window
Basically, what I want is to do is to create a frame in the main window (root or master) that pop-out initially. This frame will contain labels and buttons; besides, it will be above other labels and buttons. Similar to the image I posted. I tried to achieve this by creating a new window but the new window comes with title, minimize, maximize and close button which it is something I do not want. I want to achieve I similar result like the image I posted. Thank you in advance.
If you do not need a floating window, you can just create a frame and use place to place it in the center of the window.
Here's a basic example:
import tkinter as tk
class Popout(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, background="black", padx=10, pady=10)
title = tk.Label(self, text="How to play", font=("Helvetica", 16), anchor="w",
background="black", foreground="white")
instructions = tk.Label(self, text="The goal of Klondike is to blah blah blah...",
background="black", foreground="white", anchor="w")
cb = tk.Checkbutton(self, text="Do not show again", highlightthickness=0,
background="black", foreground="white")
oneof = tk.Label(self, text="1 of 6", background="black", foreground="white")
close_btn = tk.Button(self, text="Close", background="black", foreground="white")
next_btn = tk.Button(self, text="Next", background="black", foreground="white")
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=1)
title.grid(row=0, column=0, columnspan=2, sticky="ew")
oneof.grid(row=0, column=2, sticky="ne")
instructions.grid(row=1, column=0, columnspan=3, sticky="nsew", pady=10)
cb.grid(row=2, column=0, sticky="w")
close_btn.grid(row=3, column=1, sticky="ew", padx=10)
next_btn.grid(row=3, column=2, sticky="ew")
root = tk.Tk()
root.geometry("600x400")
p = Popout(root)
p.place(relx=.5, rely=.5, anchor="center")
root.mainloop()