Skip to content

Instantly share code, notes, and snippets.

@radhikalism
Created August 9, 2009 07:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save radhikalism/164652 to your computer and use it in GitHub Desktop.
Save radhikalism/164652 to your computer and use it in GitHub Desktop.
(ns slider-demo
"A brief demonstration of using interactive Swing components with Clojure."
(:import [javax.swing JSlider JFrame JPanel SwingConstants]
[javax.swing.border LineBorder]
[javax.swing.event ChangeListener]
[java.awt BorderLayout Color Rectangle]))
(defn make-frame
"Returns a JFrame instance which is non-resizable, 800px wide, 600px high,
and containing panel."
[panel]
(let [frame (new JFrame)]
(doto frame
(.setResizable false)
(.setSize 800 600)
(.add panel)
(.show))))
(defn make-content
"Returns a JPanel instance using BorderLayout, and containing plot and
vertical and horizontal slider controls."
[plot slider-x slider-y]
(let [content (new JPanel)]
(doto content
(.setBackground Color/BLACK)
(.setLayout (new BorderLayout 10 10))
(.add slider-x BorderLayout/SOUTH)
(.add slider-y BorderLayout/WEST)
(.add plot))))
(defn make-plot
"Returns a styled JPanel instance that serves as a drawing area, rendered
by invoking paint-fn from paintComponent, with a cleared Graphics object."
[paint-fn]
(let [plot (proxy [JPanel] []
(paintComponent [graphics]
(proxy-super paintComponent graphics)
(paint-fn graphics)))]
(doto plot
(.setBackground Color/BLACK))))
(defn make-slider
"Returns a JSlider instance oriented along axis, and with an added
ChangeListener that invokes state-changed-fn on change events."
[axis state-changed-fn]
(let [orientation (axis {:x SwingConstants/HORIZONTAL,
:y SwingConstants/VERTICAL})
initial (axis {:x 0, :y 100})
slider (new JSlider orientation 0 100 initial)
listener (proxy [ChangeListener] []
(stateChanged [e] (state-changed-fn e)))]
(doto slider
(.setBackground Color/BLACK)
(.addChangeListener listener))))
(defn paint-plot
"Renders spot on a cleared Graphics object."
[spot graphics]
(doto graphics
(.setColor Color/DARK_GRAY)
(.fillRect @(:x spot) @(:y spot) (:size spot) (:size spot))
(.setColor Color/GREEN)
(.drawRect @(:x spot) @(:y spot) (:size spot) (:size spot))))
(defn update-spot
"Repaints plot with the recalculated and reset position of spot in plot,
according to the value of event's source slider."
[axis spot plot event]
(let [ratio (/ (.getValue (.getSource event)) 100)
ratio (if (= :y axis) (- 1 ratio) ratio)
range (if (= :y axis) (.getHeight plot) (.getWidth plot))
range (- range (+ 2 (:size spot)))
position (int (* ratio range))]
(reset! (axis spot) position)
(.repaint plot)))
(defn main
"Draws a frame with two sliders that control the vertical and horizontal
position of a box in a drawing area."
[]
(let [spot {:x (atom 0) :y (atom 0) :size 8}
plot (make-plot (partial paint-plot spot))
slider-x (make-slider :x (partial update-spot :x spot plot))
slider-y (make-slider :y (partial update-spot :y spot plot))
content (make-content plot slider-x slider-y)
frame (make-frame content)]
{:frame frame
:content content
:slider-x slider-x
:slider-y slider-y
:plot plot
:spot spot}))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment