Tkinter Designer

Tkinter widgets reference

Every example below is produced by the same code generator the designer uses when you export, so it's what you'd actually get rather than a paraphrase. Positions come from place(), which is how the designer lays windows out.

Text and input

The widgets almost every window needs.

Label Lb

tk.Label · CustomTkinter: CTkLabel · ttkbootstrap: ttkb.Label

Static text, or text your code updates as things happen: a result, a status line, a field caption. The most common way to show output in a tkinter app.

Worth knowing: Change the text at runtime with self.label1.configure(text="…"). Use .configure() rather than .config(), because CustomTkinter rejects the latter.

self.label1 = tk.Label(root, text="Label")
self.label1.place(x=20, y=20, width=90, height=26)

Button Bt

tk.Button · CustomTkinter: CTkButton · ttkbootstrap: ttkb.Button

A clickable control. Point its command at a method and that method runs on click; the designer generates an empty on_<name> handler for you to fill in.

Worth knowing: To pass an argument, use a lambda: command=lambda: self.on_press("7"). Without it, Python would call the function immediately instead of on click.

self.button1 = tk.Button(root, text="Button", command=self.on_button1)
self.button1.place(x=20, y=20, width=96, height=32)

Entry En

tk.Entry · CustomTkinter: CTkEntry · ttkbootstrap: ttkb.Entry

A single-line text field. Read what was typed with .get(), clear it with .delete(0, "end"), and set show="*" to mask a password.

Worth knowing: Entry always returns a string. Convert with int() or float() inside a try/except, or a stray letter will crash your handler.

self.entry1 = tk.Entry(root)
self.entry1.place(x=20, y=20, width=150, height=28)

Text Tx

tk.Text · CustomTkinter: CTkTextbox · ttkbootstrap: no ttk equivalent, stays tk.Text

A multi-line editor for notes, logs or longer input. Insert with .insert("end", "…") and read it back with .get("1.0", "end").

Worth knowing: Text indices are "line.column" with lines counted from 1, so the very start is "1.0", not 0.

self.text1 = tk.Text(root)
self.text1.place(x=20, y=20, width=220, height=110)

Image Im

tk.Label · CustomTkinter: CTkLabel holding a CTkImage · ttkbootstrap: ttkb.Label

A picture from a file. There is no image widget as such: tkinter draws pictures by giving a Label an image, so that is what the designer generates. Point it at a filename and the export opens it, scales it to the box you drew, and keeps it on the instance.

Worth knowing: Images vanish if you only hold them locally. A PhotoImage referenced by nothing but the widget is garbage-collected and the label goes blank with no error, which is why the generated code assigns it to self. Scaling and JPEG support come from Pillow (pip install pillow); PNG and GIF at their original size need nothing extra.

# Kept on self, or Python garbage-collects it and the image goes blank.
self.image1_image = ImageTk.PhotoImage(Image.open("image.png").resize((160, 120)))
self.image1 = tk.Label(root, image=self.image1_image)
self.image1.place(x=20, y=20, width=160, height=120)

Choices

Ways to let someone pick something.

Checkbutton Ck

tk.Checkbutton · CustomTkinter: CTkCheckBox · ttkbootstrap: ttkb.Checkbutton

An independent on/off toggle. Each one gets its own IntVar, so read its state with self.checkbutton1_var.get(), which is 1 when ticked and 0 when not.

self.checkbutton1 = tk.Checkbutton(root, text="Checkbutton", variable=self.checkbutton1_var)
self.checkbutton1.place(x=20, y=20, width=120, height=26)

Radiobutton Rb

tk.Radiobutton · CustomTkinter: CTkRadioButton · ttkbootstrap: ttkb.Radiobutton

One choice from several. Radiobuttons sharing a group name share a variable, so only one can be selected; read the winner with self.<group>_var.get().

Worth knowing: Give every option in a group the same group name and a distinct value, or they will not behave as a set.

self.radiobutton1 = tk.Radiobutton(root, text="Option", variable=self.choice_var, value="1")
self.radiobutton1.place(x=20, y=20, width=110, height=26)

Switch Sw

tk.Checkbutton · CustomTkinter: CTkSwitch, the real thing · ttkbootstrap: ttkb.Checkbutton with the round-toggle style

An on/off toggle. Only CustomTkinter has a genuine switch widget; ttkbootstrap draws a Checkbutton as one given the round-toggle bootstyle, and classic tkinter falls back to an ordinary checkbox. The variable is an IntVar either way, so the code that reads it does not change with the toolkit.

self.switch1 = tk.Checkbutton(root, text="Enabled", variable=self.switch1_var)
self.switch1.place(x=20, y=20, width=120, height=28)

Combobox Cb

ttk.Combobox · CustomTkinter: CTkComboBox · ttkbootstrap: ttkb.Combobox

A dropdown of preset values that can also accept typing. Good when there is a usual set of answers but you want to allow others.

self.combobox1 = ttk.Combobox(root, values=["Option 1", "Option 2", "Option 3"])
self.combobox1.place(x=20, y=20, width=160, height=28)

OptionMenu Om

tk.OptionMenu · CustomTkinter: CTkOptionMenu · ttkbootstrap: ttkb.OptionMenu

A dropdown limited to the options you supply. Simpler than a Combobox when free text would not make sense.

self.optionmenu1 = tk.OptionMenu(root, self.optionmenu1_var, "Option 1", "Option 2", "Option 3")
self.optionmenu1.place(x=20, y=20, width=150, height=28)

Spinbox Sp

tk.Spinbox · CustomTkinter: no equivalent, stays tk.Spinbox · ttkbootstrap: ttkb.Spinbox

A number field with up and down arrows, bounded by from_ and to. Useful for quantities and small ranges where a slider would be imprecise.

self.spinbox1 = tk.Spinbox(root, from_=0, to=100)
self.spinbox1.place(x=20, y=20, width=150, height=28)

Listbox Ls

tk.Listbox · CustomTkinter: no equivalent, stays tk.Listbox · ttkbootstrap: no ttk equivalent, stays tk.Listbox

A scrollable list of rows. Add with .insert("end", "…"), find the selection with .curselection(), and remove with .delete(index).

Worth knowing: .curselection() returns a tuple, which is empty when nothing is selected, so check it before indexing, or you will hit an IndexError.

self.listbox1 = tk.Listbox(root)
self.listbox1.insert("end", "Item 1")
self.listbox1.insert("end", "Item 2")
self.listbox1.insert("end", "Item 3")
self.listbox1.place(x=20, y=20, width=160, height=110)

Date picker Dt

tkcalendar.DateEntry · CustomTkinter: no equivalent, stays tkcalendar.DateEntry · ttkbootstrap: ttkb.DateEntry, built in and themed

A text field showing a date, with a calendar that drops down when you click it. tkinter has nothing of the sort, so on classic tkinter and CustomTkinter this is tkcalendar. Read the value with .get_date(), which hands back a real datetime.date rather than a string.

Worth knowing: ttkbootstrap is the exception: it ships its own DateEntry, so exporting for that toolkit needs no extra package. The two spell the format differently — tkcalendar takes date_pattern="yyyy-mm-dd", ttkbootstrap takes a strftime dateformat — and the designer converts between them so switching toolkit keeps your format.

self.dateentry1 = DateEntry(root, date_pattern="yyyy-mm-dd")
self.dateentry1.place(x=20, y=20, width=130, height=28)

Containers and layout

Widgets that hold other widgets, or divide a window up.

Frame Fr

tk.Frame · CustomTkinter: CTkFrame · ttkbootstrap: ttkb.Frame

An invisible box that groups other widgets. Drop widgets inside one in the designer and they become its children, so moving the frame moves the group.

self.frame1 = tk.Frame(root, relief="groove", bd=2)
self.frame1.place(x=20, y=20, width=180, height=130)

LabelFrame LF

tk.LabelFrame · CustomTkinter: composed from CTkFrame + CTkLabel · ttkbootstrap: ttkb.Labelframe

A frame with a caption in its border, the usual way to label a related set of controls, like "Address" or "Options".

self.labelframe1 = tk.LabelFrame(root, text="Group", relief="groove")
self.labelframe1.place(x=20, y=20, width=200, height=140)

Notebook (tabs) Nb

ttk.Notebook · CustomTkinter: CTkTabview · ttkbootstrap: ttkb.Notebook

Tabbed pages in one window. Each tab holds its own widgets, so a settings screen can be split up without opening more windows.

Worth knowing: In the designer, click a tab to switch which page you are editing; widgets are added to the tab that is showing.

