Archive

Posts Tagged ‘seesaw’

Using a Wysiwyg Forms with Seesaw and Clojure

March 20th, 2012 No comments

At Clojure/West I mentioned that it was pretty easy to use forms built with wysiwyg UI editors seamlessly with Seesaw. I added an example and a section to the wiki that describes building a simple form with WindowBuilder in Eclipse. The basic principle should apply equally well to the ui tools in NetBeans and IntelliJ.

For someone that knows CounterClockwise well (that doesn’t describe me), I imagine the setup would be even more pleasant since changes to forms could be reused immediately from Clojure code without leaving Eclipse.

Finally, because everyone likes screenshots:

Categories: clojure, seesaw Tags: ,

Regenemies: A very simple game in Clojure

February 26th, 2012 4 comments

Lately I’ve been working on several things in Clojure with the goal of getting a better handle on general app development as opposed to library dev. Working on Seesaw and other libraries is fun and an interesting challenge in API design, but wrapping up Java interop is quite different from building a functioning app.

Anyway, one of my little experiments is a game called Regenemies. A long time ago a friend and I had the idea for “regex invaders” where regular expressions fall down the screen and you have to type in matches for them to “kill” them as fast as you can. Well, I finally got around to it this weekend. The whole falling regex thing didn’t work that well, so I opted for just showing 1 or more expressions in a grid, each with a little countdown timer to tell you how long you’ve got.

The game itself isn’t really that fun. In fact, it’s a little stressful since every missed pattern is a strike against your skills as a programmer, and therefore, your worth as a human being. But it was a useful exercise in building up the game representation and defining state transitions in a mostly functional way.

The UI, which is rudimentary in the extreme, is currently implemented in Seesaw, but I will probably give porting it to ClojureScript and canvas a try.

The game is hosted via JavaWebStart here, the code’s on github, and here’s a screenshot since people like those:

Comment and criticism welcome, especially on the game state representation. Regex generation could also use a little more love as well.

Categories: clojure Tags: ,

A Seesaw Tutorial

December 7th, 2011 1 comment

It was recently pointed out to me that Seesaw’s “amazing and wonderful”, but not still not that friendly for developers with no background in Java or Swing. By coincidence, I was scheduled to give a talk on Seesaw at Ann Arbor’s CraftsmanGuild, so I took the opportunity to try to improve the situation.

I’m usually not a fan of slides, so I did the talk completely in the REPL. The result was, I think, a nice introduction that assumes no Java or Swing knowledge and shows off some of Seesaw’s cool high-level features.

You might want to view it in its native habitat since this dumb fixed-width layout will hide some of the text. Also, depending on your fonts, my lovingly crafted screenshots might look like crap. Sorry about that.

In any case, here it is. Feedback welcome and encouraged.

Categories: clojure, seesaw Tags: ,

Seesaw Widget Binding

July 11th, 2011 8 comments

Lately I’ve been working on the problem of binding widgets and widgets (and data) together in Seesaw. I think it’s in a state to throw it out there and solicit feedback from anyone who’s interested. This work is similar to the arrow work done in Hafni, but takes a somewhat different approach and builds on top of the pretty extensive infrastructure that’s already in place in Seesaw.

The full source the for example shown here is here.

Motivation

Let’s say you were creating a search box where the user can enter a regular expression. You’d like to give some feedback whether the expression is valid or not, say by turning the text box red and updating a status label. Additionally, you’d like an “enabled” checkbox which enables or disables the search. Yeah, it’s contrived, deal with it :)

So, the usual approach would be something like this:

  • Set up the widgets
  • Add a selection change listener to the check box. When it fires, check its value and set the enablement of the search box
  • Add a document change listener to the text box. When it fires, parse the regex, set the color of the text box and update the status label appropriately

Not horrible, but kind of a hassle. If you turn your head and squint, you can kind of see a couple data flows going on here. First, the boolean value of the checkbox flows to the boolean enablement of the searchbox. Second, the text of the search box is transformed into a regex and then into a color (or status label) depending on success of failure. That color is then fed into the background color of the search box.

