Release notes#
Notable changes to the tkinter-icons base package, newest first. The project follows Semantic Versioning; the full file lives at CHANGELOG.md.
Each icon pack keeps its own changelog, since a pack changes when its upstream font does rather than when this package does. They are linked from Icon packs.
[5.0.0] — renamed to tkinter-icons, rebuilt around measured glyph ink#
ttkbootstrap-icons is now tkinter-icons. Bootstrap icons were built
directly into ttkbootstrap, so this library is no longer the way to get icons
for ttkbootstrap — it is for people on raw tkinter, and for people who want an
icon set other than Bootstrap. The name now says that.
Installing ttkbootstrap-icons still works. It becomes a forwarding shim that
depends on tkinter-icons and re-exports everything, including submodules, so
from ttkbootstrap_icons.icon import Icon keeps working. It warns once on
import and will not be updated again.
pip install "tkinter-icons[material]"
from tkinter_icons import MaterialIcon
Added#
Sixteen icon packs are now extras of one library. Each pack is still its own distribution — it has to be, since each ships a font — but you no longer install them by name.
pip install "tkinter-icons[material]"pulls in the right one, and two are named together astkinter-icons[material,simple]. Asking for a pack that is not installed raises with the exact install command for it. (#69)Icon.render_pil(), a headless entry point. It returns a PIL image and touches no Tk, so icons can be rendered in a test suite, a build step, or any process without a display. (#67)RenderOptions, carrying every drawing knob as one immutable value. Size, color, padding, rotation, flip, and oversampling travel together instead of living as mutable class state onIcon. (#67)IconSet, one immutable object per provider and style, holding the font bytes, the glyph map, the ink metrics, and the default options. (#67)python -m tkinter_icons.tools.generate_metrics, which measures and verifies glyph ink bounds.--allregenerates every installed pack,--checkverifies without writing, which is what CI runs to catch drift in the committed metrics. (#67)
Changed#
Glyphs are centered on measured ink, not on
font.getbbox(). Pillow’sgetbbox()under-reports ink on icon fonts, which left full-bleed icons with no padding at all and nudged everything else off center. Each glyph’s true ink is now measured once at 512px and shipped with its pack as em-fraction bounds inmetrics.json. A pack without metrics falls back togetbbox, so old packs still render. (#67)The Bootstrap
y_biasfudge was removed. It existed to cancel thegetbboxskew; against real ink metrics it visibly pushes glyphs low. (#67)An odd size snaps up to the next even one.
size=15renders at 16px. Half-pixel geometry is what produced the soft LANCZOS edges at fractional display scaling.icon.rendered_sizereports what was actually drawn, and it is part of the cache key. (#67)The drawing internals are public.
render.pyis pure PIL and imports no Tkinter;icon.pyis the only Tk-facing layer. SubclassingIconto change how something draws is no longer the only way in. (#67)Entry-point discovery scans both provider groups. A pack published against either
ttkbootstrap_icons.providersortkinter_icons.providersis found, so upgrading the base package with old packs installed does not silently lose every icon set. (#75)
Fixed#
Image caches are scoped to the Tk interpreter and dropped when its root is destroyed. A
PhotoImagebelongs to the interpreter that created it, so a process-wide cache handed out dead handles as soon as a root was replaced — which is what happened in test suites and in any app that tears a window down and builds another. (#68)A stateful icon releases its widget bindings. Icons bound to widget state kept the widget, its images, and its theme-change binding alive after the widget was gone. (#68)
The pack asset runner no longer stops on a pack with nothing to build.
bshas notools/generate_assets— its assets were vendored, not generated — and the runner treated that as a failure rather than a skip. (#77)render_pilworks on a pack’s icon class without a warm-up. It readIcon._icon_set_current, aClassVarshared by every subclass, soMaterialIcon.render_pil("home")drew a Material icon only if something had already constructed one — and raisedRuntimeErrorin a fresh process, which is exactly how a test suite or a build step would call it. A pack now names its own provider throughIcon.provider_class, andrender_pilresolves friendly names the way the constructor does. The baseIconhas no pack of its own, so it raises in a fresh process and otherwise falls back to whichever set was loaded last.Every pack’s icon class accepts
options.RenderOptionswas public API and the documented way to change how an icon draws, reachable only throughIcon.render_pilor the baseIcon— never through the sixteen classes anyone actually constructs. It is keyword-only, so it cannot be confused withstyle.PyInstaller finds the bundled hooks by itself. The package shipped hooks but never registered them, so PyInstaller had no reason to look in
_pyinstaller/and every frozen application needed an explicithookspath. Apyinstaller40entry point now points atget_hook_dirs, which is what the documentation had always described. Two packs also had no hook file at all —bsandfluent-reg— so a frozen application using Bootstrap or Fluent (Regular) icons shipped without their fonts. All three failures were silent by construction: a glyph with no font renders transparent, so the application started normally and drew nothing.
Removed#
Only the icon browser is published as a command. The base package installed
tkicons-build-allandtkicons-metrics, and each pack installed its owntkicons-<pack>-buildandtkicons-<pack>-quick— twenty-eight commands across fourteen packs. They regenerate assets and metrics into a source tree, so they do nothing useful from an installed wheel, andgenerate_metricswould have written into site-packages. Maintainers run them withpython -m.tkinter-iconsremains. (#79)The
toolsmodules no longer ship in any wheel. Auto-discovery had been sweepingtkinter_icons_<pack>.toolsinto all sixteen pack wheels, andtkinter_icons.toolinginto the base — upstream-scraping asset generators that no user can run and that nothing imports at runtime.toolingmoved undertkinter_icons.toolswith the rest. (#79)The
[all]extra. The sixteen sets serve disjoint purposes — brand marks, developer logos, fantasy glyphs, weather symbols — so no application draws from all of them, and installing every one cost about 22 MB of fonts and JSON on disk to get fifteen icon sets nobody opens. That is the bundling extras exist to avoid. Name the one or two you need. (#79)BaseFontProvider,ProviderRegistry, andload_external_providersare no longer re-exported from the package root. They define an icon set rather than use one, and sat besideMaterialIconas though the two were the same kind of thing. Import them fromtkinter_icons.providersandtkinter_icons.registry— which is how all sixteen packs already do. (#79)
[4.0.0] — the base package no longer ships icons#
Changed#
Bootstrap icons moved out of the base package into their own
ttkbootstrap-icons-bsdistribution, making the base package fully provider-agnostic. This is breaking: an install that relied on Bootstrap being built in needs the pack added.Asking for a provider that is not installed says how to install it, rather than failing on an empty registry.
Added#
ttkbootstrap-icons-fluent-reg, packaging the regular weight of Fluent System Icons separately from the filled set.
Fixed#
Package data and license references that resolved on a working tree but not in a built wheel.
[3.2.0] — cache keys#
Changed#
The image cache key is a hash rather than a concatenation of subclass names, which could collide.
[3.1.2] — Python 3.10#
Fixed#
typing-extensionsis a dependency, so Python 3.10 installs work.
[3.1.1] — theme changes#
Fixed#
Stateful icons follow a theme change instead of keeping the colors of the theme they were created under. (#54)
[3.1.0] — stateful icons#
Added#
StatefulIconMixin, which maps an icon to a widget’s ttk state so it recolors on hover, press, and disable along with the widget.
Fixed#
Multi-state ttk foreground maps parse correctly, including compound states such as
pressed !disabled.A widget with no existing image map no longer raises when an icon is attached to it.
The fallback state color is the normal foreground rather than black.
[3.0.1] — provider asset fixes#
Fixed#
Invalid icon references in several providers. (#46)
Font Awesome’s generated glyph map covers the brands and regular styles, not just solid. (#48)
[3.0.0] — one provider API#
Changed#
Every provider was rewritten against a single API. Names, styles, and display names resolve the same way everywhere, whether the style is passed as an argument or carried in the name. (#31)
Font scaling and padding are standard parameters across all providers.
Added#
Typicons and Meteocons packs. (#12, #19)
Documentation site and per-provider metadata, with a visual test per pack. (#32, #34)
[2.1.0] — more packs, typed styles#
Added#
Eva Icons, RPG Awesome, and Devicon packs. (#10, #15, #17)
Type hints for style arguments. (#21)
Fixed#
Fluent style naming. (#23)
[2.0.0] — packs became separate distributions#
Changed#
The project was restructured so each icon set is its own installable package, discovered through entry points, instead of everything living in one distribution.
Added#
Font Awesome, Material Design Icons, Remix, Ionicons, Fluent System Icons, Simple Icons, Weather Icons, Lucide, and Google Material Icons packs. (#1–#9)
Multi-style icon support, for fonts shipping more than one weight.
PyInstaller hooks for the pack subpackages.
Fixed#
Icons are no longer clipped at their bounding box.
[1.0.0] — initial release#
Font-based Bootstrap icons for Tkinter and ttkbootstrap, rendered to Tk-compatible images.