Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image Processing, extending JPanel and Simulating Classes in Clojure

there! I'm building an image-processing application in swing/clojure, and right now I need to develop an image panel in which I can click and compute data. Thanks to coobird, I now have a good idea on how to do it in Java, but I still don't get many issues on its integration with Clojure.

Let's take a look at how coobird suggested me doing. First, we should extend a class in Java. In clojure, we do this with the proxy macro, so we'd have something like this:

(def painting-panel
  (proxy [JPanel] []))

The next step is to create the class constructor and set some variables.

  1. I can define functions after the second argument of proxy, but how can I create the constructor? Is painting-panel the name of this class (therefore the name of the function I should create)?

  2. How can I deal with class variables? Should I define them with a let, like I did?

  3. Are this and super available for me to use, like I did below?

(def painting-panel
  (let [background-image (Image.)
          point-clicked (Point.)]
    (proxy [JPanel] []
        (paintComponent [g]
          (do ((.paintComponent super) g)
            (doto g
              (.drawImage background-image 0 0 nil)
              (.fillRect (.x point-clicked) (.y point-clicked) 1 1))))
        (painting-panel []; constructor?
          ((.addMouseListener this)
             (proxy [MouseAdapter] []
               (mouseClicked [e]
                 (do
                   (def point-clicked (.getPoint e)) 
                   (.repaint this)))))))))

Suggestions and code corrections are also welcome!

Thank you!

like image 409
konr Avatar asked Oct 05 '09 09:10

konr


1 Answers

  1. proxy actually creates an instance tada! You don't need to create a constructor.

  2. Yes, but consider using a clojure ref instead. Also using def like that on the second last line is nasty! it creates a global binding for point-clicked when your logic relies on the lexically scoped one created by let.

  3. (proxy-super paintComponent g), and yes "this" is available

This works for me:

(let [click (ref nil)
      panel (proxy [javax.swing.JPanel] []
              (paintComponent [g]
                (proxy-super paintComponent g)
                (.drawImage g (.getImage
                            (javax.swing.ImageIcon. "play.png"))
                            0 0 (.getWidth this) (.getHeight this) nil)
                (if @click
                  (.fillRect g (:x @click) (:y @click) 10 10))))]
  (.addMouseListener panel
      (proxy [java.awt.event.MouseAdapter] []
        (mouseClicked [e]
          (let [p (.getPoint e)]
            (dosync (ref-set click {:x (.x p), :y (.y p)})))
          (javax.swing.SwingUtilities/invokeLater #(.repaint panel)))))
  (doto (javax.swing.JFrame.)
    (.setContentPane panel)
    (.setSize 200 200)
    (.show)))
like image 86
Timothy Pratley Avatar answered Nov 15 '22 09:11

Timothy Pratley