self.notebook1 = ttk.Notebook(root)
self.notebook1_tab1 = ttk.Frame(self.notebook1)
self.notebook1.add(self.notebook1_tab1, text="Tab 1")
self.notebook1_tab2 = ttk.Frame(self.notebook1)
self.notebook1.add(self.notebook1_tab2, text="Tab 2")
self.notebook1.place(x=20, y=20, width=260, height=170)

Scrollable frame Sf

a generated ScrollableFrame class · CustomTkinter: the same generated class, built from CTk widgets · ttkbootstrap: ttkb.ScrolledFrame

A container whose contents can be taller than the space it occupies. Drop widgets inside it as you would any frame and set how tall the scrolling content is; the export wires the canvas, the inner frame and the scrollbar together. Its contents live in `.body` on every toolkit, so code that adds rows at runtime keeps working if you switch.

Worth knowing: CustomTkinter has a CTkScrollableFrame and the designer deliberately does not use it. It works out its scroll region from packed or gridded children, and everything here is positioned with place(), which never grows a parent — so it reports a content height of one pixel and never scrolls. The generated class takes the height you give it instead.

self.scrollframe1 = ScrollableFrame(root)
self.scrollframe1.place(x=20, y=20, width=240, height=180)

Separator Se

ttk.Separator · CustomTkinter: composed from a thin CTkFrame · ttkbootstrap: ttkb.Separator

A horizontal or vertical rule for dividing a window into visual sections. Purely decorative, but it does a lot for a busy form.

self.separator1 = ttk.Separator(root, orient="horizontal")
self.separator1.place(x=20, y=20, width=200, height=10)

Canvas Cv

tk.Canvas · CustomTkinter: CTkCanvas · ttkbootstrap: no ttk equivalent, stays tk.Canvas

A drawing surface for lines, shapes, images and charts. Anything tkinter can draw that is not a standard widget happens here, in your own code.

self.canvas1 = tk.Canvas(root, bg="white", highlightthickness=1, highlightbackground="#828282")
self.canvas1.place(x=20, y=20, width=200, height=150)

Values and feedback

Showing a number, a range, or a table of rows.

Scale (slider) Sc

tk.Scale · CustomTkinter: CTkSlider · ttkbootstrap: ttkb.Scale

A draggable slider across a range set by from_ and to. Good for volume, zoom or any value where the rough position matters more than the exact number.

self.scale1 = tk.Scale(root, from_=0, to=100, orient="horizontal")
self.scale1.place(x=20, y=20, width=180, height=48)

Progressbar Pb

ttk.Progressbar · CustomTkinter: CTkProgressBar · ttkbootstrap: ttkb.Progressbar

Shows how far along a task is. Set the value from your code as work completes.

Worth knowing: The two toolkits differ: ttk.Progressbar takes 0–100, CTkProgressBar takes 0.0–1.0. Switching toolkit means rescaling the numbers you set.

self.progressbar1 = ttk.Progressbar(root, orient="horizontal", mode="determinate")
self.progressbar1.place(x=20, y=20, width=180, height=22)

Meter (gauge) Me

ttk.Progressbar · CustomTkinter: CTkProgressBar, which takes 0.0-1.0 · ttkbootstrap: ttkb.Meter, a real circular gauge

A dial showing a value out of a total. This is ttkbootstrap territory: it is the only one of the three with an actual gauge widget, so exporting for the other toolkits substitutes a determinate progress bar carrying the same number.

Worth knowing: The fallback is honest rather than exact — a horizontal bar instead of a dial. If the gauge is the point of your interface, that is a reason to export for ttkbootstrap.

self.meter1 = ttk.Progressbar(root, orient="horizontal", mode="determinate", maximum=100, value=65)
self.meter1.place(x=20, y=20, width=140, height=140)

Scrollbar Sr

tk.Scrollbar · CustomTkinter: CTkScrollbar · ttkbootstrap: ttkb.Scrollbar

Scrolls a listbox, text box or canvas. Pick the widget it drives in the inspector and the designer writes the wiring between the two for you.

self.scrollbar1 = tk.Scrollbar(root, orient="vertical")
self.scrollbar1.place(x=20, y=20, width=18, height=120)

Treeview (table) Tv

ttk.Treeview · CustomTkinter: no equivalent, stays ttk.Treeview · ttkbootstrap: ttkb.Treeview

