Python GUI Programming With T
by David Amos @Mar 20,2022. 106 Comments
‘> (ini) (ea)
Mark as Completed
inter
Table of Contents
+ Building Your Fist Python GU Apolication With Thinter
© AddingaWidget
© Check Your Understanding
+ Working with widgets
Displaying Textand Images With Label Widgets
Displaying Clickable Bustons With Button Widgets
Getting User Input With Entry Widgets
Getting Multiline User Input With Text Widgets
Assigning Widgets to Frames With Frame Widgets
Adjusting Frame Appearance With Reiss
‘Understanding Widget Naming Conventions
‘Check Your Understanding
* Controlling Layout With Geometry Managers
© The pack!l Geometry Manager
© The placel Geometry Manager
© The rid Geometry Mana
+ Making Your Aplications Interactive
Using Events and Event Handlers
© Using command
© Check Your Understanding
+ fuildinga Temperature Converter (amo Appl
+ Bulding a Tex Etor (example App
+ Conclusion
+ Additional Resources soe= ‘Your Practical Introduction to Python 3 »
O Remove ads
Python has alot of Gul rameworks, but Tkinter’s the only framework that’s bult inte the Python standard library,
Tkinter has several strengths. is eress-platfarm, so the same code works on Windows, macOS, and Linux Visual
elements are rendered using native operating system elements, so applications built wth Tkiner look lke they
belong onthe platform where they're run
Although Tknteris considered the de facto Python GUI framewor4t’s not without ecm, One notable ctcsm Is
‘that GUIs buile with Tkinterlook outdated. fyou want a shiny, modem interface, then Tkinter may not be what
your'e looking for
However, Tkintr is lightweight and relatively painless to use compared to other frameworks. This makes ita
compelling choice for building GUI applications in Python, especially for applications where a modern sheen is
unnecessary and the top priory isto quickly build something that’s functional and cross-patform.
In this tutorial, you'll learn how to:
+ Ger started with Tkinter with a Hello, World application
*+ Work with widgets, suchas buttons and textboxes
+ Contvo your application layout with geometry managers
‘+ Make your applications interactive by associating button clicks with Python functions
"Note: This tutorial is adapted from the chapter “Graphical User Interfaces” of i a
lnteoduction to Pyth
‘The book uses Python's built-in IDLE editor to create and eait Python files and inter
In this tutorial, references to IDLE have been removed in favor of mare general language.
the Python shel.
‘The bulk ofthe material in this tutorial has been let unchanged, and you should have ne problems running
the example code from the ecitor and environment of your choice.
(once you've mastered these skills by working through the exercises atthe end of each section, youl tie everything
‘together by building two applications. The fist isa temperature converter, and the second isa text editor. k's time
+0 diverghtin and learn how to build an application with Tkinter!
Free Bonus: 5 Thoughts On Python Mastery ree course for Python developers that shows you the roadmap
and the mindset you'll eed to take your Python skills tothe next level
| Take the Quiz: Test your knowledge with our interactive “Python GUI Programming With Tkinter”
Upon completion you wil receive a score so you can track your leaning progress overtime:
1
Take the Qui
Building Your First Python GUI Application With Tkinter
The foundational element ofa Tkinter GUlis the window. Windows are the containers in which ll other Gul
elements live. These other GUI elements, such a text boxes abels, and buttons, are known as widgets. Widgets
are contained inside of windows.
Fist, create a window that contain a single widget. Startup a new Python shel session and follow along!
Note: The code examples in this tutorial have all been tested on Windows, macOS, and Ubuntu Linux20.04
with Python version 320IFyou've installed Python withthe official installers avalable for Windows and macOs from pyshon.org, then
you should have no prablem running the sample code. ou can safely skip te rest ofthis nate and continue
with the tutria
Ifyou haven't installed Python withthe official installers, or there's no ofa distribution for your system, then
here ae some tips for getting up and going,
Python on macOS with Homebrew:
The Python distribution for macOS available on Homebre doesn't come bundled with the Tc/tk dependency
required by Tknter The default system version is used instead, This version may be outdateé and prevent you
{om importing the Tkinter module, To avoid ths problem, use the afcal mac0S installer.
‘bunt Linux 20.04:
To conserve memory space, the default version ofthe Python interpreter that comes preinstalled on Ubuntu
inux 20.04 has no support for Tknter. However ifyou want to continue using the Python interpreter bundled
with your operating system, then install the following package:
Shel
$ sudo apt-get install pythond-tk
This installs the Python GUI Tkinter module
Other Linux Favors:
you're unable to geta working Python installation on your favor of Linux, then you can build Python with
the correct version of Te/Tk from the source code. For a step-by-step walkthrough of this process, check out
the Python 3 Installation & Stun Guide, You may aso ty using ayeny to manage multiple Python versions
‘with your Python shell open the first thing you need to dois import the Python GUI Tkinter module:
Python
‘Awindow isan instance of Thinter’s 1k clas. Go anead and create new window and assign it to the warable windows
Python -
> window =H TKO)
‘When you execute the above code, a new window pops up on your screen. How it looks depends on your operating,
system:
ts - 0 x ooo (cli
(a) Windows (by macos (Ubu
‘Throughout the rest ofthis tutorial, you'll see Windows screenshots.Ra aL)
0 Remove a
Adding a Widget
Now that you have a window, you can add a widget Use the tk. Label class to add some text to a window. Create a
Label widget with the text “Helo, Tkinter* and assign toa variable called greeting
Python -
o> greeting = 9k Label tex
eldo, Tkinter")
The window you created earlier doesn't change. You just created a Label widget, but you haven't added ito the
window yet. There are several ways to add widgets to a window. Right now, you can use the Labes widget’s .22ck()
method:
aython
o> grest ing pack()
The window now looks ike tis
~~ o x
Hello, Tkinter
When you pack a widget into a window, Tkinte sizes the window as smal as it ean be while stil fully encompassing
the widget. Now execute the following:
Python ~
29> window. aasetooet)
Nothing seems to happen, but notice that no new prompt appears inthe shell
stndaunatnoop() tells Python to run the Tkinter event loop. This method listens for events, such as button clicks oF
eypresses, and blacks any code that comes ate i from running until you clase the window where you called the
‘method. Go ahead and close the window youve created, and you'll se a new prompt displayed inthe she
hen you work with Tknter from a Python REPL, updates to windows are applied as each line is
‘executed. This snot the case when a Tkinter program is executed from a Python ile!
you don't include window nasntoop() 3 the end of program in a Python le, then the Tkinter application will
never un, and nothing wil be displayed. Alternatively you can bulld your use interface
Python REPL by calling windew.update() after each step to reflect the change.
crementallyin
Creating 2 window with Tkinter only takes a couple of lines of code. But lank windows aren't very useful! In the
next section, youl learn about some of the widgets avallabe in Tknter, and how you can customize them to meet
your application’ needs.
Check Your Understanding
‘Expand the code blocks below to check your understanding:
Esercise: Crete a Tkinter window Show/Hide
You can expand the code black below to see a solutionSolution: Create a Tkinter window showitiide
When you're ready you can move on to the next section,
Working With Widgets
Widgets are the bread and butter ofthe Python GUl framework Tknter. Theyre the elements through which users
ineeract with your program. Each widget Tkinteris defined by a class. Here are some ofthe widgets available
Widget class Deseri
Lae ‘A widget used to display text on the screen
button ‘button that can contain text and can perform an action when clicked
entry ‘text entry widget that allows only a single line of text
Text ‘text entry widget that allows multe text entry
rane ‘rectangular region used to group related widgets or provide padding between widgets
Youll se how to work with each ofthese inthe following sections, ut keep in mind that Tkiter has many more
‘widgets than those listed here, The widget’ choice gets even more complicated when you account fora whole new
setof themed widgets, In the remaining part ofthis tutorial, you're only going to use Tkinter’s classic widgets,
though
It you'd like to lean more about the two widget types, then you can expand the collapsible section below:
Classievs Themed Widgets Showitide
For afull ist of Tkinter widgets, check out Basic Widgets and More Widgets inthe TkDocs tutorial. Even though it
describes themed widgets introduced in Tel/Tk 8.5, most ofthe information there should also apply to the cassie
widgets.
Fun Fact Tkinter literally stands for" Tk interface” because i's 2 Python binding or a programming interface to
the T library inthe Tel scripting language
For now take a closer look atthe Lael widget.
cl
oa Become a Python Expert »
O Remaveads
Displaying Text and Images With Labe1 Widgets
Label widgets are used to display text or images. The text displayed by a Label widget can't be edited by the user. Its
for display purposes only As you saw in the example at the beginning of this tutorial, you can create a Label widget
by instantating the Labe cass and passing a iting to the text parameter
Python
sbel = te. tabel(texte"Hel oy Tkinte=")
abel widgets display text with the default system text color and the default system text background color. These
are typically black and white respectively, but you may see different colors if you've changed these settings in your
operating system,You can control Lave text and background colors using the foreground and background parameters
Python
abel = tk. Label(
There are numerous valid color names, including:
Many ofthe HTML color names work with Tkinter, Fora fll ference including macOS- and Windows-specfc
system colors that the current system theme contrals, check out the colors manual page.
‘You can also specify a color using hexadecimal RCS values:
Python
sbel = te. Label(texte"HieLo, Tkinter’, backerounde"#34i246")|
This ses the label background toa nce light blue color, Hexadecimal RGB values are more cryptic than named
colors, but they're also more flexible. Fortunately, there are tools available that make getting hexadecimal color
codes relatvely painless.
you don't feel ke typing out feregrouna and backgreuné all the time then you can use the shorthand fg and bg
parameters to set the foreground and background colors:
eython
Inbel = te. Label(textsrHieo, kinter", #eehuntte",
ack")
You can aso control the width and height of label with the wiath and nesant parameters
Python
abel = ex Label(
Heze's what this label looks Uke in a window:
a xlt may seem strange that the label inthe window isn't square even though the width and height are both set to 26
Thisis because the width and height are measured in text units. One horizontal text units determined by the width
ofthe character, or the number zero, in the default system font. Similarly, one vertical text units determined by
the height of the character
Note: For width and height measurements, Tkinter uses text Unit, nstead of something like inches,
centimeters, or picels to ensure consistent behavior ofthe application across platforms.
Measuring units by the with ofa character means that the size of a widgets relative tothe default font on 3
users machine, This ensures the text fits properly in labels and buttons, no matter where the apalication is
sunning
Labels are great forcisplaying some text, but they don'thela you get input from a user. The next three widgets that
you'l lean about ae all used to get user input.
Learn Python »
0 Remove a
Displaying Clickable Buttons With sutton Widgets
button widgets ate usec to display cickable buttons. You can configure them to cal function whenever they're
clicked. Youll cover how to call functions from button clicks inthe next section, For navy, take 2 look at haw to
create and stye a button
There are many similares between sutton and Label widgets. In many ways, 9 button s just a label that you can
click! The same keyword arguments that you use to create and syle a Label will work with sutton widgets. For
example, the following code creates a button witha blue background and yllow text It also sets the with and
height to 25 and s text unis, respectively:
Python
heapnt5,
evolve
Here's what the button looks like ina window:
eee
Pretty nity! You can use the next two widgets to collect text input from a use.
Getting User Input With entry Widgets
When you need to geta litle bit of text from a user, like a name or an emall address, use an Entry widget. el display
‘a small text box thatthe user can type some text nto, Creating and styling an Entry Widget works prety much
exactly lke with Label and sutton widgets For example, the fllowing code creates a widget with a blue background,
some yellow text, and a width of se text units:thon
entry = ek EntryCfyelion’, bee"be", width-s0)
The interesting bit about entry widgets isn't how to style them, though. I's how to use them to get input froma
user. There are three main operations that you can perform with Emery widgets:
1. Retrieving text with .2e0()
2 Deleting text with .seiere()
23. Inserting text with -insert()
‘The best way to get an understanding of Entry widgets sto create one and interact with it Open up a Python shell
and follow along wit the examples inthis section. First, import inter and create anew window:
Python =
Sop window = TKO)
Now ereate a abel and an entry Widget:
bython =
29> Label = tk Label (exten)
o> entry = tk Entry)
The tater describes what sort of text should go in the entry widget. It doesnt enforce any sort of requirements on
‘the Entry, butt tells the user what your program expects them to put there. You need to -pack() the widgets into
the window so that they'e visible
Python oe
29> tabel puck)
o> entry Packt)
Heres what that looks tke:
Name
Notice that Thinter automaticaly centers the label above the Entry widget in the window. Tis isa feature of -pack(),
which you'l lear more about in later sections.
Click inside the enery widget with your mouse and type Re Python
Er eae ea
Nome
[realPthon
Now you've got some text entered into the entry widget, but that text hasn't been sent to your program yet: You can
Use -get() to retrieve the text and assign it toa variable called rare:
bython oe
o> mame = entry. get
You can delete text as well. This celeta() method takes an integer argument that tells Python which character to
1 code block below shows how .deteta(o) deletes the fst character rom entry
remove. For example,Python =
o> entry. celerete)
The text remainingin the widget is now esl Python
ae oe
Name
lel Python
Note that, jst like Python string objects, ext in an entry widgets indexed starting with
It you need to remove several characters from an entry, then pass a second integer argument to .celete() indicating
‘the index ofthe character where deletion should stop. For example, the following code deletes the frst four letters
in entry
Python
o> entry-cetetet®, 4)
“The remaining text now reads fythar
ao x
Python
Entry-celetet) works just ike string slicing, The fist argument determines the stating index, and the deletion
continues up to but aot including the index passed asthe second argument. Use the special constant tk.ew or the
second argument of .dlete() to remove all textin entry:
Python
o> entry deletet®, 1.190)
‘You'll now see a blank textbox:
Name
(on the opposite end ofthe spectrum, you can also insert text into an Entry widget
Python =
o> entry dnacre(0, Python’)
The window now looks lke this
Name |
Python
‘The frst argument tells -tnsers() where to inser the text there's no textin entry, then the new text will always be
inserted atthe beginning ofthe widget, no matter what value you pass a the fst argument. For example, calling
nsert() with 10 as the frst argument instead of 3s you did above, would ve generated the same output.every already contains some text, then -insert() will nsert the new text at the spectid postion and shift all
existing texto the right:
python
o> entry dnserst@, “Rest
The widget text now reads Rea #ython
Er eae ea
Nome
Real Python
Entry widgets are great for capturing small amounts of text from a user, but because they're only eisplayed on a
single line, theyre not ideal for gathering large amounts of text, That's where Text widgets come int
ob Read
Getting Multiline User Input With Text Widgets
Text widgets are used fr entering tet ust ke Entry widgets. The dferenceis that ext widgets may contain
smutiple ines of tent. With Text widget 2 user can input awhole paragraph or even several pages oftext! Just ike
‘th Entry widgets, you can perform three main operations with Text widgets
1. Retrieve text with .get0)
2,Delete text with eiete()
3. Insert text with snsere()
Although the method names are the same as the Entry methods, they work abit iferently. It's time to get your
hands drt by creating a rext widget and seeing what t can do
Note: Do you stil have the window from the previous section open?
Ifso, then you can close it by executing the following:
Python
Do window.cestroyt)
You can also close it manually by clicking the Close button
In your Python shell create anew blank window and pack a rext() widget into it
Python
o> window = HTK)
o> textbox =k: TexeO
2 tentbon.pack()
Text boxes are much largerthan enery widgets by default. Here's what the window created above looks ike:Click anywhere inside the window to activate the text box. Type in the word Nelio.Then press Enter and type
od on the second line, The window should now look tke ths:
am oa
[zeit
Irora
ust lke with entry widgets, you can retrieve the text from a Text widget using .et(). However calling -get() with
no arguments doesnt return the fll textin te text box ike it does fr entry widgets. It ralses an exception:
Python =
>> text bow. 820)
Traceback (ost recent call Last):
sypotcrors get() afssing 1 required postttonal argunent: ‘Sedexd
Text get() require at least one argument. Calling .ge%() with a single index returns a single character To retrieve
several characters, you need to passa start index and an end index. Incices in Text widgets work ciferentl than in
Entry widgets. Since Tex widgets can have several ines of text, an index must contain two pieces of information:1. The tne number of a character
2. The position of character on that line
Line numbers star with , and character positions start with . To make an index, you create a string ofthe form ~
." replacing cLine> with the line number and tent bow gett"
oy
There are fie letters in the word teil, ane the character number of is 4, since character numbers star from @, and
‘the word et starts at the frst position inthe text box. Just lke wth Python string slices, in arder to get the entire
ward e110 rom the textbox, the end index must be ane mare than the index f the last characterto be read,
for the first ndex and
So, to get the word Helio from the textbox, use*3, 5" forthe second index:
Python -
>> text bow gee 0", 15")
To get the word uorta°on the second line of the text box, change the line numbers in each indexto 2:
Python ~
95 text pow ge30°2.0
cas)
‘To getall ofthe text na textbox, set the starting indexin "1.0" and use the special tno constant forthe second
Index
Python oe
o> tent bow geet.0", ND)
edle\naorl aie
Notice that text retumed by .get() includes any newline characters You can also see from this example that every
linen a text widget has a newiine character atthe end, including the last tine of text inthe text box
deiete() is used to delete characters from a text box. It works jst lke delete() for entry widgets. There are two
ways to use delete()
1, With a single argument
2. With two arguments
Using the single-argument version, you pass to .éelete the index of single character tobe deleted. For example,
‘the following deletes the fist character from the text box
Python ~
o> tant bow delete(.0°)
The fist line of text in the window now reads ello:‘With the two-argument version, you pass two indices to delete a range of characters starting at the fist index and up
‘9, but nat including the second index.
For example, to delete the remaining elio onthe ist line ofthe text box, use the indices 1.0" and "2.4"
Python -
9) text box delete.
ony
Notice thatthe texts gone from the ist line. This leaves a blank line followed the word wori¢ on the second line:
Even though you can't see there's stil a character onthe fist line. I's @ newline character! You can verily this.
using et)Python =
99 text box geet"
you delete that character, then the estof the contents ofthe text box wll shift up ain:
Python
os tot pox delete
Now, Horta ison the fist line of the text box:
fe Saecee
jroria
“Tryto clear out the rest ofthe text inthe textbox Set “1.0” asthe start index and use tk. tno fr the second index:
Python ~
>> text pox.delete(.0%, tk.010)
“The textbox s now empty:‘You can insert text into a text Box using .ansert():
Python os
o> tent_poxctnsere 1
ores")
This insets the word weiso atthe beginning ofthe textbox, using the same "cLine>.colun>” format used by get()
‘0 specify the insertion position:
a - ag x
lietto
Check out what happens ifyou try to insert the word word on the second ine:
Python oe
o> tent bow dnaert¢"
sents")
Instead of inserting the text on the second line, the tet is inserted atthe end of the frst line:you want to insert text onto anew lin, then you need to insert a newline character manually nto the string being
inserted
Python =
99 tent bow Seaers(
ynuorie")
Now tori ison the second line ofthe text box:
fu - oa x
[zeit
Irora
Ancert() will do one of two things:
1 Insert text at te specified postion ifthre's already text ator ater that positon
2. Append text tothe spected line ifthe character number's greater than the index ofthe last character inthe
textbox.1s usually impractical to try and keep track of what the index ofthe last chara
‘the end of vext widgets to pass tk. e400 the frst parameter of insert
is, The best way to inset text at
python
20> text bow tnsert(th A, “Put ne at the endl”)
DDon' forget to include the newiine character (\n) atthe beginning ofthe text ifyou want to putit on anew line:
Python ~
”
o> tent bow snsere( th A, “\abut se on 9 n00 1
Label button, Entry, and Text widgets ae usta few ofthe widgets available in Tkinter. There are several others,
including widgets for checkboxes, radio buttons, scroll bars, and progress bars. For more information on allo the
available widgets, see the Adetional Widgets list inthe Ac section
nal Resour
Te rca Sly
O Remove ads
Assigning Widgets to Frames With Frame Widgets
In this tutorial, you're going to work with only fe widgets:
2.autton
Sentry
5.
These ae the four you've seen so far plus the Frane widget Frane widgets are important fr organizing the layout of
your widgets in an application
Before you get into the details about laying out the vsual presentation of your widgets, take a closer look at how
Frame widgets work, and how you ean assign other widgets to ther, The fellowing script creates a blank Frare
‘widget and assigns it to the main application windows
thon
vancow = thTKOD
frame = te. Franet)
‘rane. pack’)
window natnloop()
‘rane.pack() packs the frame into the window so that the window sizes itself as small as possible to encompass the
frame, Vihen you run the above script, you get some seriously uninteresting output
a = a
‘An empty Frave widget is practically invisble. Frames are best thought of as eantainers for other widgets. You can
assign a widget to 2 frame by setting the widget’ master attribute
Python
frame = tk. Franet)
abel = te Label(naster=frane)To gota fel for how this works, write a script that creates two Frane widgets called frane_a and ¢rane_. In this
‘crip, frane_s contains label with the text“1'n in Frane A", and frawe_b contains the label "r'e sn Frame
Heres one way to do this
Python
moore tednter as
sancow = teTHOD
frame a = th.Frane()
frone_b = th FraneQ)
Isbel_s = th tanel(nastorfranea, text
abel a.p2cki)
in in rane a)
label_b = th.Label(nastercfeae_b, texte"I'm in Frame 6°)
abel b.paekt
rane a. p2ek()
frane_b.p3ek()
incon aninloop()
Note that rane_a is packed into the window before frane_p, The window that opens shows the label in érane_a
above the label intranet
fo x
minFame
min Fame
"Now see what happens when you swap the order of frane_a.pack() and frane_p.pack)
Python
Inport tednter as
window = thth()
frames = th.Frane()
Isbel_a ~ th (anel(nasten-fnae_a, text-'7'n in Frane #°)
Isbel_a.p3ek)
frome = th.Frame()
Label_b = th Lavel(naster-frane_b, Sext-"7'm An Frane 8°)
abel b.poek0)
frane_b.23ek() - 7
frane_a.93ek()
incon aninloon()
The output looks ike this:
-“~ Oo x
Frm in Frame 8
min ame A
Now 1sbe1_bis ontop. Since abe
i assigned to Yrane_b,'t maves to wherever transis positioned
All four of the widget types that you've learned about—Label,avtton Entry and Text—have 2 naster attribute that's
set when you instantiate them. That way, you can contol which Fane 9 widget is assigned to. Frane widgets are
great for organizing other widgets ina logical manner, Related widgets can be assigned to the same frame so that, if
‘the frame is ever maved in the windows, then the related widgets stay together,"Note: Ifyou omit the master argument when creating a new widget instance, then ill be placed inside ofthe
top-level window ay default
In adcition to grouping your widgets logically, rane widgets can acd lite flare t the visual presentation of your
Adjusting Frame Appearance With Reliefs
Frame widgets can be configured with a relief attribute that creates a border arounc the frame. You can set relies to
application, Read on to see how to create various borders for Frane widgets,
aCe aa eer
© Remove
be any of the following values:
4 tk runt: Has no border effect (the deta
+ tx. suntcn: Creates a sunken effect
lve)
+ sksmarseo: Creates a raised effect
reates a grooved border effect
+ ksmtooes Creates a ridged effect
To apply the border effect, you must set the torderuieh attribute toa value greater than 3. Ths attribute adjusts the
Width ofthe borderin ptels. The best way ta geta fe! for what each effect looks lke is to se them for yourself.
Heres a script that packs five rane widgets into a window, each with a different value forthe reise argument:
Python
ingort thinter 25 tk
groove"? tk-ca00¥e,
ridge": RIDGE,
>
vind = 8 TKO)
‘for eelief_pave, relief in border effects. Stens()
frame = thcFrae(nastersuindon, relief-relief, torderwidth-s)
rane pack(side-2t LEFT)
label = th Label (naster-érane, text-reltef
abel. pack()
ne)
vindow.nainioon()
Heres a breakdown ofthis srt:
+ Lines 309 create a dictionary whose keys ae the names ofthe ciferent relief effects available in Tkinter. The
values are the corresponding Tkinterabjects, This dictionary is asigned tothe vorder_eFfecte variable
*+ Line 13 stars a ‘orlo0p to loop over each item inthe border_etrectsditionany.
+ Line 14 creates a new Frane widget and assigns itto the window object. The retier attribute is st to the
corresponding relief in the berdr_effects dictionary, and the border attibute s set tos so thatthe effects
vsible
*+ Line 15 packs the rane into the window using .pack(). The ide keyword argument tells Tknter in which
dliretion to pack the feane abject. You'l see more about how this works inthe next section.
Lines 16 and 37 creat
created
2 Label widget to display the name ofthe relief and pack itnto the érane object you justThe window produced by the above script looks lke this
‘ - o x
In this image, you can see the following effects:
+ sk.ruar creates a frame that appears to be Mat
‘+ tk, suween adds a border that ives the rame the appearance of being sunken into the window,
‘+ sksaazsep gives the frame a border that makes it appear to stick out from the sereen,
*+ tk.cnoove adds a border that appears as a sunken groove around an otherwise Mat frame
+ tk.aro0e gives the appearance of raised lip around the edge ofthe frame.
“These effect gve your Python GU! Tkinter application a bit of visual appeal
Understanding Widget Naming Conventions
‘When you create a widget youcan get any are you tke, as long ass a valid Python identifier. usully2
00d idea to include the name ofthe widget lass inthe variable name that you assign tothe widget instance For
example fa ate widgets used to display a users are then you might name the widget abel_eser_pne. An
eniry widget used to cllect a user age might be called ertry_age
Note: Sometimes, you may define anew widget without assigningit to a variable, You'l all is .eack4) method
iret on the same ine of code:
Python
o> thatabel{tent="Hello, Tkinter").pack()
‘This might be helpful when you don't intend to refer to the widgets instance lateron, Due to automatic
memory management, Python would normally garoage collect such unassigned objects, but Tkinter prevents
that by registering every new widget internally
When you include the widget lass name in the vaiable name, you help yourself and anyone else who needs to read
your code to understand what type of widget the variable name refers to. However, using the fll name af the widget
class can lead to long variable names, so you may want ta adopt a shorthanc for referting ta each widget type. For
the resto this tutorial, you'l use the following shorthand prefixes to name widgets:
Widget class Variable Name Prefix Example
entry ont centage
rane frm fonaeivess
In this section, you learned how to create a window, use widgets, and work with frames. At this point, you can make
some plan windows that display messages, but you've yt to create a full-blown application. Inthe next section,
you! learn how to control the layout of your applications using Tkinter’s powerful geometry managers.
Check Your Understanding
{Expand the code block below fr an exercise to check your understanding:rercise: Create an Entry widget and insert some text Showitide
You can expand the code block below to see a solution:
Solution: Create an Entry widget and insert some text Showide
Controlling Layout With Geometry Managers
Lp until now, you've been adding widgets to windows and Frane widgets using .pack(), but you haven't learned
wat exactly this method does. Let's clear things up! Application layout in Tkinter Is controll with geometry
‘managers. While .pack() 's an example ofa geometry manages itisn't the only one, Tknter has two others:
When you're ready you can mave on to the next section
Su RU cd
rcene er
+ place)
+ seria)
ach window or Frane in your application can use only one geometry manager. However, ferent frames can use
‘rae. grie(oows, col
label = tk Labeltnasterctrane, sextoftow (4)\aColum (3)°)
bel pack()
incon aninloop()
Heres what the resulting window 'ooks tke:
fu - Oo x
Row0 | Row0 | Row0
Column 0| Column 1] Colurnn2
Row1 | Row1 | Row!
Column 0) Column 1) Column 2
Row2 | Row2 | Row2
Column 0) Column 1) Column 2
‘You're using two geometry managers in this example. Each frames attached to window withthe iat) geometry
manager:
Python
incon = te-TK0)
for 4 sn vange(a)
for 3 30 ranget3)
fewe = th Frame
>
frate.erse(rows, colunn-3)
Isbel = tk Labeltnaetemtrane, sextfou (8)\aColuen (3)°)
abel pack()
vindow nainloop()
Each Inbes attached tits master Frane with pack)Python
incon = tTK0)
‘for 4 in range
bonderwsasnes
>
‘rane. grie(ron-s, colune-3)
label = tk Label(vasterctrane, sextoftow (4)\2Colum (3)°)
bel pack)
incon aainloop()
‘The important thing to realize here is that even though er) is calleé on each eran object, the geometry manager
applies tothe window object, Similarly, the layout of each frareis controlleg withthe -pack¢) geometry manager.
‘The frames inthe previous example are placed tightly next to one another To ade some space around each frame,
you can set the padding ofeach cell inthe grid. Padding is just some blank space that surrounds a widget and
visually sets its content apart.
“The two types of padding are external an internal padding. External padéing acs some space around the outside
ofa grid cell. Its controled with two keyword arguments to grt):
1.paéx adds paddling inthe horizontal direction
2. paty adds padding inthe vertical drection
Both pax and pady are measured in pixels, not text units, so setting both of them tothe same value will reate the
‘same amount of paddingin both directions. Try to add some padding around the ouside of the frames from the
previous example:
Python
incon = teTK0)
for 4 an vanget3)
far 3 an range(3)
rane = te Fret
>
frave.gri(rout, colunn-j, pade-5, pody-s)
Isbel = tk Label(raete~trane, sext-rtow {2)\3Coluen (3)°)
bel pack)
incon aaintoope)
Heres the resulting window:
rowo | Row0 | _Rowo
Column 0) Cokin 1} Column 2
owt | owt | Row!
camo] Cohn 1] Catuma2|
ow? | Row? | Row?
Column 0] Cohn 3] Column 2ack() also has racx and pady parameters. The following code is nearly identical tothe previous code, except that
{you add five pites of addtional padding around each label in both the x andy directions:
Python
import tednter as
swindon = th-TK0)
for 4 in vanget3)
for 3 37 ranget3)
‘rate ~ te. Franet
ascend,
>
rave. gri(rou-, coluensj, pade-5, pays)
abel = th Labei(nastenfrane, kextefton {$)\aCaluen (3)°)
abel pack(oaaies, pady-5)
non nainloone)
The extra padding around the Lave widgets ges each cell inthe grid a lite bit of breathing room between the
Frame border and the textin the label:
ae o x
Rowo | Row0 | Row
column | Column | Column 2
owt | _Rowt | Rows
Column | Colomn' | Column 2
Row2 | Row2 | Row?
column | Column | Column 2
That looks pretty nie! But fyou try and expand the window in any direction, then you'll notice that the layout n't
very responsive:
fe x
row? | rome | Row?
cote | cotumet | _cotumn 2
‘The whole grid stays atthe top-left comer as the window expands,
By using .cotuancanfigure() and .rowconfigure() on the window abject, you can agjust how the rows and columns of
‘the gid grow asthe window is resized. Remember, the grid is attached to window, even though you're calling ga)
fom each Frane widget. Both .colunaconéiguret) and .roweanfigure() take three essential arguments:
1. Index: The index ofthe grid column or row that you want to configure or ist of indices to configure multiple
rows or columns at the same time2. Weight: A keyword argument called weighs that determines how the column or row should respond to window
sizing, relative tothe other columns and rows
3. Minimum Size: A keyword argument called sinsize that sets the minimum size ofthe row height orcoluma
width in pels
‘weight is Set to by default, which means thatthe column or row doesn't expand as the window resizes every
column or row is given a weight of 2, then they al grow at the same rate. Ione column has a weight of and
another a weight of2,then the second column expands at twice the rate ofthe fist. Adjust the previous script to
better handle window resizing
eython
window = thTK()
for 4 tn range
seinaou. colemconttaure(s
endow. roncontigure
for 3 30 ranget®, 3)
fewe = theme
>
rane. grse(oows, colons, 9868-5, pady-5)
Isbel = te Labeltraetar-trane, text-Fou (4)\9Coluen (3)")
abel. pack(oades, pays)
swingow naintoope)
cobuancentigure() and .seacontsgure() are placed in the body ofthe outer for loop. You could explicitly configure
each column and row outside ofthe for loop, but that would require wtng an additional six lines of code
(on exch iteration ofthe loop, the i-th column and row are configured to have a weight of. This ensures that the
row and colursn expand at the same rate whenever the window is resized. The ninsize argument is set 0 7 for each
column and ve for exch rw. This ensures that the Label widget always cisplays its text without chopping off any
characters, even the window size i extremely small
‘The results a grié layout that expands and contracts smoathly asthe window is esized
‘
cine | cna: | cites
tow
tow | owt
Tryit yourself to get fel for how it works! Play around with the weight and ninstze parameters to see how they
affect the grid
By default, widgets ae centered in their grid cells For example, te following code creates two Later widgets and
places them ina grid with one column and two rows:Python
incon = te-TK0
‘uincoe coturaconfegure(o, ninsize-250)
incon rowcontigure({®, 2], mlnsize-t08)
Isbeld = th. label tet
abel gria(row-e, colunn-2)
sbel2 = tk taben(sexs-")
abel? grie(rowa, colunn-a)
incon nainloope)
ach grid cel i 250 pitels wide and 100 pels tall. The labels are placed in the center of each cell, as you can see in
the following gure:
Om - ag x
You can change the location of each label inside ofthe grid cell using the sticky parameter, which accepts a string
containing one or more of the following letters:
to align to the top-centerpartof the cll
+ *e° or eto align to the rght-cente side of the cell
to_align tothe bottom-center part of
cell
+ sw or w to align to the le-conter side ofthe cell
The letters “ot, "5" ‘et, and "w" come from the cardinal erections north, south, east, and west Setting sticky to“
ton both labels in the previous code positions each label atthe top-center ofits grid cell:
thon
swincow = thTK0
‘unaoe coluracontigure(o, nénsize-250)
uncon rowconfigure([2, 3], mlnsize=108)
label = th tabed(text-
abel grie(row
")
=)
label? ~ tk tabel (cert
sbel2-grie(roms, column
")
stteaye'n")
swingow naintoope)
Here's the output:oe - o x
‘You can combine multiple letters ina single string to position each label n the commer ofits grid cell:
Python
incon = teTK0)
‘uncon convacentigure(o, ninsize-250)
now rowconfigure((®, 3), minsize=108)
abel = th. label (text)
abel grie(rone, column
sthetyetre")
abel? = th Label (ext
abe12.grie(rowt, column
")
sttcayesW")
sincow antnloore)
In this example, the sticky parameter of label1 is set to "ne", which places the label atthe top-right comer ofits grid
cell 1sbe12is positioned inthe botton-letcormer by passing “sw to sticky. Here's what that looks lke inthe
window
te - a x
‘When a widget is positioned with sticiy the sive ofthe widgetitelfi just big enough to contain any text and other
content inside afi, won fil the entire grid cell. In order to fl the grid, you can specify “ns” to force the widget to
fil the cel in the vertical direction, or “ew” ofl the callin the horizental direction To fil the entire cell set sticky
to *nseu”. The following example illustrates each of these options:Python
incon = teTK0)
incon rowcontigure(o, ninsize-se)
Tnéow colurnconfigure([®, 2, 2, 3], minsize-se)
mel?
ssbel3
nbelt.grse(rowe, colunme)
abel2 grie(rowe, columet, storys")
Labels grie(row-e, column2, sttexy-"ns")
incon aninloon()
Here's what the output looks like:
GK - Oo x
What the above examplellusrates is thatthe grist geometry managers sticky parameter canbe used achieve
‘the same effects asthe .pack() geometry manager’ £1 parameter. The correspondence between the sticky and
£423 parameters fs summarized in the following table
vate) sack)
.rsa() is» powerul geometry manager It's often easier to understand than .pack() and is much more flexible than
lace().When you're creating new Tkinter applications, you should consider using .erta() as your primary
geometry manager.
Note: .gria() offers much mare flexibility than you've seen here. For example, you can configure cells to span
‘multiple rows and column. Fer mare information, check out the Grid Geometry Manager section ofthe
TiDocs tutorial
Now that you've got the fundamentals of geometry managers down forthe Python GUI framework Tknter, che next
step is to assign actions to buttons to bring your applications tole
Online Python Training for Teams »
© Remove
Check Your Understanding
txpand the cade block below for an exercise to check your understancing:Exercise: Create an address entry form Show/Hide
You can expand the code block below to see a solution:
Solution: Create an address entry frm Showptide
‘When you'
ready, you can move on to the next section.
Making Your Applications Interactive
By now, you havea pretty good idea of how to create a window with Tkinter, add some widgets, and control the
application layout. That’ great, but applications shouldn't just look good—they actualy need todo something! In
‘this section, youl lear how to bring your applications to life by performing actions whenever certain events occur
Using Events and Event Handlers
When you create a Tkinter application, you must call window.nainiooo() to start the event loop. During the event
loop, your application checks fan event has occurred. fso, then itl execute some code in response.
The event loop is provided for you with Tkinter, 50 you don't have to write any code that checks for events yourself
However, you do have to wate the code that will be executed in response to an event. In Tkinter, you writ functions
called event handlers for the events that you use in your application.
Note: An event i any action that occurs during the event loop that might vigger some behavior the
application, such as when a key or mouse button is pressed
When an event occurs, an event object is emitted, which means that an instance ofa class representing the
event s created. You don't need to worry about instantiating these classes yourself Tkinter wil create
instances of event classes for you automatically.
‘You'll wite your own event loop in order to better understand how Tkinter’s event oop works. That way you can
see how Tkinters event loop ft into your application, and which parts you neee to write yoursell
Assume there's alist called events that contains event objects. Anew event object is automatically appended to
events everytime an event occurs in your program. You dan't need to implement this updating mechanism It just
automatically happens fr you inthis conceptual example. Using an infinite loop, you can continually check f there
are any event objects in events:
Python
f tesune that tnis list gets upestee automaticaly
events =
Ward you can skip to the next Lteration of the 1eop
se events = U1
4 1 execution neaches this potrt, then there 45 at least one
4 event object in the event ist
vent = events(@]
Right now, the event loop that you've created doesn't da anything with event Let's change that. Suppase your
application needs to respond ta keypresses. You need to check that event was generated by a user pressing @key on
their keyboard, and fso, pass event to an event handler function for keypresses.
‘Assume that event has 8 type atbioute set tothe string "seynnss” ifthe events 2 keypress event object anda
hor attribute containing the character ofthe key that was pressed, Create a new handie_keyoress() function and
Update your event loop code:Python
1
1 create an event anchor
det hance keypress (event)
riot the character associated to the kty presseg™™*
event. char)
“46 events => 1
event = events(el
1 2F event 1s a keypress event oaject
56 event type on "keypress"
handie_keypressevent)
When you call wingow-ratntonp(), something lke the above {oop is run for you. This method takes care of two parts
ofthe loop for you:
1 maintains a Uist of events that have occurred,
2. Iteuns an event handler any time anew event is added to that list.
Update your event loop to use window,nainloop() instead of your own event loop:
Python
vingow = th TK()
ee nanate keypress (event)
‘esprart the character associated to the key pressed"**
retevent.chary
indo eninloop()
sainloop() takes care ofa lt for you, Bu there's something missing from the above code, How does Tkinter know
‘when to use henale_keypress()? Tkinter widgets have a method called .bira() for just this purpose.
O Remaveads
Using .bind()
Tocallaneventhandierwheneveran event ocurs ona widget, use bint), The eventhandleris said to be bound
tothe event because ale everytime the event occurs. Youl continue withthe keyores example fom the
previous section and sein to bindnande Keypress) tthe keypress eventPython
incon = th-TK0)
oot hana keypress event
rine (event. char)
1 bind baypross event £0 hancle_koyeress()
inéowbine("", handle_keypress)
snow naintoone)
Here, the handle keypress() event handler is bound toa “" event using window. bind). Whenever a key is
pressed while the application is running, your program will print the character of the key pressed.
Note: The output ofthe above program isnot printed inthe Tkinter application window. i's printed tothe
standatd output stream (stdout)
Ifyou run the program in IDLE, then youl see the output in the interactive window: Ifyou run the program
from a terminal, then you should see the output your terminal
bind) always takes atleast two arguments:
1 An event thats represented by 2 string ofthe form "event nana, where event_nane can be any of Tkinter’s
‘events
2.An event handler that's the name of the function to be called whenever the event occurs
The event handleris bound to the widget on which bine) s calle, When the event handles called the event
objectis passed to the event handler function,
In the example above, the event handlers bound tothe window itself, but you can bind an event handler to any
widget in your application. For example, you can bind an event handler toa astton widget that will perform some:
action whenever the button is pressed:
eython
ot handle eliek(event):
prtne(-Tne sutton was eltcked!”y
button © th sutton(texts"Click el)
button bing(“ebutton", manele)
In this example, the *esutton-1>" event on the button widgets bound to the nandie_click event handler. The
«" forthe
other events for mouse button clicks, including “button-2>" forthe middle mouse button and
right mouse button,
Note: Fora lst of commonly used events, see the Event types section of the Thinter 8.5 reference
‘You can bind any event handler to any kind of widget with bine), but there's a more straightforward way to bind
event handlers to button clicks using the button widgets connane attribute
Using command
Every button widget has aco
function is executed
und atribute that you can assign toa function. Whenever the button is pressed, the
Take 3 look atan example. Fits, youl create a window with a Labet widget that holds a numeric value. You'l put
buttons on the let and right side ofthe label. The left button will be used to decrease the value in the Late, and the
Fight one will increase the value. Here’ the code for the window:Python
ngort tkinter 98 th
window = 80)
window. cocontigure(®, insize-S0, welght-2)
‘endow colunneantigure([2, 1, 2], aineize-50,
ehe-2)
btn decrease ~ tk.autton(naster-window, text="-")
berasecrease.grie(rom®, colum-8, sticky="rs0¥")
L_value = th Label (naster-windon text-"0")
1wlyalue.grid(rowe, calum-1)
bun snerease = tk sutton(mastersutndow, texters")
burinerease.gete(non-8, colunn-2, sthcky="rseu")
vindow.naiionn()
The window looks ike tis
With the ap layout defined, you can bring itt life by giving the buttons some commands. Star with the le button,
When this button is pressed, it should decrease the value in the abel by one. In orderto do this, you ist need to get
answers to two questions:
1. How do you get the textin Lave?
2,How do you update the text in taber?
Label widgets don't have .gee() like cntey and Text widgets do, However, you can retrieve the text from the label by
accessing the text attribute with adictionary-style subscriat notation
Python
sbel = te tabel texte "Hel o")
text = Label e2"
abel{"text"] = "ood bye"
Now that you know how to get and seta label’ text, write an increase) function that increases the value in
181 vatue by one:
Python
ngort tkinter 95 tk
det snerease()
value = nt(aby vatue( text"})
h_valuet"text™] = #Gvalue + 3)"
‘ncreaso() gets the text from 1b1_value and convert itto an integer with ine(). Then, it increases this value by one
and sets the label’s text attribute to this new value.
Youll also need cecreaset) to decrease the value in alve_Jabel by one:Python
det decrease)
olue = S9U(aby_vatue( text")
abl yalue( text) = #(vatue = 23°
Put increasa() and decrease) in your code just after the import statement
To connect the buttons to the functions assign the function to the button's comand attribute. You can do this when
you instantiate the buttons. For example, update the twa lines that instantiate the buttons t the fallowing:
Python
btn decrease ~ tk.avtton(nastercuindoe, tent="-", conmand-decrease)
beradecrease.grie(ron8, colum-6, sticky nse")
abl yatue = tk Lave (nastersuindow, text="0")
tyalue.grsa¢row-e, colun-3)
bur snerease = te sutton(nast eeomand- Increase)
bur_inerease.geig(non, colunn-2, stichy="rseu")
window nainioon()
That’ all you need to do to bind the buttons to increase and cecrease() and make the program functional. Try
saving your changes and running the application! Click the buttons to increase and decrease the value in the center
of the window:
Here's the fll application code for your reference:
Counter Application Full Source Code Showide
This app isn't particulary useful, bu the skls you Leamed here apply to every app you'll make:
+ Use widgets to create the components ofthe user interface.
+ Use geometry managers to control the layout ofthe application.
+ Write event handlers that interact with various components to capture and transform user input
In the next two sections, you'l build more useful apps. ist, youl buld a temperature converter that converts 2
temperature value from Fahrenheit to Celsius. After that, youll build a text editor that can open, edt, and save text
files!
Check Your Understanding
‘Expand the code block below for an exercise to check your understanding:
Exercise: Simulate rollinga six-sided die Showpide
You can expand the code block below to seea solution:Solution: Simulate rolling a six-sided die Showitide
When you're ready you can move an to the next section
Building a Temperature Converter (Example App)
In this section, youl build a temperature converter application that allows the use to input temperature in
{degrees Fahrenheit and push a button to convert that temperature to degrees Celsius. You'll walkthrough the code
step by step. You can alo find the full source code atthe end ofthis section for your reference
Note: To get the most out of this section follow along ina Python shel.
Before you start coding, youl frst design the app. You need three elements
1. entry: A widget called ent_tenperature for entering the Fahrenheit value
to display the Celsius result
3, autton: A widget called ben_convort that reads the value from the Entry widget, converts from Fahrenheit to
2, abel: A widget called 1
Celsius, and sets the text ofthe Label widget to the result when clicked
You can arrange these ina grid with a single row and one columa for each widget. That gets you a minimally working
application, butt isnt very user-Wiendly. Everything needs to have labels
Youll puta abel directly to the right ofthe ent_tenperature widget containing the Fahrenheit symbol") so that the
User knows thatthe value ent_tenperature should be in degrees Fahrenheit To do this, set the label text to
‘\MEGREE FakRENvExT)", which uses Python's named Unicode character sunport to display the Fahrenheit symbol
You can gve bin convert alittle lairby setingits text to the value “\NCRZGiTARas BLACK At804)*, which displays 9
black arow pointing tothe right. Youll also make sure that 2b1_result always has the Celsius symbol 'C following
the label text“ Wcoronce ceLstusy" to indicate that the results in degrees Celsius, Here's what the final window will
look tke:
fe = x
a
Now that you know what widgets you need and what
First, import skinter and create a new window
he windowis going to look like, you can star coding it up!
bython
vendo = TKO)
seindou-tiele("Tenperature Converter")
‘endow resizanle(aietn-fatse, hesphtFatse)
window. tisie() sets the tte ofan existing window, while windos.nestzabie() with both arguments set to False
makes the window havea fixed size. When you Finally run this application, the window will have the text
reate the ont_tenpersture widget with a label called b1_tenp and assign
Temperature Converter in ts tte bar Next,
both toa Frane widget called fon_entry
Python
fem.entey = Frane(mastersutndon)
fent_tunperature = Uk entry(naster-frm entry, wlethete)
l_tens = th Label(nasterston.entry,, Cexte"\M(OEGREE FREMMEDT}")
The user wil enter the Fahrenheit value in ent_tenpersture, and 161 tenis sed to label ent_terperature with the
Fahrenheit symbol. The #rn_entry container groups ent_tenperature and 1b3_tenp togetherYou want 1b1_tew tobe placed crectly tothe right of ent_sewoersture. You can lay ther out in fon_entry using the
aria() geometry manager with one row and two columns:
Python
ert temperature. grie(ron, columone, stieaye"e")
latens.gris(eow-8, colunn-a, stlegy-'
‘You've set the sticky parameter to “efor ent_tenpenature so thatit always sticks to the rightmost edge ofits rid
cell You also set st icky to “w” for ib_tenp to keep it stuck to the leftmost edge of its grid cel. This ensures that
1b1_sonpis alvays located immediately ta the right of ent_tenperatur,
"Now, make the ben_convert and the 1b_reslt for converting the temperature entered into ent_tewwerature and
Aisplaying the results:
Python
btn convert = tk.auttan(
raster-window,
ont="WU(RIGSTIBADS LR A206)”
>
IL pesult = tk Labelinasterandon, text-P\ACOEGREE CELSTUS)")
Like ¢ra_entey, both btx_cenvert and 18} result are assigned to window. Together, these three widgets make up the
thee cells in the main application grid. Use .gta) to go ahead and lay them out now
Python
fementry.grid(ront, colum-t, paée-18)
ber_cowert.gric(rov-, column-1, 936y-20)
l_pesule.gridtrowe, colunn-2,_padr10)
Finally, run the application
Python
veindow nainioon()
That looks great! But the button doesnt do anything just yet At the top of your script fle, just below the import line,
dé 2 function called fahrenhett_t0,celstus(y:
Python
det forenest_to_celsius()
sonalt sono Io rosult
anvennese ~ ent_terperature-get()
celsius » (5 / 9) * (loat(f2bremelt) - 52)
wh_resule["text”] = #{rovnalceisius, 2)) W(OFGREE ceLsTUS}*
‘This function reas the value from ent._tenpersture, converts it from Fahrenheit to Celsius, and then displays the
resultin 1st resut,
"Now go down tothe line where you define vtn_convers and setts comang parameter to Fanremnest_to_celstusPython
ben_sonvert = th. uton(
texte" WURIGMTBRDS BLACK AAA)“
That’ it Youve created a full functional temperature converter app in ust twentysh tines of code! Pretty cool,
right?
‘You can expand the code block below to see the fll seri:
Temperature Converter Full Source Code Show/ide
It’s ime to kick things up anoteht Read on to lear how to build text editor
Building a Text Editor (Example App)
In this section, youl build a text editor application that can create, pen, edit, and save text files, There are three
essential elements in the application:
LA utton widget called
2.Asutton widget called
3. ATexcaox widget called txt_eost for creating and editing the text fle
open for opening file for editing
save for saving a fle
‘The three widgets willbe arranged so tha the two buttans are onthe left-hand side ofthe window, andthe textbox
ison the right-hand side. The whole window should have a minimum height of 00 pixels, and txt_eett should have
a minimum width of 600 pixels. The whole layout should be responsive so that the window is resized, then
‘xt_eaits resized 2s well The width ofthe frame helding the buttons should not change, however
Here's a sketch of how the window wil ook
Texr Eorron
Bal
You can achieve the desired layout using the .grid() geometry manager. The layout contans a single row and two
columns
1 Anarrow column onthe left forthe buttons
2.Awider column on the right for the textbox
To set the minimum sizes forthe window and txt_edss, you can set the ninsize parameters ofthe window methods
roucontiguret) and .columcon¢Sgure() to 808. To handle resizing, you can set the wetght parameters ofthese
methods to.