Window Icon in Tk (tkinter)
Both main windows (created via the tk.Tk
class) and child windows (tk.Toplevel
) have the Tcl/Tk logo icon by default. Setting custom window icons will give our application a more professional look. A window icon is also often displayed by the operating system on the taskbar or application bar. In this post we will see the various ways for configuring window icons on the different platforms supported by Tk (Windows, Linux and Mac).
Tk window objects provide three methods to set an icon:
iconbitmap()
iconmask()
iconphoto()
The iconmask()
function has the goal of allowing transparent areas in our window icon. However, the various image formats (PNG, GIF, JPG, etc.) and icon formats (especially .ico
) have long supported transparency. Therefore, in most cases iconmask()
is unnecessary. If we have our application icon in an image file, the easiest way to load it into the window is via iconphoto()
:
You can download our test icons from here to run the code in this post. It is a ZIP file that contains:
File |
Preview |
Notes |
---|---|---|
|
16x16 px |
|
|
32x32 px |
|
|
Contains both 16x16 and 32x32 icons. Windows only. |
The icons must be in the same folder (or the current working directory) as our program.
After running the code, we get the following result:
The code is simple: we load an image file via the tk.PhotoImage
class and then assign it as the window icon via the iconphoto()
method. The first argument is a boolean indicating whether that same icon should be applied to child windows. This procedure of loading the window icon from an image file is supported by all operating systems.
In addition to being displayed on the window, the icon is also often displayed on the task or application bar. Generally, the proper size for the window icon is 16x16 pixels. We'll call this image the "small icon." Instead, a "large icon" is displayed on the taskbar, which in Windows is usually a 32x32 image. These values may change, however, according to the display settings of each system. Since we have loaded a small icon, we will see that the operating system automatically enlarges the 16x16 image on the taskbar, producing a pixelated effect:
If we load a large icon instead of a small icon, it will look fine on the taskbar, but still pixelated on the window or title bar. Fortunately, the iconphoto()
method can receive two icons of different sizes (a small and a large one) to display properly in one case and the other:
In this way, the operating system shows the large icon on the taskbar and the small icon on the window:
Note that we have changed the first argument of iconphoto()
from True
to False
, since, for some unknown reason (perhaps a Tk bug), if the first argument is True
, in Windows the small icon is ignored and the large one is shown both in the window and in the taskbar. Similarly, some operating systems consider only the large icon (and there's really nothing we can do to change this).
Image sizes may vary, as long as one icon is larger than the other. The small icon could be 24x24 and the large one 64x64, or any other combination. The ideal sizes for each context (the window's titlebar or the system taskbar) depend on the operating system and, in Linux distributions, on each particular distribution. On Ubuntu, for example, the ideal size for the large icon is 64x64. On Windows, the appropriate sizes are generally 16x16 and 32x32, as we have been using them.
On Windows we can also use the iconbitmap()
method to set the icon of the window from an .ico
file. This Microsoft format is more convenient because it allows you to have multiple images of various sizes (16x16, 32x32, 64x64, etc.) embedded in a single .ico
file. Some programs to create and edit this type of file are Greenfish Icon Editor (free) and icofx. Thus, for example, the following code sets the icon.ico
file (available in the download above) as the window icon:
|
import tkinter as tk
|
|
|
|
root = tk.Tk()
|
|
root.title("Window With Icon")
|
|
root.geometry("300x200")
|
|
root.iconbitmap("icon.ico")
|
|
root.mainloop()
|
Since the icon.ico
file contains a 16x16 image and a 32x32 image, the small icon is automatically displayed in the window and the large icon is automatically displayed in the taskbar.
Packing Icons Into an Executable File¶
The above codes require icons to be present in the file system in order to loaded into the window. However, if we pack our GUI application into an executable file using tools like PyInstaller or cx_Freeze, we may want the executable to have no dependencies, so it can be moved from one place to another without having to carry around a bunch of files. Or maybe we just don't want to have to distribute our icons as separate files. In these cases, where do we load the icon from? There are two solutions for this.
If our application is only targeting Windows systems, then packing the icons into the executable is very easy because Tk supports loading icons directly from executable files (.exe
) via iconbitmap()
. Suppose we convert our code to an executable using PyInstaller:
pyinstaller --icon=icon.ico --noconsole app.py
app.py
is the name of our Python file, --noconsole
indicates that it is a desktop application, --icon
passes the name of the .ico
file that we want to include in the final executable.
Now we can use the following code to load the icon packed inside the Windows executable into the window:
On Windows, the iconbitmap()
method also accepts as an argument, in addition to a .ico
file, a .exe
file whose icon you want to use as window icon. Since sys.executable
contains the path of our executable, by passing it as an argument we always load the icon from the executable, without the need to ship .ico
or .png
files separately. Note that this procedure implies that when the code is executed from the .py
file, the window receives the Python icon, since sys.executable
contains the path of the interpreter.
A second, less elegant, but functional option for all operating systems, is to base64-encode the content of the icons and include them in our source code file. The image data can then be loaded directly from a variable via tk.PhotoImage
. To do this, we first need some code that reads the content of an image and encodes it with Base64. This can be easily achieved with a small Python program:
This little program receives the name of an icon by console, encodes it with base64 and copies it to the clipboard. The Pyperclip module is required (installable via pip install pyperclip
). Now let's start by enocding the small icon by running on the terminal:
python encode_icon.py icon-16.png
Next, let's paste the data copied to the clipboard into a variable and load it via tk.PhotoImage
:
Let's do the same with the large icon:
python encode_icon.py icon-32.png
And finally:
Great! Our icon data is embedded in the code, so there is no need to distribute additional .png
files.