8.17
gui-easy: Declarative GUIs🔗ℹ
This library provides a declarative API on top of
racket/gui.
1 Quickstart🔗ℹ
1.1 Hello, World!🔗ℹ

The code above describes a view hierarchy rooted in a window that
contains the text “Hello, World!”. By itself, it doesn’t do much,
but you can take it and pass it to render to convert it into
a native GUI:
1.2 Counter🔗ℹ

State in gui-easy is held by observables.
Here we define an observable called @count that holds the
current value of a counter. The two buttons change the value
of the counter when clicked and the text view displays its
current string value via a derived observable. The three widgets are
laid out horizontally by the hpanel.
1.3 Counters🔗ℹ

Since views are at their core just descriptions of a GUI, it’s easy to
abstract over them and make them reusable.
1.4 Dynamic Counters🔗ℹ

Taking the previous example further, we can render a dynamic list of
counters.
Here the @counters observable holds a list of pairs where
the first element of a pair is the id of each counter and the second
is its count. When the “Add counter” button is clicked, a new
counter is added to the list. The list-view renders each
individual counter by passing in a derived observable to its
make-view argument.
1.5 More🔗ℹ
For more examples, see the "examples" directory in the Git repository.
2 Geometry Management🔗ℹ
See Geometry Management in the racket/gui docs for
details on how views get laid out.
Containers, Windows & Dialogs take optional
keyword arguments that allow you to control the #:spacing and
#:alignment of their children and their own
#:min-size, #:stretch and #:margin. All of
these arguments can be passed as either regular values or as
observables, in which case the properties they control will
vary with changes to the observables.
3 Custom Views🔗ℹ
You can create your own views by implementing the view<%>
interface.
As an example, let’s wrap Jeffrey Massung’s canvas-list<%>. I find
it helps to work backwards from the API you’d like to end up with. In
this case, that would be:
(canvas-list |
@entries |
(λ (item state dc w h) |
(draw-item ...)) |
(λ (item) |
(printf "double-clicked ~s~n" item))) |
A canvas-list takes an observable of a list of entries, a
function that knows how to draw each entry to a gui:dc<%> and
a callback for when the user double-clicks an entry. The
canvas-list function should then look something like this:
(define (canvas-list @entries draw [action void]) |
(new canvas-list-view% |
[@entries @entries] |
[draw draw] |
[action action])) |
All it needs to do is abstract over the instantiation of the
underlying view<%>. Next, we can define a skeleton
implementation of canvas-list-view%:
Views must communicate what observables they depend on to their
parents. Since the only dependency a canvas list has is its set of
entries, that’s straightforward:
When a view is rendered, its parent is in charge of calling its
create method. That method must instantiate a GUI
object, associate it with the passed-in parent, perform any
initialization steps and then return it. In our case:
When the observables the view depends on change, its parent
will call its update method with the GUI object that
the view returned from its create method, the
observable that changed and the observable’s value when it changed.
The view is then in charge of modifying its GUI object appropriately.
Windows are a special case: the resources they manage only get
disposed of when renderer-destroy is called, or when the
program exits.
Finally, when a view is no longer visible, its destroy method is typically called to dispose of the GUI object and
perform any teardown actions. In our case, there’s nothing to tear
down so we can let garbage collection take care of destroying the
canvas-list% object:
When the view becomes visible again, its create
method will be called again and the whole cycle will repeat itself.
That’s all there is to it when it comes to custom controls. See the
"hn.rkt" example for a program that uses a custom view.
3.1 Custom Containers🔗ℹ
Containers are slightly more complicated to implement than controls.
They must collect all their children’s unique dependencies and list
them in their dependencies method. Additionally,
their update method is in charge of dispatching
updates to their children.
See "gui-easy-lib/gui/easy/private/view/panel.rkt" for an
example.
4 Escape Hatches🔗ℹ
Some views take a #:mixin argument that can be used to alter
the behavior of the underlying widget. These are intended to be used
as “escape hatches” when the library doesn’t provide a piece of
functionality you need, but that functionality is available on the
native widget.
See "examples/close-window.rkt" for a example of using a mixin to
programmatically toggle a window’s visibility.
5 Reference🔗ℹ
5.1 Renderers🔗ℹ
Renderers convert view definitions to GUI elements.
Renders the view hierarchy represented by view as a child
of parent.
Use this function when you need to embed one or more
view<%>s within an existing racket/gui
application. Otherwise, use render.
Renders the view hierarchy represented by view.
When a parent renderer is provided, renders the view as a
child of the root view of parent. This is useful when you
need to render a modal dialog on top of an existing window.
Renders the popup menu represented by view as a child of
parent.
Returns the root widget of
r. This function is handy when
you need to
embed a
gui:top-level-window<%>. The
embed function won’t show the embedded window, so you’ll
need to get it and send it a
show message.
Destroys the render tree managed by r.
5.2 Views🔗ℹ
5.2.1 Windows & Dialogs🔗ℹ
Returns a representation of a top-level window.
Returns a representation of a dialog.
5.2.2 Menus & Menu Items🔗ℹ
Returns a representation of a popup menu. Popup menus are rendered
using
render-popup-menu.
Returns a representation of a menu-bar menu.
Changed in version 0.15 of package gui-easy-lib: The #:enabled? argument.
Returns a representation of a menu with items as children.
Changed in version 0.15 of package gui-easy-lib: The #:enabled? and #:help arguments.
Returns a representation of a menu item that calls action
when clicked.
Changed in version 0.15 of package gui-easy-lib: The #:enabled?, #:help and #:shortcut
arguments.
Returns a representation of a menu item with a checkbox. The
action callback is called with the current checked state
when the menu item is clicked. Use #:checked? to set or
update the checkbox programmatically.
Added in version 0.18 of package gui-easy-lib.
Returns a representation of a menu item separator.
5.2.3 Containers🔗ℹ
Returns a representation of a panel that lays out its children
horizontally.
Changed in version 0.13 of package gui-easy-lib: Added the #:mixin argument.
Returns a representation of a panel that lays out its children
vertically.
Changed in version 0.13 of package gui-easy-lib: Added the #:mixin argument.
Returns a representation of a labeled vertical panel.
Changed in version 0.13 of package gui-easy-lib: Added the #:mixin argument.
Returns a representation of a tab panel.
The #:choice->label argument controls how each choice is
displayed and the #:choice=? argument controls how the
current #:selection is compared against the list of choices
to determine the currently selected tab.
On user interaction, action is called with a symbol
representing the event, the set of choices at the moment the action
occurred and the current selection. The selection may be adjusted
depending on the event (eg. when the current tab is closed, the
selection changes to an adjacent tab). When tabs are reordered, the
choices provided to the action represent the new tab order.
See "examples/tabs.rkt" for an example.
Changed in version 0.3 of package gui-easy-lib: Added the #:choice=? argument.
Changed in version 0.3: The selection is now a value in the set of choices instead of an index.
Returns a representation of a panel that renders then-e
when the current-value of cond-e is truthy and
else-e otherwise.
Changed in version 0.4 of package gui-easy-lib: The if-view form was converted from a procedure into a syntactic form.
Returns a representation of a panel that renders the first
view-e for which the associated cond-e’s current
value is truthy.
Returns a representation of a panel that renders the first
view-e where one of the
case-lits is
equal? to
e’s current value.
Returns a representation of a panel that renders the
entries
by passing each one as a
derived observable to
make-view. The
make-view procedure is called with
the key and the derived observable of each entry. The
#:key
procedure must return a unique value for each entry in the list, as
compared using
equal?.
See "examples/list.rkt" for an example.
Returns a representation of a pane whose content is the result of
applying make-view to the value of data. The
content of the pane changes every time data changes and its
current value is not equal (according to equal?-proc) to
the previous value. The pane automatically adjusts its area
properties when its child’s area properties change to match.
Added in version 0.9 of package gui-easy-lib.
5.2.4 Canvases & Snips🔗ℹ
Returns a representation of a canvas that is redrawn using
draw whenever data changes.
Returns a representation of a canvas that is redrawn using the
result of make-pict whenever data changes.
Returns a representation of a canvas that is redrawn using the
result of
make-snip whenever
data changes. The
snip is converted to a bitmap before being drawn to the canvas so it
is non-interactive. Use this view when you want to efficiently
update plots. For interactive snips, see
snip.
Returns the representation of an editor that holds a snip generated
via make-snip. The snip may be updated whenever
data changes via update-snip.
5.2.5 Controls🔗ℹ
Returns a representation of a button that calls action when
clicked.
Returns a representation of a checkbox that calls action
when toggled.
Returns a representation of a choice widget that calls
action whenever the current selection changes.
The #:choice->label argument controls how each choice is
displayed and the #:choice=? argument controls how the
current #:selection is compared against the list of choices
to determine the selection index.
Returns a representation of an image.
The #:mode argument controls how the image stretches to
fill its container. If the mode is 'fit, then the image
will preserve its aspect ratio, otherwise it will stretch to fill
the container.
Changed in version 0.11.1 of package gui-easy-lib: The canvas background is now
'transparent. Now passes #t to the
#:try-@2x? argument of gui:read-bitmap.
Changed in version 0.17: The first argument may now be a
gui:bitmap%.
Returns a representation of a text field that calls action
on change. The first argument to the action is the type of
event that caused the input to change and the second is the contents
of the text field.
The #:value=? argument controls when changes to the input
data are reflected in the contents of the field. The contents of
the input field only change when the new value of the underlying
observable is not value=? to the previous one. The only
exception to this is when the textual value (via
#:value->text) of the observable is the empty string, in
which case the input is cleared regardless of the value of the
underlying observable.
The #:value->text argument controls how the input values
are rendered to strings. If not provided, value must be
either a string? or an observable of strings.
Returns a representation of a progress bar.
Returns a representation of a radio box widget that calls
action whenever the current selection changes.
The #:choice->label argument controls how each choice is
displayed and the #:choice=? argument controls how the
current #:selection is compared against the list of choices
to determine the selection index.
Unlike choice, the set of choices cannot be changed.
Returns a representation of a slider that calls the action on change.
Returns a representation of a spacer. Spacers extend to fill the
space of their parents.
Returns a representation of a table that calls action when
the selection changes or when one of its columns is clicked (if the
'clickable-headers style is set). The action
callback is called with the type of event that occurred, the set of
entries at the time of the event and the current selection, if any.
The current selection can either be a single index in the set of
entries or a list of indices in the case of a 'multiple
selection table.
The #:entry->row argument converts each row in the input
data for display in the table.
The #:column-widths argument controls the widths of the
columns. Column lengths can be specified either as a list of the
column index (starting from 0) and the default width or a list of
the column index, the column width, the minimum width and the
maximum width.
Changed in version 0.13 of package gui-easy-lib: Added the #:mixin argument.
Returns a representation of a textual label.
5.2.6 Combinators🔗ℹ
Returns a proxy of v that calls create-proc and
destroy-proc when a GUI widget is created and destroyed,
respectively, from the view.
Added in version 0.14 of package gui-easy-lib.
5.2.7 Interfaces🔗ℹ
5.2.7.1 view<%>🔗ℹ
A
view<%> object is a wrapper around a GUI object that knows
what its data dependecies are and how to respond to their changes.
A single
view<%> object may be used to manage multiple GUI
widgets. Consequently, when implementing custom views, it’s best not
to store any state within the view object itself. Instead, associate
any internal state with the GUI widgets returned by
create,
possibly via
context-mixin.
Returns the set of observers that this view depends on.
Instantiates the underlying GUI object, associates it with
parent and returns it so that the parent of this
view<%> can manage it.
Responds to a change to the contents of dep. The
val argument is the most recent value of dep
and the v argument is the GUI object created by
create.
Destroys the GUI object v and performs any necessary
cleanup.
5.2.7.2 window-view<%>🔗ℹ
A
window-view<%> is like a regular
view<%> but its
create method has additional constraints placed on it.
Returns #t if this view is a dialog.
5.2.7.3 popup-menu-view<%>🔗ℹ
5.2.7.4 context<%>🔗ℹ
Specializes a class to implement the
context<%> interface.
Compares keys using
eq?.
A
context<%> object allows the user of an object to
associate arbitrary values with it. Many of the
view<%>s
implemented by this library wrap their underlying GUI widgets using
context-mixin in order to associate internal state with
them.
Stores v under k within the context, overriding
any existing values.
Stores each v under each k within the context.
Returns the value stored under k from the context. If
there is no value, the result is determined by default:
If default is a procedure?, it is called
with no arguments to produce a result.
Otherwise, default is returned unchanged.
Like get-context, but if there is no value stored under
k, the default value is computed as in
get-context, stored in the context under k and
then returned.
Removes the value stored under k from the context.
Removes all stored values from the context.
5.3 Observables🔗ℹ
Observables are containers for values that may change over
time. Their changes may be observed by arbitrary functions.
Examples:
Derived observables are observables whose values
depend on other observables. Derived observables cannot be updated
using obs-update!.
Examples:
> (define @strs (obs-map @ints number->string)) |
> @strs |
(obs "1" #:name 'anon #:derived? #t) |
> (obs-update! @strs add1) |
obs-update!: contract violation |
expected: (not/c obs-derived?) |
given: (obs "1" #:name 'anon #:derived? #t) |
Internally, every observable has a unique handle and two observables
are equal? when their handles are eq?. This means
that equality (via equal?) is preserved for
impersonated observables, such as those guarded by
obs/c.
Returns a new observable, whose initial value is v.
The #:name of an observable is visible when the observable
is printed so using a custom name can come in handy while
debugging code.
The #:derived? argument controls whether or not the
observable may be updated.
Returns an impersonator of o whose name is changed to
name.
Registers f as an observer of o, applying it to
the value contained by o every time it changes.
Removes f from o’s set of observers.
Added in version 0.16 of package gui-easy-lib.
Returns the current value contained within o.
Returns a new
derived observable whose value changes every
time
o’s value does. The values held by the new observable
are mapped via
f.
Returns a new
derived observable that applies
p to
every new value of
o. The derived observable updates when
the result of applying
p to the new value of
o
is not
#f. The initial value of the derived observable is
(or (p (obs-peek o)) d).
Added in version 0.11 of package gui-easy-lib.
Added in version 0.11 of package gui-easy-lib.
Returns a new
derived observable whose value changes every
time one of the
os change. The values held by the new
observable are the values of the
os combined via
f.
This combinator retains a strong reference to each of the last
values of the respective observables that are being combined until
they change.
Returns a new
derived observable based on
o, whose
value changes when there is at least a
duration-ms
millisecond pause in changes to
o.
Returns a new
derived observable based on
o, whose
values change at most once every
duration-ms milliseconds.
Returns an impersonator or chaperone of an observable where wrappers
optionally redirect access and update of the observable’s value,
analogous to
impersonate-box and
chaperone-box. In
the case of
chaperone-obs, the value produced by a wrapper
procedure must be a chaperone of the wrapper’s second argument.
Added in version 0.19 of package gui-easy-lib.
5.4 View Helpers🔗ℹ
(case/dep what-expr | [dep-expr body ...] ...+) |
|
|
|
Executes the body of the first clause
body whose
dep-expr is
equal? to
what-expr. Logs
the
dep-expr that matched to the
'gui-easy topic.
Use this form to implement
update methods.
5.5 Observable Operators🔗ℹ
Binds
name to an observable whose initial value is
init-expr and whose name is
'name. If
init-expr is already an
observable, then it is
locally renamed to
'name then bound to
name.
Converts
v into an
observable. If
v is
already an observable, it is returned unchanged.
Changes the value of o to v.
Changes the value of o to the result of (f v).
Added in version 0.11 of package gui-easy-lib.
Returns a function that updates o using f when
applied.
5.6 Contracts🔗ℹ
The contract for container child alignment. Represents the
horizontal and vertical alignment, respectively.
The contract for margins. Represents the horizontal and vertical
margin, respectively.
The contract for optional labels.
The contract for positions. The first places
windows and
dialogs in the center of the screen.
The contract for sizes. Represents the width and height,
respectively. If either value is false, the view is allowed to
stretch in that direction.
The contract for spacing.
The contract for stretch values. Represents whether or not a view
can stretch horizontally and vertically, respectively.
Returns a contract that accepts an
obs? whose values
conform to
c. Checks the initial value of the observable
as well as all subsequent updated values.