I've used proxy successfully several times so far, but I'm not sure I
can use it here. The code that I'm trying to translate is as follows:
-----------------------------------
class ToggleShape extends PPath {
private boolean fIsPressed = false;
public ToggleShape() {
setPathToEllipse(0, 0, 100, 80);
addInputEventListener(new PBasicInputEventHandler() {
public void mousePressed(PInputEvent event) {
super.mousePressed(event);
fIsPressed = true;
repaint();
}
public void mouseReleased(PInputEvent event) {
super.mouseReleased(event);
fIsPressed = false;
repaint();
}
});
}
protected void paint(PPaintContext paintContext) {
if (fIsPressed) {
Graphics2D g2 = paintContext.getGraphics();
g2.setPaint(getPaint());
g2.fill(getBoundsReference());
} else {
super.paint(paintContext);
}
}
}
-----------------------------------
Some questions:
1) Because this new class, ToggleShape, has the added state of
fIsPressed, is it possible to use proxy at all, or do I have to use
gen-class? If it's the latter, how do I declare the namespace that
surrounds the gen-class so that this new class is visible to the code
that uses it?
2) If I can use proxy, do I create a constructor for this nameless new
class by redefining PPath (which is, after all, the name of the
constructor for the superclass)?
As always, thanks for your help.
The proxy body can close over the lexical scope:
(let [pressed? (ref false)]
(proxy [PPath] []
;; ...
(ref-set pressed? true) ;; write ref
@pressed? ;; read ref
;; ...
))
-Per
class ToggleShape extends PPath {
private static final long serialVersionUID = 1L;
private boolean fIsPressed = false;
public ToggleShape() { ; location (1)
<<<<<<<<<<<<<<<<<<<<<
setPathToEllipse(0, 0, 100, 80);
addInputEventListener(new PBasicInputEventHandler() {
public void mousePressed(final PInputEvent event) {
super.mousePressed(event);
fIsPressed = true;
repaint();
}
public void mouseReleased(final PInputEvent event) {
super.mouseReleased(event);
fIsPressed = false;
repaint();
}
});
}
protected void paint(final PPaintContext paintContext) {
if (fIsPressed) {
final Graphics2D g2 = paintContext.getGraphics();
g2.setPaint(getPaint());
g2.fill(getBoundsReference());
}
else {
super.paint(paintContext);
}
}
}
Note that this subclass, ToggleShape, redefines its constructor (see
the line marked "location (1)", above). The question is, what name do
I put to the function that executes the Clojure equivalent of
"setPathToEllipse(0, 0, 100, 80)"? Since proxy creates an anonymous
subclass, the only function named that I could think to use is that of
its superclass, PPath--but I can't get it to work (and the code below
is just one of several variations I've tried).
To eliminate other possible sources of error, I've taken out the event
listeners in the Clojure code below, and all I'm trying to do is have
the program display the %$#@#! ellipse (I can get it to display a
square just fine). I've also put a println statement in the code that
creates an instance of ToggleShape (which does execute), and another
println statement in the code that implements ToggleShape (which DOES
NOT execute).
I've searched the web for articles and source code that might give me
some idea of how to proceed, and I've also consulted Java reference
books, but I haven't found anything that explains what I need to do.
Anyway, here's one version of the corresponding Clojure code:
(defn create-toggle-shape
"Creates an ellipse that changes shape when it is clicked."
[]
(let [fIsPressed? (ref false)
serialVersionUID (long 1)]
(proxy [PPath] [] ; ToggleShape is an extension of PPath
; I'm trying to create the constructor for ToggleShape--proxy
; requires that what follows is a sequence of superclass method-
names-
; arguments-and-bodies. What do I call it here? Since the
superclass is
; PPath, the name of its constructor is PPath, so that's what
I'm
; trying here--but it doesn't seem to work: the println is
; never executed.
(PPath [] ;
; super's constructor should execute automatically
(println "Reached ToggleShape")
(.setPathToEllipse 0 0 100 80)
;add input listeners here
)
(paint [paintContext]
(if (fIsPressed?)
(let [g2 (.getGraphics paintContext)]
(do
(.. g2 setPaint getPaint)
(.fill g2 (.getBoundsReference this))))
(proxy-super paint paintContext))))))
I can post the entire program if anyone wants to see it. As always,
thanks for taking the time to help.
My try. Not tested, though...
(defn create-toggle-shape
"Creates an ellipse that changes shape when it is clicked."
[]
(let [fIsPressed? (atom false)
shape (proxy [PPath] []
(paint
[#^PPaintContext paintContext]
(if @fIsPressed?
(doto (.getGraphics paintContext)
(.setPaint (.getPaint this))
(.fill (.getBoundReference this)))
(proxy-super paint paintContext))))]
(doto shape
(.setPathToEllipse 0 0 100 80)
(.addInputEventListener
(proxy [PBasicInputEventHandler] []
(mousePressed
[evt]
(proxy-super mousePressed evt)
(reset! fIsPressed? true)
(.repaint shape))
(mouseReleased
[evt]
(proxy-super mouseReleased evt)
(reset! fIsPressed? false)
(.repaint shape)))))))
Sincerely
Meikel