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:
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.
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.
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.
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:
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:
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:
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.
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.
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.
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.
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.
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 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?.
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.
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 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.
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 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 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.
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.
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.
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.
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.
Updates the value within o by applying f to it and
storing the result. Returns the new value. If o is a
derived observable, raises an exn:fail:contract?
error.
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-peeko))d).
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.
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.
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.
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.