widgetkit
| (require widgetkit) | package: widgetkit |
widgetkit is a curated collection of GUI widgets for Racket. It gathers the controls that almost every racket/gui application wants but that the core toolkit leaves you to build yourself — tooltips and placeholder text, grid layout, date entry, virtualized lists, status bars, spinners and steppers — behind a single (require widgetkit), with one manual and a runnable example per widget.
The design follows two rules:
Curated, not redundant. Every widget fills a gap that core racket/gui leaves open. If the toolkit already does the job well, the widget is not here.
Reuse over rewrite. When a mature upstream package already does the job, widgetkit depends on it and re-exports it; it does not fork. New code is written only where no good solution exists.
The collection has two layers:
Gap-filling widgets (new, MIT, in this repo): status-bar%, spinner%, stepper% (plus the clamp helper).
Aggregated widgets (re-exported from mature upstream packages): the cue-mixin, tooltip-mixin and validate-mixin text-field enhancers, table-panel%, canvas-list% and date-text-field%.
Larger, heavier-dependency controls (maps, sortable data grids, plots, a web view, a tree) are listed in Recommended companions (install separately) — install them separately on demand.
1 Installation
From a clone of this repository:
(raco pkg install)
Then, in any module:
(require widgetkit)
2 A quick tour
Open "examples/showcase.rkt" for a single window that demonstrates every widget, or run it directly:
racket examples/showcase.rkt
3 Gap-filling widgets
3.1 status-bar%
A compact bottom-of-window bar: a status message plus an optional determinate progress gauge. Core gui ships message% and gauge% but no combined status bar, so this is boilerplate every app rewrites. It subclasses horizontal-panel%, so extra children (e.g. a Cancel button) can be appended.
Constructor:
(new status-bar% [parent parent] [initial-message ""] [show-progress #f])
Methods: (send bar set-message text), (send bar set-progress percentage) (0–100, ignored if the bar has no gauge), (send bar get-message), (send bar clear).
(define bar (new status-bar% [parent f] [show-progress #t] [initial-message "Ready."])) (send bar set-message "Working...") (send bar set-progress 75)
3.2 spinner%
An indeterminate circular activity indicator. Core gui only ships the determinate gauge%; there is no “busy, unknown duration” control. spinner% draws a rotating arc on a canvas driven by a timer.
Constructor:
(new spinner% [parent parent] [diameter 24] [color "dodgerblue"] [track-color "lightgray"] [interval 60])
Methods: (send sp start), (send sp stop), (send sp spinning?).
(define sp (new spinner% [parent f] [diameter 36])) (send sp start) (send sp stop)
3.3 stepper%
A compact [-] value [+] numeric stepper. Core gui has slider% for picking from a range but no small +/- control for numeric tweaks.
Constructor:
(new stepper% [parent parent] [min-value 0] [max-value 100] [step 1] [initial 0] [callback (λ (self) (void))] [show-value #t])
Methods: (send st get-value), (send st set-value v), (send st increment), (send st decrement). Values are clamped to [min-value ,max-value] using the exported clamp helper.
(new stepper% [parent f] [min-value 0] [max-value 12] [initial 1] [callback (λ (self) (printf "qty: ~a\n" (send self get-value)))])
3.4 disclosure%
A collapsible section: a header button toggles the visibility of a content panel. Add the collapsible children to the panel returned by get-content.
(define d (new disclosure% [parent f] [label "Advanced options"] [expanded? #f])) (new check-box% [parent (send d get-content)] [label "Verbose logging"])
Methods: (send d get-content), (send d is-expanded?), (send d set-expanded! bool).
3.5 image-view%
A canvas that displays a bitmap%, centered and scaled to fit (or at a fixed numeric scale). core gui has canvas% but no ready-made widget to just show an image.
(new image-view% [parent f] [bitmap some-bitmap%] [scale 'fit]) (define iv (new image-view% [parent f])) (send iv load-file "photo.png")
Methods: (send iv set-bitmap b), (send iv load-file path), (send iv get-bitmap).
3.6 progress-dialog%
A modal dialog showing a message and a determinate gauge, with an optional Cancel button. Drive it from a worker thread while (send pd show #t) runs the modal event loop; update the UI via queue-callback and close with (send pd show #f). See "examples/progress-dialog-demo.rkt" for the full pattern.
(define pd (new progress-dialog% [parent f] [label "Working..."])) (void (thread (λ () ... (queue-callback (λ () (send pd set-progress n))) ... (queue-callback (λ () (send pd show #f)))))) (send pd show #t)
Methods: (send pd set-progress n), (send pd set-message s), (send pd cancelled?).
3.7 notification-banner%
A transient, dismissible message strip (a “toast”/banner) with a severity (info/success/warning/error), pinned to the top of a window. It collapses when dismissed (click near its right edge) or after an auto-dismiss timeout. Use it instead of a modal message-box when you just want to flash a non-blocking result.
(define nb (new notification-banner% [parent f])) (send nb show-message "Saved." 'success 3000) (send nb show-message "Check input." 'warning #f)
Methods: (send nb show-message text severity auto-dismiss-ms) (pass #f for auto-dismiss-ms to keep it up), (send nb hide), (send nb current-message).
3.8 log-view%
A scrolling, read-only, monospace log/console output that stretches to fill its parent, auto-scrolls to the newest line, accepts append-line while staying read-only, and trims old lines past max-lines. Building this from raw editor-canvas% + text% is where most people get stuck (the canvas does not stretch inside a pane%; auto-scroll and read-only-with-programmatic-appends both need care).
(define log (new log-view% [parent f] [max-lines 5000])) (send log append-line "[boot] ready")
Methods: (send log append-line s), (send log clear), (send log get-text), (send log scroll-to-bottom).
3.9 split-view%
Two panes separated by a draggable divider (Qt’s QSplitter / GTK’s GtkPaned). Add children to (send sv get-first) and (send sv get-second); the divider is mouse-draggable; set-fraction sets the first pane’s share in 0..1.
(new split-view% [parent f] [orientation 'horizontal] [fraction 0.4])
3.10 toolbar%
A fixed-height row of action buttons with separators. Callbacks are no-argument thunks; add-button returns the created button% and add-separator the separator canvas. Any other widget can be added with [parent tb].
(send tb add-button "Open" (λ () ...)) (send tb add-separator)
3.11 search-field%
A “Search…” box firing a one-argument (λ (query) ...) callback on every keystroke and on clear.
(new search-field% [parent f] [callback (λ (q) (filter-items q))])
3.12 stack%
Shows one of several pages at a time (QStackedWidget). Pair it with a choice% or tab-panel% for working switched content; this sidesteps the tab-panel%-has-no-callback trap.
(define pages (new stack% [parent f])) (define p0 (send pages add-page)) (send pages show-page 0)
4 Aggregated widgets
These are re-exported from their upstream packages; see each package’s own documentation for the full API.
4.1 Tooltips & cue text
From the gui-widget-mixins package (Apache-2.0 OR MIT). Core gui has no tooltips and no placeholder text for text-field%.
(new (cue-mixin "" (tooltip-mixin text-field%)) [parent f] [label "Name:"] [cue "Enter your name"] [tooltip "Your full name"])
cue-mixin takes a default cue string and a base class; tooltip-mixin takes a base class. validate-mixin adds a validation callback. decorate-mixin / decorate-with compose several enhancements.
4.2 table-panel%
From the table-panel package (LGPL-2.1). A panel that aligns its children to a grid — core gui has only horizontal/vertical panels.
(define g (new table-panel% [parent f] [dimensions '(4 2)])) (for ([l '("Name:" "Value:" "Unit:" "Note:")]) (new message% [parent g] [label l]) (new text-field% [parent g] [label #f]))
4.3 canvas-list%
From the canvas-list package (MIT). A fast, single-selection, virtualized list that renders only the visible rows and supports custom per-item drawing. Core list-box% cannot virtualize very large lists or custom-draw items.
(new canvas-list% [parent f] [items (for/vector ([i (in-range 1 2000)]) (format "Item ~a" i))] [item-height 22] [action-callback (λ (canvas item event) (printf "picked ~a\n" item))])
4.4 date-text-field%
From the text-date package (MIT). A text-field% for entering dates (dd.mm.yyyy): shows today’s date as faded cue text when empty and filters input to digits and dots. Core gui has no date entry widget.
(new date-text-field% [parent f] [label "Date:"])
5 Consistency wrappers
These wrap the aggregated widgets to hide their API footguns behind a single, consistent class.
5.1 labeled-field%
A text-field% with cue (placeholder) and tooltip already mixed in, so you do not have to remember that cue-mixin takes two arguments and must be composed with tooltip-mixin.
(new labeled-field% [parent f] [label "Name:"] [cue "Enter your name"] [tooltip "Your full name"])
5.2 text-list%
A canvas-list% for a list of items rendered as text, with a one-argument action callback instead of the underlying three-argument one.
(new text-list% [parent f] [items (vector "a" "b" "c")] [action (λ (item) (printf "picked ~a\n" item))])
6 Recommended companions (install separately)
These heavier controls are deliberately not hard dependencies, to keep (require widgetkit) light. Install the ones you need:
Control | Install |
Interactive OSM map |
|
Sortable multi-column data grid |
|
Spreadsheet editor |
|
Embed plot snips in a window |
|
Web view (Chromium / native) |
|
A tree / outline view already ships with Racket as mrlib/hierlist — no install needed.
7 Roadmap
Planned future additions (only where no mature solution exists): a collapsible “disclosure” section, a draggable split view, a calendar, a dedicated color picker, a segmented control, and a small toolbar helper.