-
Notifications
You must be signed in to change notification settings - Fork 149
Widgets
Seesaw has a bunch of functions for constructing "widgets". Widgets are user interface components that are displayed on the screen. They're called widgets for no good reason other than the name is shorter than "component" and it might help people forget that Swing lives under Seesaw :)
That said, a Seesaw widget is just a Swing component with some additional metadata attached to make things like [Selectors] work and to generally make them more pleasant to work with. In fact, most Seesaw functions that take a "widget" as an argument can take any old Swing component as well.
Seesaw includes a protocol (ToWidget
) for converting arbitrary objects to widgets. This is usually invoked on the values of the :items
and other "member" options for containers. It allows for a hopefully more natural UI construction process. For example, to make a label ((label)
in Seesaw, or just JLabel
in Swing), just pass a String:
(vertical-panel :items ["This" "is" "a" "vertical" "stack" "JLabels"])
The following table outlines the widget coercions that are provided in Seesaw out of the box. If you feel like it, you can provide coercions for your own types. See the [to-widget] (https://github.com/daveray/seesaw/blob/master/src/seesaw/examples/to_widget.clj) example for details.
Without further ado, here are the coercions:
Input | Result |
java.awt.Component | return argument unchanged |
java.awt.Dimension | return Box/createRigidArea |
java.swing.Action | return a button using the action |
java.util.EventObject (for example in an event handler) | return the event source |
:fill-h | Box/createHorizontalGlue |
:fill-v | Box/createVerticalGlue |
[:fill-h n], e.g. [:fill-h 99]
|
Box/createHorizontalStrut with width n |
[:fill-v n] | Box/createVerticalStrut with height n |
[width :by height] | create rigid area with given dimensions |
A URL | a label with the image located at the url |
A non-url string | a label with the given text |
Most of Seesaw's container functions (flow-panel
, grid-panel
, etc) take an :items
property which is a list of these widget-able values. For example:
(let [choose (fn [e] (alert "I should open a file chooser"))]
(flow-panel
:items ["File" [:fill-h 5]
(text (System/getProperty "user.dir")) [:fill-h 5]
(action :handler choose :name "...")]))
creates a panel with a "File" label, a text entry field initialized to the current working directory and a button that doesn't do much. Each component is separated by 5 pixel padding.
New coercions can be added by extending the ToWidget
protocol. See the to-widget
example.
All of Seesaw's widget creation functions (label
, text
, horizontal-panel
, etc) support a base set of properties:
Property | Description |
:id |
A unique id for the widget for use with `(select)` (see below). |
:opaque |
(boolean) Set whether the background of the widget is opaque. |
:background |
Background color by coercing into a Color (see below) |
:foreground |
Foreground color by coercing into a Color (see below) |
:border |
Set the border of the widget by coercing into a Border. See below. |
:font |
Set the font of the widget by coercing into a Font. See below. |
:enabled? |
Whether the widget is enabled or not. |
:minimum-size |
Minimum size of component, set with a `java.awt.Dimension` or a vector of the form `[width :by height]`, for example `[50 :by 50]`. Note that in Swing, some containers don't honor minimum size. |
:maximum-size |
Same as `:minimum-size`, but maximum. Note that in Swing, some containers don't honor maximum size. |
:preferred-size |
Same as `:minimum-size`, but preferred size. |
:size |
Set `:minimum-size`, `:maximum-size`, and `:preferred-size` all at once. |
:location |
Set the location of the widget with a `[x y]` vector or a `java.awt.Point`. _Note this is only useful when there is no layout on the container._ |
:bounds |
Set the bounds (location and size) of the widget with a `[x y width height]` vector or a `java.awt.Rectangle`. _Note this is only useful when there is no layout on the container._ |
:listen |
List of event listeners with same format as args to `(listen)` function (see below). |
:popup |
A JPopupMenu or function that generates the items of a popup menu to display. In this case, Seesaw ensures that the popup is shown on the correct mouse event for the platform. See `src/seesaw/examples/popup.clj` |
... and many more. See code and tests for details.
Note that these properties can also be used with the (config!)
function which applies them to an existing widget or widgets:
(config! (select root [:#my-widget]) :enabled? false :text "I'm disabled.")
(config!)
can be applied to a single widget, or list of widgets, or things that can be turned into widgets.
Use the (scrollable)
function to make a widget scrollable:
(scrollable (text :multi-line? true))
Use the (top-bottom-split)
or (left-right-split)
functions to make a splitter each takes two widget args:
(top-bottom-split "Top" "Bottom")
(left-right-split "Top" "Bottom")
Seesaw has some basic support for Java2D drawing, using the (canvas)
function to create a paintable panel. See src/seesaw/graphics.clj
and src/seesaw/examples/canvas.clj
.
Note that though sub-classing is very common in Swing tutorials, it's actually often not as necessary as you'd think.
If you're using custom widgets, either sub-classes of your own, or from another toolkit like SwingX, you can still take advantage of Seesaw, even for constructing the widgets. The `(seesaw.core/with-widget)' macro let's you use a custom sub-class with an existing Seesaw widget construction function. For example:
(with-widget org.jdesktop.swingx.JXList
(listbox :id :my-jxlist ... other listbox options ...))
This will return JXList
rather than just JList
. If the given class isn't a sub-class of whatever the construction function creates, IllegalArgumentException
is thrown.
See the docs for the (seesaw.core/with-widget)
macro for more info.