Declarative UI library built on tkinter
Project description
dkinter
Declarative UI library built on top of Python's tkinter. Describe your UI as a tree of nested descriptor objects instead of calling imperative widget methods.
from dkinter import App, Label, Button, State, PackLayout, PackLayoutItem
count = State(0)
App(
title="Counter",
width=300, height=150,
layout=PackLayout(items=[
PackLayoutItem(widget=Label(text=count, font=("Arial", 24)), pady=20),
PackLayoutItem(widget=Button(text="Click me", on_click=lambda: count.set(count.get() + 1))),
])
).run()
Installation
pip install dkinter
Requires Python 3.10+ and tkinter (included with standard Python on Windows and macOS).
Core Concepts
State
State[T] is an observable value. Bind it directly to any widget property — the UI updates automatically when the value changes.
name = State("World")
label = Label(text=name) # updates whenever name changes
name.set("dkinter") # label text updates immediately
show = State(True)
frame = Frame(visible=show) # hide/show the entire frame
title = State.derived(lambda: f"Hello, {name.get()}!") # computed from other states
Ref
Ref[T] gives you a handle to a live widget after the app is built.
from dkinter import Ref
from dkinter.live import LiveEntry
entry_ref: Ref[LiveEntry] = Ref()
App(layout=PackLayout(items=[
PackLayoutItem(widget=Entry(ref=entry_ref)),
PackLayoutItem(widget=Button(text="Get", on_click=lambda: print(entry_ref.current.value))),
])).run()
Layouts
| Layout | Description |
|---|---|
PackLayout |
Stack widgets top-to-bottom or side-by-side |
GridLayout |
Place widgets in rows and columns |
PlaceLayout |
Absolute or relative positioning |
GridLayout(
column_weights={0: 1, 1: 2},
items=[
GridLayoutItem(widget=Label(text="Name:"), row=0, column=0),
GridLayoutItem(widget=Entry(), row=0, column=1, sticky="ew"),
]
)
Widgets
tk widgets (default)
from dkinter import Label, Button, Entry, Text, Frame, LabelFrame
from dkinter import Checkbutton, Radiobutton, Listbox, Spinner, Canvas, Scrollbar
| Widget | Key params |
|---|---|
Label |
text, font, fg, bg |
Button |
text, on_click, font, fg, bg |
Entry |
on_change, font, fg, bg |
Text |
width, height, on_change, font, fg, bg |
Frame |
layout, bg |
LabelFrame |
text, layout, font, fg, bg |
Checkbutton |
text, on_change, check_bg, font, fg, bg |
Radiobutton |
text, value, check_bg, font, fg, bg |
Listbox |
items, select_mode, on_select, height |
Spinner |
values or from_/to/increment, on_change, wrap |
Canvas |
width, height, on_click, on_mouse_move |
Scrollbar |
orient, target |
ttk widgets (themed)
from dkinter.widgets.ttk import Label, Button, Entry, Checkbutton
from dkinter.widgets.ttk import Combobox, Progressbar, Notebook, Treeview, Menubutton
| Widget | Key params |
|---|---|
Label |
text, font, fg, bg |
Button |
text, on_click, font, fg, bg |
Entry |
on_change, font, fg, bg |
Checkbutton |
text, value, on_change, font, fg, bg |
Combobox |
values, selected, state, on_select |
Progressbar |
value, maximum, mode, orient |
Notebook |
tabs, on_change |
Treeview |
columns, rows, show, on_select |
Menubutton |
text, menu, direction, font, fg, bg |
Note: ttk
font/fg/bgstyling requires a non-native theme on Windows. Addtheme="clam"(or"alt") to yourAppto enable full color control.
App
App(
title="My App",
width=800,
height=600,
resizable=True,
theme="clam", # ttk theme: clam, alt, default, classic
layout=...,
menu=MenuBar(...),
on_close=handle_close,
on_key=handle_key,
on_resize=handle_resize,
).run()
Menus
from dkinter import MenuBar, Menu, MenuCommand, MenuSeparator
App(
menu=MenuBar(menus=[
Menu(label="File", items=[
MenuCommand(label="New", on_click=on_new),
MenuCommand(label="Open", on_click=on_open),
MenuSeparator(),
MenuCommand(label="Exit", on_click=on_exit),
]),
]),
...
)
Dialogs
from dkinter import (
open_file, open_files, save_file, open_directory,
show_info, show_warning, show_error,
ask_yes_no, ask_ok_cancel, ask_retry_cancel,
pick_color,
)
path = open_file(filetypes=[("Text files", "*.txt")])
color = pick_color(initial="#ffffff")
ok = ask_yes_no(title="Confirm", message="Are you sure?")
Canvas
from dkinter import Ref
from dkinter.live import LiveCanvas
canvas_ref: Ref[LiveCanvas] = Ref()
# after app is built:
c = canvas_ref.current
rect_id = c.draw_rect(10, 10, 100, 60, fill="steelblue")
c.make_draggable(rect_id)
c.make_hoverable(rect_id, hover={"fill": "red"}, normal={"fill": "steelblue"})
ttk Checkbutton (two-way binding)
from dkinter.widgets.ttk import Checkbutton
from dkinter import State
checked = State(False)
Checkbutton(text="Enable feature", value=checked, on_change=lambda v: print(v))
# checked.set(True) → checks the box; user click → updates checked
ttk Menubutton
from dkinter.widgets.ttk import Menubutton
from dkinter.menu import Menu, MenuCommand, MenuSeparator
Menubutton(
text="File",
font=("Arial", 10),
fg="#003399",
direction="below", # above | below | left | right | flush
menu=Menu(label="File", items=[
MenuCommand(label="New", on_click=on_new),
MenuSeparator(),
MenuCommand(label="Exit", on_click=on_exit),
]),
)
Widget Common Params
All widgets inherit these from the base Widget class:
| Param | Type | Description |
|---|---|---|
visible |
bool | State[bool] |
Show/hide the widget |
ref |
Ref |
Access the live widget after build |
font |
tuple | str |
e.g. ("Arial", 12, "bold") |
fg |
str |
Foreground/text color |
bg |
str |
Background color |
context_menu |
Menu |
Right-click popup menu |
on_click |
Callable |
Left mouse button |
on_right_click |
Callable |
Right mouse button |
on_double_click |
Callable |
Double click |
on_enter |
Callable |
Mouse enters widget |
on_leave |
Callable |
Mouse leaves widget |
on_focus_in |
Callable |
Widget gains focus |
on_focus_out |
Callable |
Widget loses focus |
on_key |
Callable[[str], None] |
Key pressed while focused |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dkinter-0.1.0-py3-none-any.whl.
File metadata
- Download URL: dkinter-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
202f73223d0479cc41af14f97091f2888bef47dd30a14f5e57ee6b15a11221c1
|
|
| MD5 |
76b65999012cb7d782f5bcbb4c61c759
|
|
| BLAKE2b-256 |
0cb0c98485407f62326b466bb5282eb686f951b5e2c8f1a5863b2bad9bf8d477
|