Seesaw’s binding (from Java Beans Binding, better names welcome) framework let’s you express this dataflow more directly.

Solution

So, the framework’s workhorse function is (seesaw.bind/bind). It takes a list of “Bindables” (see below) and hooks their values together into a chain. When a value at the start of a chain changes, it’s passed through the rest of the chain. bind returns a composite Bindable which can be composed into other chains.

So, for example, we can bind the value of a text box to an atom:

  (let [txt (text)
        a   (atom)]
    (bind txt a))

when the user types in the text box, the atom’s value changes to match it. There are several bindables already supported:

  • Text boxes, labels, sliders, atoms, etc are all bindable in the way you (or at least I) would expect.
  • (property widget property-name) – bind to a property of a widget
  • (selection widget) – bind to the current selection of a widget
  • (transform f) – transform a value with a function and pass it along
  • (some pred) – like (clojure.core/some) only pass along truthy values returned by a predicate.
  • (tee ... bindables ...) – split (demux) the chain into several independent chains.

Now back to our example. Here’s the annotated code for binding the search pattern logic. Here pattern is a text box, and status is a label:

    (b/bind 
      ; As the text of the textbox changes ...
      pattern
      ; Convert it to a regex, or nil if it's invalid
      (b/transform #(try (re-pattern %) (catch Exception e nil)))
      ; Now tee into two chains ...
      (b/tee
        ; The first path sets the color of the text box depending
        ; on whether the regex was valid
        (b/bind 
          (b/transform #(if % "white" "lightcoral")) 
          (b/property pattern :background))
        ; The second path sets the text of the status label
        (b/bind 
          (b/transform #(if % "Ready" "Invalid regex")) 
          status)))

Kinda cool? Similarly, we can hook a checkbox to the textbox enablement:

    (b/bind (b/selection (select f [:#enable]))
            (b/property  (select f [:#search]) :enabled?))

In this example, we’re using Seesaw selectors to find the checkbox (:#enable) and search text box (:#search).

Conclusion

I think this covers a lot of the tedious UI state management tasks that come up. Although atom binding is supported, it doesn’t seem like something you want to be doing often. It’s just doesn’t seem Clojure-y to me. Maybe a bindable atom that works more like (clojure.core/swap!) than (clojure.core/reset!) would be more appealing.

I’m looking for feedback, so if you find this interesting, useful, or offensive, please let me know!

Categories: clojure, seesaw Tags: ,

JSplitPainInTheAss: A less abominable fix for setDividerLocation

June 12th, 2011 9 comments

Update: Some discussion of this idea and code updates are in the gist here. Hubris.

If you use Swing much there will come a time when you’d like to create a splitter, aka JSplitPane. Overall, it works fine, but it has one lame, lame, lame feature; if you want to set the divider’s initial position proportionally, you’re screwed. I say feature, because the documentation for JSplitPane.setDividerLocation clearly states that it won’t work if the component hasn’t been “displayed” yet.

I bet that 95% of the time the programmer using this function is calling it at start-up before anything is displayed. Way to cover the 5% case there.

Anyway, you’ll go to Google and try to find a solution to this problem and you’ll find a lot of discussion and many variations on the same workaround. But they inevitably rely on sub-classing (isn’t that the solution to everything in Swing?) and hacking in some logic to fix things right before the splitter gets painted the first time. Nasty.

I’ve been thinking about this in terms of Seesaw, a Clojure/Swing API I’ve been working on. I want setDividerLocation to cover the 95% case and I don’t want to sub-class anything if I can help it. It’s not composable. So I thought about it a bit and came up with a much more elegant solution that works on a vanilla JSplitPane. Since I think this will be much more interesting to the Java Swing developers toiling away out there, I’ve coded it in pure Java. Here it is, a simple function:

If you can’t see any code, look here.

By the way, this code is insanely shorter in Clojure. Just sayin’.

The basic idea is to keep putting off the call to setDividerLocation using invokeLater until the splitter is realized on the screen. No fuss, no muss. … strike that. The invokeLater approach did indeed work, but under certain circumstances, a split pane that wasn’t displayed very soon would result in an infinite cascade of invokeLater events. The main problem with this is that the processor never gets to sleep, etc, etc. So I came up with an alternate approach which takes advantage of a HierarchyChange event to detect when the split pane is displayed (learn something new every day) optionally followed by a resize listener because the hierarchy event may arrive before the split pane’s been laid out by its parent. Swing’s exhausting.

Cheers!

Categories: java, swing Tags: , ,

Painting Widgets with Seesaw

June 10th, 2011 1 comment

The functionality describe here will be in the 1.0.7 release of Seesaw in the next week or so.

Say for some reason, you want a label with a red X on it. A bad, bad label. If you’re working with Swing in Java, you’ll create a new class, extend JLabel, override paintComponent, make some drawing calls, etc. Not terrible, but not that fun either. Something like this:

public class BadLabel extends JLabel {
  public BadLabel(String text) {
    super(text);
  }
  @Override
  public void paintComponent(Graphics g) {
    super.paintComponent(g);
    final int w = getWidth();
    final int h = getHeight();
    final int d = 5;
    g.setColor(Color.RED);
    g.drawLine(d, d, w - d, h - d);
    g.drawLine(w-d, d, d, h - d); 
  }
}

That’s pretty minimal if we ignore imports and stuff. Enabling anti-aliasing would be nice. It’d also be nice to set the width of the lines. And if you wanted to draw the X on a button or something else, you could pull all the drawing code into a function, but you couldn’t avoid a new, possibly anonymous, class for each type of component you want to use it on.

In Seesaw, we use the paintable macro to do all the dirty work for us. Give it a function to handle the painting and a description of the widget you want, and you’re done. It handles anti-aliasing and there’s functions that make styling the lines a little less tedious.

Below is the equivalent Clojure code using Seesaw. Note that here we can easily apply the red X to a label or a button. Of course this also puts the widgets in a frame and displays them too. I’ll spare you that part in Java :)

The code for this example is also here.

(ns seesaw.examples.paintable
  (:use [seesaw core graphics]))

(defn draw-a-red-x 
  "Draw a red X on a widget with the given graphics context"
  [c g]
  (let [w          (width c)
        h          (height c)
        line-style (style :foreground "#FF0000" :stroke 3 :cap :round)
        d 5]
    (draw g
      (line d d (- w d) (- h d)) line-style
      (line (- w d) d d (- h d)) line-style)))

(defn content []
  (flow-panel 
    :border 5
    :items [
      (label           :text "I'm a good label!" :font "ARIAL-BOLD-40" :foreground "#00AA00")
      ; *** Make a label and button with a red X on them ***
      (paintable label :text "I'm a bad label!"  :font "ARIAL-BOLD-40" 
                              :paint draw-a-red-x)
      (paintable button :text "I'm a bad button!"  :font "ARIAL-BOLD-40"
                                :paint draw-a-red-x)]))

(defn -main [& args]
  (invoke-later
    (->
      (frame :title "Seesaw (paintable) example"
             :content (content))
      pack!
      show!)))

(paintable) is still a macro so it comes with all the limitations associated with them. Unfortunately with Swing you have to sub-class to paint on a widget and in Clojure you can’t (as far as I know) sub-class at run-time.

Categories: clojure, seesaw, swing Tags: , ,

A Brief Note on Seesaw Selectors

June 8th, 2011 No comments

Just wanted to note that I finally got around to a full implementation of CSS-style selectors in Seesaw, the Clojure UI library I’ve been working on. The updated doc for the (seesaw.core/select) function has most of the details, but here are a couple examples:

      ; All JLabels, no sub-classes allowed
      (select root [:<javax.swing.JLabel!>])

      ; All JSliders that are descendants of a JPanel with id foo
      (select root [:JPanel#foo :JSlider])

      ; All JSliders (and sub-classes) that are immediate children of a
      ; JPanel with id foo
      (select root [:JPanel#foo :> :<javax.swing.JSlider>])

To implement the selectors, I hacked up the zipper-based selector code in the very cool Enlive project. It was surprisingly straightforward:

  • Modify zipper construction to create a zipper over a Swing widget hierarchy instead of an HTML doc
  • Hack up the parser a little bit to allow my Java-class-matching extensions
  • Update the predicate sets to work on widgets instead of DOM nodes

Hats off to Christophe Grand for writing such a well-factored piece of Clojure code that I could get this working in an evening.

I’ll write more (like what this could be useful for) when it’s not the middle of the night.

p.s. this will be in the 1.0.6 release on Clojars sometime this week after I beat on it a bit more.

Categories: clojure, seesaw, swing Tags: , ,

Nice Weather for Some Clojure (UIs)

May 24th, 2011 9 comments

Summary: I tried build something slightly non-trivial with Seesaw and learned some things.


And so it came to pass that it seemed like I needed to start dog-fooding Seesaw a bit. I’ve been steadily adding features and building tiny toy apps to demonstrate them. Others (and others) have apparently found it useful, but I haven’t tried anything myself.

So, I decided to write Gaidica, a little app that displays weather info for user-selected cities. The whole process wasn’t terrible, but shows that there’s work to do. I’d guess about 4 hours of work including fixing Seesaw bugs as I hit them and at least an hour puzzling over Clojure XML stuff. Here’s a screenshot of the forecasts:

The code is all available on github.

Intro

Just to make sure we’re on the same page, Seesaw is an API/DSL for building user interfaces in Clojure. It happens to be built on Swing as you’ll see below, but please don’t judge it too harshly. I’m working hard to make it so you never need to know that Swing’s even there.

The Data

I decided to use Weather Underground’s XML API for the data. It provides the data in a simple format and as a bonus, includes icons for weather conditions, which saved me some work. Additionally, I got to do some XML wrangling in Clojure. Let’s just say that that deserves a blog post of its own.

In any case, I just point Clojure’s (xml/parse) function at the URL and get back some results. All this is done in a background thread using (future) to keep the UI responsive.

The Good

I mostly want to focus on the bad in this post, but despite any difficulties I had, building this was more enjoyable in Clojure+Seesaw than the equivalent Clojure+Swing or raw Java code. The lack of (proxy) and (reify) usage is testament to that.

Seesaw’s table support, seen in the webcam tab below, really paid off. Compared to the equivalent JTable-wrangling you’d have to do, it was downright dreamy.

Here’s the code to create that table:

(defn make-webcam-table [] 
  (table 
    :id :webcam-table 
    :model 
      [:columns 
        [{:key :handle :text "Name" } 
         :lat :lon 
         {:key :updated :text "Last Updated"}
         {:key :image :text "Image"}]]))

The Bad

I learned a lot during this exercise. One thing I noticed is that Swing is a pain in the ass. I think when you’re in the depths of a Java-based Swing app, you don’t even notice it because you’re already so mired in Java verbosity. It’s a form of Stockholm Syndrome I guess.

Most of the pain centered around, you guessed it, layout. I wanted to do it with the vanilla Swing layouts provided by Seesaw (border-panel, vertical-panel, etc), but after fiddling with component alignments and lame resize problems, I eventually surrendered and ran back to MigLayout. It’s powerful and pretty easy to use, but it’s yet another little language to learn. Luckily Seesaw already has Mig support.

Otherwise, most of the other issues I had were just missing functionality. Swing methods not yet wrapped by Seesaw. The nice thing is that since Seesaw’s a fairly thin wrapper, it’s easy to drop down to raw Swing when needed. Some random functionality that I’m going to address as a result:

  • Manipulation of the widget hierarchy needs to be seamless. This has historically been a problem in Swing (invalidate(); revalidate(); repaint()!!)
  • Widget styling. Sprinkling fonts and colors throughout the code is a hassle. The main question is whether I just add convenience options for this, or go whole hog and try for a CSS-style styling.
  • Saner defaults for “vanilla” layouts. I think I can tune some of the defaults and add some dials to make it less frustrating. It still really bugs me that I had to use Mig for something so simple.

Conclusion

From the perspective of a potential Seesaw user, already suspicious of Swing, all of this is a problem. I’ll take it as a challenge to continue making Seesaw a buffer between them and the occasional craziness of Swing. Feedback welcome!

Categories: clojure, seesaw, swing Tags: , ,

20 Minute File Explorer with Seesaw

April 30th, 2011 3 comments

Seesaw, my Clojure/Swing experiment has been making a lot of progress. Earlier today I added basic support for JTree which is kind of the last major Swing component that had no support in Seesaw. As an test, I thought I’d try making a file explorer with the directory tree on the left and file list on the right. It took about 20 minutes and was way less tedious than the equivalent raw Swing code you’d write in Java or Clojure.

The full code for the example can be found on github.

Here’s what it ended up looking like:

Code Highlights

There are three code highlights.

Set up a model for the tree using the same pattern as (cloure.core/tree-seq):

; Make a model for the directory tree
(def tree-model
  (simple-tree-model
    #(.isDirectory %)
    (fn [f] (filter #(.isDirectory %) (.listFiles f)))
    (File. ".")))

Set up the structure of the frame. I think this reads pretty nicely:

  (frame :title "File Explorer" :width 500 :height 500 :pack? false :content
    (border-panel :border 5 :hgap 5 :vgap 5
      :north (label :id :current-dir :text "Location")

      :center (left-right-split
                (scrollable (tree :id :tree :model tree-model :renderer render-file-item))
                (scrollable (listbox :id :list :renderer render-file-item)))

      :south (label :id :status :text "Ready")))

Set up selection event handling:

  (listen (select [:#tree]) :selection
    (fn [e]
      (if-let [dir (-> (selection e) first last)]
        (let [files (.listFiles dir)]
          (config (select [:#current-dir]) :text (.getAbsolutePath dir))
          (config (select [:#status]) :text (format "Ready (%d items)" (count files)))
          (config (select [:#list]) :model files))))))

Here, the widgets are being retrieved by id with the (select) function. Alternatively, I could have just bound them to variables and used them directly. I’m still thinking about how this should work.

Conclusion

This is obviously still a toy (no sorting, doesn’t update, etc, etc), but I think shows promise. I like the separation of the structure and behavior, but the selector stuff needs more thought. Probably the biggest gain over raw Swing is that Seesaw takes care of all the yucky reify and proxy stuff for you. In this example alone, a raw implementation would need two (reify)s and a (proxy) call. Building up the widget structure is also pretty tedious with raw Swing.

I’d love to to hear feedback and criticism of the API since this is my first attempt at real Clojure code. Thanks!

A nice evening with the Clojure REPL

April 25th, 2011 4 comments

I’ve been working on Seesaw a lot lately. It’s a Swing wrapper/dsl/whatever for Clojure and I’ve had a great time working on it. Tonight, I was testing some very simple graphics stuff I added (namely, the (push) macro) and I had a nice moment with the REPL. Here’s my session where I paint some text to an image and display it in a JFrame:

Clojure
user=> (use 'seesaw.core)
nil
user=> (use 'seesaw.graphics)
nil
user=> (use 'seesaw.color)
nil
user=> (def image (buffered-image 200 200))
#'user/image
user=> (let [g (.getGraphics image)]
 (.setColor g (to-color "#FF0000"))
 (.drawString g "This is RED" 5 20)
 (push g
   (.setColor g (to-color "#0000FF"))
   (.drawString g "This is BLUE" 5 40))
 (.drawString g "This is RED again" 5 60))
nil
user=> (frame :content (label :icon image))
#<JFrame ...>
user=>

and up pops:

All the yucky Java-y graphics calls need to be cleaned up, but I would never be able to type in the equivalent code in Java without liberal use of ctrl+space.

Ok, back to work.

 

 

Categories: clojure Tags: ,