(some #{:easy :simple} swing) ;=> nil
JLabel myLabel = new JLabel("Hiya"); myLabel.setBackground(new Color(136, 136, 136)); myLabel.setOpaque(true); myLabel.setForeground(Color.BLUE); JFrame myFrame = new JFrame("Why Swing, why?"); myFrame.setContent(myLabel); myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); myFrame.pack(); myFrame.setVisible(true);
(doto (JFrame. "Why Swing, why?") (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE) (.setContent (doto (JLabel. "Hiya") (.setBackground (Color. 136 136 136)) (.setOpaque true) (.setForeground Color/BLUE))) .pack (.setVisible true))
(-> (frame :title "Why Swing, why?" :on-close :exit :content (label :text "Hiya" :border 5 :background "#888" :foreground :blue)) pack! show!)
:red
"#F00"
"#FF0000"
:my-app.core/my-color-resource
"ARIAL-BOLD-18"
{:name "ARIAL" :style :bold :size 18}
(seesaw.font/font :name "ARIAL" :style :bold :size 18)
:my-app.core/my-font-resource
"http://example.com/icon.png"
(clojure.java.io/resource "path/to/icon.png")
:my-app.core/my-icon-resource
; Keystroke "ctrl C"
; Dimensions [640 :by 480]
; Borders [5 "Compound" 10]
(config! my-label :background :red :foreground "#00FF00") ;=> my-label
(config my-label :background) ;=> #<Color java.awt.Color[r=255,g=0,b=0]>
Inspired completely by Stathis Sideris' Clarity
(value (textbox :text "HI")) ;=> "HI"
(value (slider :min 0 :max 11 :value 6)) ;=> 6
(-> (combobox :model [1 2 3 4]) (selection! 3) value) ;=> 3
(def form (grid-panel :columns 2 :items ["First Name" (text :id :first-name) "Last Name" (text :id :last-name) "Sex" (combobox :id :sex :model ["Female" "Male"]) "Age" (spinner :id :age)]))
(-> (dialog :content form) pack! show!) ;=> :success
(value form) => {:first-name "Philip", :last-name "Glass", :sex "Male", :age 75}
public interface MouseListener { void mouseClicked(MouseEvent e); void mouseEntered(MouseEvent e); void mouseExited(MouseEvent e); void mousePressed(MouseEvent e); void mouseReleased(MouseEvent e); } JLabel label = new JLabel(); label.addMouseListener(new MouseListener() {...});
(.addMouseListener my-panel (proxy [MouseAdapter] [] (mouseClicked [this e] ... do something ...))) (.addMouseMotionListener my-panel (proxy [MouseMotionAdapter] [] (mouseMoved [this e] ... do something ...))) (.addComponentListener my-panel (proxy [ComponentAdapter] [] (componentResized [e] ... do something ...)))
(listen my-panel :mouse-clicked (fn [e] ... do something ...) :mouse-moved (fn [e] ... do something ...) :component-resized (fn [e] ... do something))
:selection
// List JList myList = ...; myList.addListSelectionListener(...);
(listen my-list :selection (fn [e] ...))
:selection
// Tree JTree myTree = ...; myTree.addTreeSelectionListener(...); // seriously?
(listen my-tree :selection (fn [e] ...))
:selection
// Table JTable myTable = ...; myTable.getListSelectionModel() .addListSelectionListener(...); // oh, come on.
(listen my-table :selection (fn [e] ...))
// Group of mutually exclusive radio buttons Enumeration<AbstractButton> bs = myButtons.getElements(); for(; bs.hasMoreElements();) { bs.nextElement().addItemListener(...); } // WTF, eh?
(listen buttons :selection (fn [e] ...))
(require '[seesaw.bind :as b]) (def safety (checkbox :text "Safety" :selected? false)) (def fire-missiles (button :text "Fire!" :enabled? false)) (b/bind safety (property fire-missiles :enabled?))
... (def status (label :text "Safe")) (b/bind safety (b/tee (property fire-missiles :enabled?) (b/bind (b/transform #(if % :red :green)) (property status :background)) (b/bind (b/transform #(if % "Armed" "Safe")) (property status :text))))
(def volume-control (slider :min 0 :max 11 :value 5)) (def volume-atom (atom 5)) (b/bind volume-control volume-atom volume-control)
How do you separate layout from behavior?
Select by :id
(select panel [:#first-name]) ;=> JTextField
Select by :class
(select panel [:.dangerous]) ;=> (JButton JButton JButton ...)
Select all children of widget with class :foo
(select root [:.foo :> :*])
... and many, more
Plays nicely with "vectorized" config!
; Disable everything (config! (select panel [:*]) :enabled? false)
Plays nicely with "vectorized" listen
; Add action handler to all widgets ; with class :dangerous (listen (select panel [:.dangerous]) :action (fn [e] ...))
(button :id :open-doors :text "Open Pod Bay Doors") (checkbox :id :safety :text "Safety") (button :id :launch-missiles :class ...) (button :id :fire-torpedoes :class :dangerous ...) ...
(defn add-behaviors [root] (listen (select root [:#open-doors]) :action (fn [_] ...)) (listen (select root [:#safety]) :selection (fn [e] (config! (select root [:.dangerous]) :enabled? (not (selection e))))) ...
"Seesaw is amazing and wonderful, but it still doesn't do much good for people who don't know Java/Swing already"Anthony Grimes (aka Raynes)
user=> (doc button) ------------------------- seesaw.core/button ([& args]) Construct a generic button. In addition to default widget options, supports the following: :halign Horizontal alignment. One of :left, :right, :leading, :trailing, :center ... snip ... Resources and i18n: A button's base properties can be set from a resource prefix, i.e. a namespace- qualified keyword that refers to a resource bundle loadable by j18n. Examples: ; Create a button with text "Next" with alt-N mnemonic shortcut that shows ; an alert when clicked. (button :text "Next" :mnemonic \N :listen [:action #(alert "NEXT!")]) See: http://download.oracle.com/javase/6/docs/api/javax/swing/JButton.html (seesaw.core/button-group)
(use 'seesaw.dev)
user=> (show-options (label)) Option Notes/Examples ------------------- -------------- :background :aliceblue "#f00" "#FF0000" (seesaw.color/color 255 0 0 0 224) :border 5 "Border Title" [5 "Compound" 10] See (seesaw.border/*) :bounds :preferred [x y w h] Use :* to leave component unchanged: ... snip a lot here... :user-data Anything. Associate arbitrary user-data with a widget. See (seesaw.core/user-data) :v-text-position :bottom :center :top :valign :bottom :center :top :visible? boolean
user=> (show-events (text)) :action [java.awt.event.ActionListener] :action-performed :caret [javax.swing.event.CaretListener] :caret-update :component [java.awt.event.ComponentListener] :component-hidden :component-moved :component-resized :component-shown ... snip a lot here ... :mouse-motion [java.awt.event.MouseMotionListener] :mouse-dragged :mouse-moved :mouse-wheel [java.awt.event.MouseWheelListener] :mouse-wheel-moved :property-change [java.beans.PropertyChangeListener] :property-change :selection [javax.swing.event.CaretListener] :caret-update
; Construct a widget (def my-text (text :id :my-text :text "Hi" :font ...)) ;=> #<JLabel ...> ; Change a widget (config! my-text :enabled? false) ;=> #<JLabel ...>
; Get a widget's value (value my-text) ;=> "Hi"
; Find out when things happen (listen my-text :focus-gained (fn [e] ...)) ; Bind widgets together (bind my-text (property my-label :text))
; Find a widget (select root [:#my-text]) ;=> <JLabel ...>
; Explore a widget (show-options my-text) (show-events my-text)
Use a spacebar arrow keys to navigate