util.actionDialog module¶
A general-purpose popup dialog (ActionDialog) that renders a small,
dependency-free subset of HTML – bold/italic/underline, line breaks, and
<a id="..."> action links – inside a tk.Text widget, and invokes a
caller-supplied callback when an action link is clicked.
Motivating use case: a validation-error popup (eg: for decorators.py’s
error tag) that lists an object’s errors, one per line, each with inline
“Fix” / “Delete” / “Ignore” links – without needing a full HTML rendering
dependency (eg: tkinterweb) or a hand-rolled tag/click-binding scheme
every time such a popup is needed.
Created on Sep 18, 2026
Code author: Rob Kremer <robkremer@me.com>
- util.actionDialog.ActionCallback¶
A zero-argument callback invoked when an action link is clicked.
alias of
Callable[[],None]
- util.actionDialog._STYLE_TAGS = {'b': 'bold', 'em': 'italic', 'i': 'italic', 'strong': 'bold', 'u': 'underline'}¶
Maps the small subset of supported inline HTML tags to the tk.Text tag name that renders them.
- class util.actionDialog._RichTextParser¶
Bases:
HTMLParserParses the small HTML subset ActionDialog understands –
<b>/<strong>,<i>/<em>,<u>,<br>,<ol>/<ul>/<li>, plain text, and<a id="...">label</a>action links – into a flat list of (text, styleTags, actionId) runs.Anything outside that subset (unknown tags, attributes other than id on
<a>) is silently ignored rather than raising: this is meant for small, hand-written strings composed by the caller, not for rendering arbitrary or untrusted HTML documents.- __init__() None¶
Initialize and reset this instance.
If convert_charrefs is True (the default), all character references are automatically converted to the corresponding Unicode characters.
- runs: list[tuple[str, tuple[str, ...], str | None]]¶
Accumulated (text, styleTags, actionId) runs, in document order.
- _styleStack: list[str]¶
- _linkId: str | None¶
- _listStack: list[dict[str, int | str]]¶
One entry per currently-open <ol>/<ul>, innermost last: {“kind”: “ol”|”ul”, “index”: int}.
- _atLineStart: bool¶
Whether the run most recently emitted ended with a newline (or nothing has been emitted yet).
- _emit(text: str, actionId: str | None = None) None¶
- Parameters:
text (str)
actionId (Optional[str])
- handle_starttag(tag: str, attrs: list[tuple[str, str | None]]) None¶
- Parameters:
tag (str)
attrs (list[tuple[str, Optional[str]]])
- handle_endtag(tag: str) None¶
- Parameters:
tag (str)
- handle_data(data: str) None¶
- Parameters:
data (str)
- class util.actionDialog.ActionDialog(parent: Wm, title: str, html: str, actions: dict[str, Callable[[], None]] | None = None, *, closeOnAction: bool = True, width: int = 80, maxHeight: int = 40)¶
Bases:
ToplevelA general-purpose popup dialog that renders a small subset of HTML (bold, italic, underline, line breaks, ordered/unordered lists, and
<a id="...">action links) and invokes a caller-supplied callback when an action link is clicked.Typical use – eg: from decorators.py’s error-tag popup – is to build one html string per object with an
<li>per validation error and a Fix/Ignore/Delete action link at the end of each item, and a matching actions dict mapping each link’s id to the handler that should run when it’s clicked.<li>items need no<br>between them – each one starts its own line automatically, numbered if inside an<ol>or bulleted otherwise:ActionDialog(parent, "Validation errors", "<b>2 errors on 'Foo':</b>" "<ol>" "<li>Missing type — <a id='fix0'>Fix</a> <a id='ignore0'>Ignore</a></li>" "<li>Broken link — <a id='fix1'>Fix</a> <a id='delete1'>Delete</a></li>" "</ol>", actions={ "fix0": lambda: fixMissingType(obj), "ignore0": lambda: ignoreError(obj, 0), "fix1": lambda: fixBrokenLink(obj), "delete1": lambda: deleteError(obj, 1), }, closeOnAction=False) # stay open so the remaining errors can still be acted on
- Parameters:
parent (tk.Misc) – The parent widget this dialog is transient for.
title (str) – The dialog’s window title.
html (str) – The content, in the small HTML subset _RichTextParser understands (
<b>,<strong>,<i>,<em>,<u>,<br>,<ol>,<ul>,<li>, and<a id="...">).actions (Optional[dict[str, ActionCallback]]) – [default: None] Maps each
<a id="...">link’s id to the zero-argument callback to invoke when it’s clicked. A link whose id has no entry here is still rendered (as a link) but is inert when clicked.closeOnAction (bool) – [default: True] If True, clicking any action link closes the dialog immediately after running its callback. Pass False for a dialog meant to stay open across several actions – eg: fixing one error in a list and leaving the rest visible to act on next.
width (int) – [default: 60] The text area’s width, in characters.
maxHeight (int) – [default: 25] The text area’s height is sized to fit its content up to this many lines, then scrolls.
- Return type:
None
- __init__(parent: Wm, title: str, html: str, actions: dict[str, Callable[[], None]] | None = None, *, closeOnAction: bool = True, width: int = 80, maxHeight: int = 40) None¶
- Parameters:
parent (tk.Wm)
title (str)
html (str)
actions (Optional[dict[str, ActionCallback]])
closeOnAction (bool)
width (int)
maxHeight (int)
- _actions: dict[str, Callable[[], None]]¶
- _closeOnAction: bool¶
- _linkTagCount: int¶
- _render(html: str) None¶
Parse html and insert its runs into self.text, giving each distinct action link its own uniquely-named tag (so each link can be bound to, and later look up, its own callback independent of any other link that happens to share the same visible label).
- Parameters:
html (str) – The markup to render – see the class docstring for the supported subset.
- Return type:
None
- _bindAction(tagName: str, actionId: str) None¶
Wire up one action link’s click and hover behaviour: clicking it runs the caller’s callback for actionId (if any was supplied) and then closes the dialog iff self._closeOnAction; hovering it swaps the cursor to a hand to signal it’s clickable.
- Parameters:
tagName (str) – This specific link occurrence’s unique tk.Text tag.
actionId (str) – The id from the
<a id="...">markup, used to look up the callback in self._actions.
- Return type:
None