Skip to content
daveray edited this page May 31, 2011 · 13 revisions

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.

Default Properties

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.

Scrolling

Use the (scrollable) function to make a widget scrollable:

(scrollable (text :multi-line? true))

Splitters

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.

Integrating Custom Widgets

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.

Clone this wiki locally