A multi-column table with headings, for showing rows of records. The designer sets up the columns and generates a load_<name>(rows) helper that fills it from any iterable of row tuples.

self.treeview1 = ttk.Treeview(root, columns=("col1", "col2"), show="headings")
self.treeview1.heading("col1", text="Column 1")
self.treeview1.heading("col2", text="Column 2")
self.treeview1.place(x=20, y=20, width=240, height=150)

Data

Plotting numbers, using a library outside the standard one.

Chart (matplotlib) Ch

FigureCanvasTkAgg · CustomTkinter: unchanged, matplotlib draws its own canvas · ttkbootstrap: unchanged, matplotlib draws its own canvas

A matplotlib plot embedded in the window. tkinter has no chart widget, so this wraps a matplotlib Figure in the FigureCanvasTkAgg bridge and places that. Set the plot type, title and axis labels here; the designer generates a plot_<name>(x, y) helper that clears the axes, draws your data and refreshes the canvas.

Worth knowing: The only widget needing a package outside the standard library: pip install matplotlib. It is also a wrapper rather than a widget, so geometry goes through .get_tk_widget() — the generated code already does this.

self.chart1 = FigureCanvasTkAgg(Figure(figsize=(3.20, 2.20), dpi=100, layout="constrained"), master=root)
self.chart1_axes = self.chart1.figure.add_subplot(111)
self.chart1_axes.set_title("Chart")
self.chart1.draw()
self.chart1.get_tk_widget().place(x=20, y=20, width=320, height=220)

A menu bar is the one thing here that isn't a widget you drag. It has no position or size, and it attaches to the window itself rather than sitting on it, so you build it in the inspector with nothing selected, under Menu bar, and it's drawn as window chrome on the canvas rather than as something you can select or move.

Menus hold items. Leave an item's label blank and it becomes a separator; give it a name and you get an on_<menu>_<item> handler stubbed for you, exactly like a button. Items can hold their own items, which nests them as submenus.

Shortcuts are worth a word of warning. tkinter's accelerator only draws the shortcut text beside the item; it doesn't make the key do anything. So whenever the designer recognises what you typed, it also emits a real bind_all, and the shortcut works rather than just looking like it should:

menubar = tk.Menu(root)
self.file_menu = tk.Menu(menubar, tearoff=0)
self.file_menu.add_command(label="New", accelerator="Ctrl+N", command=self.on_file_new)
self.file_open_recent_menu = tk.Menu(self.file_menu, tearoff=0)
self.file_open_recent_menu.add_command(label="notes.txt", command=self.on_file_open_recent_notes_txt)
self.file_menu.add_cascade(label="Open Recent", menu=self.file_open_recent_menu)
self.file_menu.add_separator()
self.file_menu.add_command(label="Quit", accelerator="Ctrl+Q", command=self.root.destroy)
menubar.add_cascade(label="File", menu=self.file_menu)
root.configure(menu=menubar)
# accelerator= only draws the shortcut text; these make the keys work.
root.bind_all("<Control-n>", lambda e: self.on_file_new())
root.bind_all("<Control-q>", lambda e: self.root.destroy())

It's plain tk.Menu whichever toolkit you export, because neither CustomTkinter nor ttkbootstrap provides a menu of its own.

Nesting and containers

Frames, label frames and notebook tabs can hold other widgets. Drop a widget inside one on the canvas and it becomes a child, so the generated code parents it correctly and moving the container moves everything in it. Positions of nested widgets are relative to their parent, exactly as tkinter treats them.

The same design, three toolkits

Thirteen of these map onto a native CustomTkinter widget, three are composed from CTk primitives, and three (Listbox, Spinbox and Treeview) have no CTk equivalent and keep their classic versions. The CustomTkinter page has the full mapping.

ttkbootstrap is a themed skin over ttk, so sixteen of these become the ttk widget of the same name and only Text, Listbox and Canvas, which ttk does not provide at all, stay classic tkinter. Because ttk takes colours and fonts from styles rather than constructor options, any per-widget colour you set becomes a named style in the generated code.

Drag any of these onto a window and watch the Python write itself.

Open the designer, no sign-up →

Next steps

Start from a working template, follow the step-by-step walkthrough, work out which modern toolkit suits your app with CustomTkinter vs ttkbootstrap, or see what to look for when choosing a tkinter GUI builder.