This page introduces the basics of coding a GUI surface
based on the core Superficial concepts of facets,
targets and retargeting:
On-page applets demonstrate how you can use the Facets implementation
of Superficial to
This page and its applets are at the beta stage of development.
Please notify bugs here.
Creating an application
Below is an applet running the Superficial implementation of "Hello
You can view its complete code in a window or in the code
viewer (itself a demo application).
is certainly a novel, and rather elaborate, way to display what
is really just a Swing label. Why split the code between two methods,
and how do they relate to each other? What are these
types? What is a
and what does a
These questions are answered in some detail below: the underlying
point is that Superficial is probably the first truly high-level
framework for GUI development. In Superficial you don't define a
GUI and then bind data to it - you define the data first, then (after
a bit of magic performed for you by the framework) the GUI that
gives access to it.
In this respect Superficial conforms to the Model-View-Controller
(MVC) paradigm: it defines a GUI surface
in terms first of its targets,
and only then of the facets that
expose them to user view and control; targets and facets are linked
by retargeting which avoids
the need for explicit data binding.
The two methods of
HelloLabel (both called ultimately from the
Applet) construct the simplest possible GUI
application surface by defining a single text target, which in turn
has a single exposing label facet.
The first method called is
newBasicTargets which returns
an array of
the supertype of all target
HelloLabel the array comprises
which represents a simple text string, of which the initial (and
HelloLabel unchanging) state is passed to the constructor.
Of the other two parameters to the
title is returned by all
for use as a caption by exposing facets. Since this
is to be exposed by an uncaptioned label facet, a string is passed
that documents this.
parameter is a minimal example of an important feature of the Facets
implementation of Superficial as described later.
newBasicTargets returned a
to be exposed in the GUI of
it makes sense for
newBasicPanelFacets to return a
that will create and manage a suitable Swing label. The puzzle is
that of the two types passed to
neither bears any obvious relationship either to the
or to Swing.
The Swing issue is most easily resolved. Because a Superficial
GUI is defined purely in terms of facets,
the Facets implementation can hide details of the GUI toolkit from
client code using an abstract
This has a wide range of methods supplying instances of
that in turn create and manage GUI widgets.
HelloLabel the only facet required is one that
creates a simple label, so the method to call is
Like most methods of
this takes two parameters: a
and one or more concatenated
HINT constants that can
supply low-level facet policy. But where does the
array passed to
newBasicPanelFacets has a single member
that can be used to create a label facet exposing the
must be related in some way to
- but how?
During application construction each
creates a corresponding
which has the following characteristics:
- It is retargeted (passed a reference) initially on the
that created it.
- It can have any number of
attached to it.
- It can retarget these
on its current
It is this relationship between targeters, targets and facets that
makes the Superficial retargeting
mechanism so powerful.
The initial retargeting takes place before the
is passed to
newBasicPanelFacets, where the
is used to create and attach a
to it. Once the Swing GUI has been created as described below, the
will in turn retarget the
and this will set its
JLabel widget with the text of
A major advantage of the Superficial approach is that it can shield
client code completely from the details of low-level GUI construction.
(Though in practice the Facets implementation allows surprisingly
fine control of the detailed appearance of a GUI, and even the use
of custom Swing components.)
All you need to know when coding with Superficial is that having
that they create, you can rely on the framework to do the rest.
If you're curious to see what actually happens, you can start at
the top with
demo.DemoSurface which manages the application
creation and retargeting sequences for
However even these are performed at a high level of abstraction
- if you insist on finding Swing code, you'll need to peer behind
another layer or so of interfaces.
But why worry about these details? Much better move on to the next
applet, and find out how Superficial helps you handle input to your
Input and updates
demonstrates the basics of a constructing a Superficial surface,
but its simple label facet can't show how Superficial handles input
to a GUI.
HelloField is a slightly more elaborate version of
HelloLabel that exposes the greeting text not just
with a label, but also with a text field that allows the the greeting
to be edited. This enables it to demonstrate
- how Superficial handles updating of targets and facets transparently
to client code
- how a single target can be shared by multiple facets
- how facets hide code complexity and promote code re-use
Given the substantial increase in functionality provided by
may surprise you how little the code differs from
is constructed with a title that can be used by an edit field
facet, and a
that defines policy for the facet.
- Such a facet is returned by
together with the label facet.
- And that's it! How does that work?
The edit field facet
The edit field facet returned by
demonstrates how Superficial's high-level approach shields client
code from low-level GUI complexities, while at the same time promoting
To start with, the facet creates and manages not just a single
widget, but a
JPanel containing both a
JLabel is set to
title property of the
JTextField allows editing of the
Now try editing in
HelloField and you will find the
has more intelligence than you might expect. It won't allow you
to blank it (this would make a nonsense of most texts); pressing
Esc reverts its state while Enter commits the edited state.
Because the code that constructs the facet's widgets and enables
it to handle input intelligently is hidden behind the
reference, client code is hugely simplified. Code re-use is guaranteed
because its functionality is available from every instance of
Moreover, the edit field facet appears magically bound to the label
facet. The label reflects even uncommitted edits, while reverting
the field reverts the label as well. Yet there's no code in
this binding (the
only sets a flag as described below) - how is it defined?
Binding targets and facets
demonstrate much more clearly the advantages of Superficial for
Sharing a target
An obvious advantage is the ease with which multiple facets can
be bound to a single target.
The label and edit field facets are both attached in
to the same targeter, so they share the same
target. Because it is the target that represents the data to be
exposed in the surface, after each retargeting
both facets automatically display the latest state of that data.
A more subtle advantage demonstrated by
the complete absence of code that explicitly updates the target
and facets after input. To understand why this is not required,
let's consider how input is handled by the text field facet.
When the GUI is created by the applet host, the facet constructs
JPanel with child
components. Setting properties as required to match the title and
text state of its
it then listens for input on the
As input arrives, the facet can respond appropriately to signals
such as Esc and Enter, and ask the
attached to the
to validate the current text in the
is why it rejects blank texts). Above all, it can decide at some
point to update its target with the current text, and trigger a
Whenever a retargeting is triggered, the framework takes over.
First all targeters are retargeted on appropriate targets. This
has no particular effect in a simple application such as
but is crucial when there may be a selection
Next all facets are retargeted on the latest targets of their targeters,
and have the opportunity to update their widgets to match the current
state and policy of these targets. Facets that share a target will
set their widgets to the same state, in effect binding them all
to the same data.
Exactly when the text field facet triggers a retargeting depends
on a flag set by the
Both facets and application generally require more than the core
functionality of simple
- The facet may need to know how it should display or update the
data represented by the
For instance in
the edit field facet needs to know if it should wait for Enter
before committing edits and updating its target.
- The application often needs to know when a
has been updated. In
HelloField no further action
is required once the edit field facet updates its
target. But most applications will need to update data that their
targets represent, or (like the next few applets on this page)
take some other action..
The Facets implementation of Superficial uses appropriate
to provide this extra functionality. Because couplers are parameter
objects that hold no reference to any particular
they can be defined independently of their
and shared between logically related
The larger part of the code related to simple
is contained within subclasses of default implementations such as
STextual.Coupler; only in a simple case such as
can a default implementation be used 'as-is'.
is subclassed to make the text field facet behave in a non-standard
way. By default the facet waits for Enter as a signal to commit,
updateInterim in the coupler is reimplemented
true, the facet triggers a retargeting every
time that input pauses - this is how the label state tracks the
edit state so closely.
Now that we've covered the basics of creating a Superficial surface
that responds to input, let's add some more logic and GUI.
extends the functionality of
by adding a checkbox in the panel and a single-item menu, both defining
validation of the greeting text.
Looking at the code of
you will see the following developments compared with
- There are now two targets, one of them of a
providing the validation flag.
for both targets override several methods so as to provide the
- A further method from
CodingApplet is implemented
to define a menu item.
The validation flag is provided by a
which is a
that represents Boolean values. Like
it is constructed from a title text and its own flavour of
but with its state set and returned as a
can be exposed by a large variety of facets. Targeters of
can be passed to togglingX methods of
to create facets which define and manage checkboxes and toggle buttons,
menu items and even multi-selection lists.
provides a typical example of coding with couplers.
- Couplers are ideal anonymous subclasses. They can be instantiated
as class or method variables, or as parameter objects if they're
- They often refer to targets instantiated after them, so to avoid
compiler errors targets have often to be defined as instance variables.
Sometimes even the order of instantiation of the targets is critical:
must be created first because
isValidText in the
references it when the
The two couplers provide examples of the two main reasons for overriding
default implementations: the
to state change, while the
Responding to change
is updated by one of its exposing facets so as to disallow spaces,
the existing state of the
may become invalid.
SToggling.Coupler allows for this by overriding
the default (empty) implementation of
is called whenever a
to which it is attached is updated. The new implementation responds
to resetting of the flag by fetching the current state of the
stripping any spaces and updating the
with the stripped text.
Whenever the state of a
is set, it calls
isValidText in the coupler (including
at construction). Because an exception is thrown if the return is
false, the text field facet uses the same method to
pre-check text before updating its target.
STextual.Coupler extends the default implementation
isValidText which rejects a blank text, adding a
check for spaces if required by the state of the
newBasicMenuFacets to return a non-
array signals to the superclass
CodingApplet that it
should construct a menu bar (inside the panel!), adding to it menu
items for each of the facets returned.
HelloSpaces a single
is returned, created using
Because the facet is attached to the same targeter as the panel
checkbox facet, the framework ensures that their widgets are synchronised
just like the panel label and text field.
HelloCommit is a another version of
which introduces another new
type. It extends the functionality of
logic that commits or cancels edits to the greeting text, exposed
both by buttons in the panel and items in the menu. Buttons and
menu items are disabled unless the actions they represent are meaningful.
The code of
the following developments compared with
- A second
holds uncommitted edits to the greeting text.
represent the actions of committing or cancelling edits.
- Each pair of targets shares a custom coupler instance.
- The logic provides for disabling of buttons and menu items.
are constructed from a shared custom
instance, which overrides
updateInterim as before (this
will only be called for edits). It also overrides
which is called whenever the state is set of either edits
(usually by its text field facet) or greeting (only by the
STrigger.Coupler); in both cases it calls the convenience
setTriggerLives described below.
is a stateless
that represents an application action or process, exposed by either
buttons or simple menu items.
are constructed with a
that has a single
fired method, which here checks whether
commit or cancel has been fired and copies the state
of one of the
to the other as appropriate.
Enabling and disabling
Superficial makes it easy to manage the enabled state of GUI widgets.
live value that can be checked at each retargeting
by its exposing facets and used to disable/enable the appropriate
The live state can be set for any
but it only returns
true when any enclosing groups
(see below) are also live; this facilitates very fine-grained control
to the enabled state of the GUI.
The commit and cancel
are returned from
newBasicTargets wrapped in the commitCancel
group. Grouping allows logically related targets to be treated by
the framework as one, and
advantage of it in two ways:
- From the single targeter exposing commitCancel, the
can construct with
triggerButtons a single facet
that constructs and manages a panel of equally-sized buttons,
triggerMenuItems another that creates corresponding
- All the buttons and menu items can be enabled or disabled at
once by setting the live state of commitCancel in the
HelloLimit is very similar to
but restricts the maximum length of the greeting text to a limit
exposed in several different ways.
The code of
essentially that of
updated to set a different constraint.
- The text of the
is limited in length.
- The limit is defined by a
which in turn is constrained by the
returned by its
is the shared target of three facets in the applet panel and menu,
one exposing its state in two different ways.
The length limit of the greeting represented by the
is itself represented (as a
double value) by a
When its value changes,
valueSet is called in the
here implemented to ensure the text length does not exceed the new
to check the length of the text proposed against the current limit.
double of potentially any value. How can you
ensure that it is constrained in the GUI to an integer value within
a sensible range?
SNumeric.Coupler returns the necessary validation
policy as a
initialised with the minimum and maximum limits to be set. In
is returned, which extends
to supply the display policy required by a slider facet to define
its ticks and labels. Re-implementing
both slider and numeric field to allow entry only of multiples of
5 in the defined range, and sets the size of the nudge for the panel
buttons and menu items.
The facets created in
newBasicPanelFacets are broadly
similar to those in
and demonstrate further the power of the facet concept, not to speak
of the flexibility and concision of the
The textual facets are exactly as before, the spacer facet and
BREAK constant together add a blank row to the
Contrary to what you might expect, there just two numeric facets
(separated by a horizontal spacer facet).
HINT constants passed to
ensure that the facet returned not only creates a titled, labelled
and ticked slider to meet the
supplied by the
target, but also adds a numeric field and arranges its widgets
in two rows.
- The facet obtained from
a rare example of a GUI element providing control without view
(almost). Once again following the
its paired buttons increment and decrement
the value where possible, becoming disabled when the value is
at the end of its range.
The single facet returned by
a pair of menu items corresponding to the panel nudge buttons, then
groups them in a sub-menu.
Choosing from a list
HelloChoose differs from applets such as
in that it does not allow its greeting to be edited, but instead
presents a choice of texts using the last of the simple
The code of
SIndexing represents a list of possible texts and an index
into that list.
- The state of the
is updated whenever
indexSet is called in the
is exposed by a total of five panel and menu facets, creating
and managing two or three widgets each.
Editing a selection
HelloSelect both allows the greeting to be edited
and presents a choice of texts like
As you might expect, the facet details in
But otherwise the code presents several puzzles.
- Both targets and facets are defined within different methods
from the previous applets.
is defined within a new
is defined, but a suitable
is passed to the facet methods.
The key to the different methods lies in the constructor to
which creates an array of
HelloTexts and passes it
to the superclass. This triggers a radical change in the behaviour
CodingApplet because it now has to allow editing
of a selection within the content supplied.
Just creating simple targets in
not handle this new complexity, which is why in
it returns an empty array. Instead,
the framework to construct elements (including the missing
that allow selection within the content array.
HelloSelect each content selection is passed to
newSelectionFrame to allow targets to be created representing
its editable state; the initial targets together with the hidden
are used to create the extra
On the face of it,
newSelectionFrame might just return
an array of
newBasicTargets. However the framework requires
targets representing a selection to be wrapped by a distinct subclass
(which makes possible advanced features like adapting the GUI to
match the current selection).
extends the basic
implementation not by specialising for a specific content type,
but by exposing its content directly as an immutable
member. While this is of little benefit in
it allows more complex applications to access the selected content
via the framework.
To ensure subclassing,
cannot be constructed from its
child elements; instead it creates them during the initial retargeting
much like that returned by
with the important difference that its
textSet to update the state of the selected
The main development in the facet creation methods is in the parameters
- basics are targeted as before on the targets returned
newBasicTargets (so the array is empty in
- indexing is targeted on the
CodingApplet and allows view and control
of the index into the content array.
- selection is targeted on the
newSelectionFrame, so the first member
elements is targeted on the
created in different places (including one in the superclass), the
can be freely arranged in any combination.
Bringing it all together
HelloAll combines the functionality of all previous
applets on this page:
therefore needs very little new code, but does
have a few points of interest.
- Non-selection targets are created in
shared by the triggers can access the current selection using
a method from
- Some of the
newContentPanelFacets are arranged within
a nested panel.
Try downloading the source code of real-world Facets
applications and see how you get on.
© 2011 David M Wright