Textbox (Entry) in Tk (tkinter)

A textbox lets the user enter any one-line text. In Tk it is represented by the ttk.Entry class, which inherits the features of a more primitive widget called tk.Entry.

To create a textbox let's first create an instance of the ttk.Entry class.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.config(width=300, height=200)
# Create the textbox.
entry = ttk.Entry()
# Place it within the window.
entry.place(x=50, y=50)
root.mainloop()

This code creates the following interface:

/images/textbox-entry-in-tk-tkinter/tk-entry.png

To specify the text alignment, we use the justify param. Valid values for this param are tk.LEFT (default value), tk.RIGHT and tk.CENTER.

# Right justify text.
entry = ttk.Entry(justify=tk.RIGHT)

We can force Tk to show a custom glyph when we want to hide the text; for example, when the widget is used to enter a password.

# Show asterisks instead of the original text.
entry = ttk.Entry(show="*")

Through the width param we indicate the widget width, although not in pixels, but in characters. For example, the following code establishes enough width to view a 10-characters line completely.

entry = ttk.Entry(width=10)

If the text exceeds the specified amount of characters, the widget always shows a piece of the text (as long as width) based on the cursor position. Since the width of each character might change even in the same typography, the width value is always an approximate value, not an absolute one.

A textbox might be created as disabled (grayed out and the user can't type in it) using the state param.

entry = ttk.Entry(state=tk.DISABLED)

We can enable it later by establishing again this param via the config() method.

entry.config(state=tk.NORMAL)

An intermediate state is "readonly", in which the user can see the widget but can not type in it.

entry = ttk.Entry(state="readonly")

This is specially useful when we want to disable text entering but nevertheless keep copying options or contextual menus.

A textbox can take focus when the user successively presses the Tab key and passing through the multiple widgers in our window. If we want to prevent our textbox from taking focus this way, we use the takefocus argument.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.config(width=300, height=200)
entry = ttk.Entry()
entry.place(x=50, y=50)
# This second textbox cannot take focus via the Tab key.
entry2 = ttk.Entry(takefocus=False)
entry2.place(x=50, y=150)
root.mainloop()

Reading and Writing

Once the textbox is created, we can execute the following operations: insert, get, select, and delete text. From these, the most used is the second one, since it let us know what the user of our application has typed in.

So let's begin by fetching what the user has typed inside the textbox using the get() method.

print(entry.get())

For example, the following code outputs the typed text when the user presses a button.

entry.insert(0, "Hello world!")
entry.place(x=50, y=50)
button = ttk.Button(text="Get text", command=lambda: print(entry.get()))
button.place(x=50, y=100)

Inversely, to write text we use insert(), that takes a position as the first argument and a regular string as the second one.

entry.insert(0, "Hello world!")

This is similar to:

entry.insert(0, "Hello")
entry.insert(5, " world!")

Every Tk function that requires a position will accept the tk.END constant, used to represent the end of the text. So here tk.END equals len(entry.get()). For this reason the following code also gets the same result as the previous ones.

entry.insert(0, "Hello")
entry.insert(tk.END, " world!")

We can delete a text or a piece of it by using the delete() method, which receives as arguments the indexes of the range of characters we want to delete.

# Deletes the whole text.
entry.delete(0, tk.END)

In the same way works select_range(), that selects the text from one position to another one. For example, the following code selects "world".

entry.insert(0, "Hello world!")
# Select from the sixth character to the eleventh.
entry.select_range(6, 11)
# Send the focus to the textbox to make effective
# the selection.
entry.focus()

To get the cursor position within the textbox, we call the index() method with the tk.INSERT constant.

print(entry.index(tk.INSERT))

And to set the position of the cursor:

entry.insert(0, "Hello world!")
# Sets the cursor before the "w".
entry.icursor(6)
# Sends the focus.
entry.focus()

Tk has no specific function to return the selected text, but by using the index() method with the tk.SEL_FIRST and tk.SEL_LAT constants (which retrieve the start and end indexes of the selection) we can manually build it.

entry.insert(0, "Hello world!")
def get_selection():
    # First check there's a selection.
    if entry.select_present():
        # Get the selection start and end indexes
        first = entry.index(tk.SEL_FIRST)
        last = entry.index(tk.SEL_LAST)
        print(entry.get()[first:last])
    else:
        print("There is no selection.")
button = ttk.Button(text="Get selection", command=get_selection)

The select_present() method returns a boolean that indicates where there is a selection at all.

Linking a variable

When a textbox is simply employed to receive a text entered by the user, then it will be enough to call the get() method to obtaint the text when we need it, as previously exposed. But when our application requires to both read the user input and write new text into the textbox very often, then it would be more suitable to link a variable.

Tk provides the tk.StringVar() to create objects that act like a string, but in order to assign or read a value we need to use the set() and get() methods.

var = tk.StringVar()
var.set("Hello world!")
print(var.get())

We can link one of these variables to a textbox when creating an instance of ttk.Entry via the textvariable param.

entry_var = tk.StringVar()
entry = ttk.Entry(textvariable=entry_var)

This way, every call to entry_var.set() will modify the textbox content, and inversely, changes made by the user in the widget will alterate the result of entry_var.get().

Font

It is possible to configure the font of a textbox via the font parameter. For example, the following code creates a textbox with a font of the Times family and a size of 14 points.

import tkinter as tk
from tkinter import font, ttk
root = tk.Tk()
root.config(width=300, height=200)
entry = ttk.Entry(font=font.Font(family="Times", size=14))
entry.place(x=50, y=50)
root.mainloop()
/images/textbox-entry-in-tk-tkinter/ttk-entry-font.png

The font argument used when creating the textbox must receive an instance of the tkinter.font.Font class. Tk supports a large number of font families. To see a full list of possible values for the family argument, run the following code in the Python shell:

>>> import tkinter as tk
>>> root = tk.Tk()
>>> font.families()  # Returns a list of available fonts.

Other acceptable arguments for font settings are weight, slant, overstrike and underline:

entry = ttk.Entry(
    font=font.Font(
        family="Courier",
        size=14,
        weight=font.BOLD,
        slant=font.ITALIC,
        overstrike=True,
        underline=True
    )
)

Styles

The rest of the appearance of a textbox can be configured through styles. For an introduction to how styles work, see https://tkdocs.com/tutorial/styles.html.

The following code creates a style for a textbox and sets the foreground and fieldbackground properties, which represent the text color and background color, respectively.

import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.config(width=300, height=200)
style = ttk.Style()
style.configure(
    "MyEntry.TEntry",
    # Red background.
    fieldbackground="#ff0000",
    # Blue text color.
    foreground="#0000ff"
)
entry = ttk.Entry(style="MyEntry.TEntry")
entry.place(x=50, y=50)
root.mainloop()

Colors are indicated using the RGB notation in hexadecimal or HTML format.

Note that certain operating systems (especially Windows) ignore the fieldbackground property, making it impossible to customize the background color of the textbox using this method. Here's what the same code looks like on Ubuntu and Windows:

/images/textbox-entry-in-tk-tkinter/ttk-entry-blue-text-ubuntu.png/images/textbox-entry-in-tk-tkinter/ttk-entry-blue-text.png

The appearance of the selected text can also be configured:

style.configure(
    "MyEntry.TEntry",
    # Background color of the selected text.
    selectbackground="#87F6F9",
    # Color of the selected text.
    selectforeground="#ff0000",
    # Width of the selected text's border.
    selectborderwidth=2
)
/images/textbox-entry-in-tk-tkinter/ttk-entry-selection.png

As well as the color and thickness of the cursor (the one that indicates where the focus is within the text):

style.configure(
    "MyEntry.TEntry",
    # Cursor color.
    insertcolor="#FF46FF",
    # Width in pixels.
    insertwidth=3
)
/images/textbox-entry-in-tk-tkinter/ttk-entry-cursor.png

Lastly, you can alter the space (in pixels) between the text and the box margins via the padding argument:

style.configure(
    "MyEntry.TEntry",
    # Space between the textbox margins and the text
    # itself (in pixels.)
    padding=10
)
/images/textbox-entry-in-tk-tkinter/ttk-entry-padding.png

Styles in tk.Entry

New applications should always use the ttk.Entry class. But if you're upgrading old Tk code that still uses the classic tk.Entry widget, since it doesn't support styles, you'll need to configure its appearance by passing arguments when creating the textbox.

For text and background colors, use the foreground and background arguments, respectively:

import tkinter as tk
root = tk.Tk()
root.config(width=300, height=200)
# Note tk.Entry instead of ttk.Entry.
entry = tk.Entry(
    # Background color.
    background="#ff0000",
    # Text color.
    foreground="#0000ff",
)
entry.place(x=50, y=50)
root.mainloop()

To configure the cursor and the selected text appearance (color and thickness of the selection), the arguments are the same as those used with styles:

entry = tk.Entry(
    # Cursor color.
    insertbackground="#00ffff",
    # Cursor width in pixels.
    insertwidth=3,
    # Background color of the selected text.
    selectbackground="#87F6F9",
    # Color of the selected text.
    selectforeground="#ff0000",
    # Width of the selected text's border.
    selectborderwidth=2
)

In the classic widget it is also possible to configure the border color and thickness:

entry = tk.Entry(
    # Border color when the textbox has focus.
    highlightcolor="#008000",
    # Border color.
    highlightbackground="#ff0000",
    # Border width (in pixels).
    highlightthickness=3,
)

The highlightbackground argument indicates the color of the textbox border when focus is absent, while highlightcolor indicates the color when the widget has focus.