Ah yes, good catch. That is intentional for now, as I don't want to
kill the Swank server I'm using every time I close the window. That
brings up a good point though - it would be nice to be able to have
code know when it being executed inside an IDE as opposed to
independently; that way I could have the window closing event trigger
a system exit only when it is being run independently, and do nothing
when it is run from within the IDE.

I've expanded the code into an animating graphing calculator. The user
enters Clojure code (in the text box) which generates a function that
returns y in terms of x and t (t is the time variable). When the user
hits enter, the function is drawn, and updated every few milliseconds
with incrementing t values. So you can write for example a sine
function that moves to the left as "(fn [x t] (sin (+ (/ x 2) (/ t
10))))"

The full code is posted here for those interested:
http://curransoft.com/code/clj-grapher-20090511.zip

It's an intermediate stage of a larger project which will eventually
involve parsing a simple math language and rendering a 3D surface
using OpenGL. I've learned a lot from progressing thus far and thought
I'd share some thoughts:

 - I realized that I had the model-view-controller idea wrong. I
thought the model was the data, the view was the GUI components which
reflect the model, and the controller was the gui components which
change the model. This is wrong - the correct model model-view-
controller idea is as follows (I'm pretty sure) the model is the data,
the view is the entire gui definition which is not dependent upon the
model whatsoever, and the controller is the glue code that handles all
communication between the model and view (for example, it adds the
appropriate listeners to GUI components for changing the model, and
also adds listeners to (or polls for changes in) model components that
trigger view updates.
 - I've discovered the greatness of the following Clojure functions/
macros: (constantly) (add-watch) (doseq) (future) #(... %)
 - I came up with a syntactically sweet solution for listening to many
mutable objects with many functions, which is perfect when defining
the controller. Here it is:

(defn link
  "Expects a sequence of refs and a sequence of functions. Adds a
watch (via add-watch) to the refs which calls the functions
sequentially\
s in the order given."
  [refs functions]
  (let [f (fn [k r o n] (doseq [f functions] (f)))]
    (doseq [r refs] (add-watch r (str (gensym)) f))))

;example use in my code:
(link [function-str] [generate-compiled-function update-x-values
update-y-values])
(link [function-str num-lines window time-value] [#(.repaint graphics-
panel)])

Problems:
 - I assumed that calls to the watch functions placed on my refs and
atoms would be called synchronously, within the thread which changed
the value of the ref or agent via (dosync (ref-set...)) or
(swap! ...). Evidently this is not the case, because I can see visual
artifacts of the data changing midway through a call to repaint(),
which reads the data (from a java array). The code that changes the
data is invoked by a loop executing in a thread spawned by (future). I
need to have everything happening synchronously for correct
performance, and I can't create a new seq of values every time because
I would observe garbage collection as visible pauses in the animation
(I've tried - I'm pretty sure this is a case where mutable java
primitive arrays are preferable to Clojure seqs)

 - When attempting to use multiple namespaces within Emacs+SLIME, it
seems that in order to define namespace A which depends namespace B
(regardless of whether or not namespace B is already defined in the
environment), one must put the path to the file defining namespace B
on the classpath. I'm sure this issue can be resolved somehow, but for
now has led me to just use (load-file) instead of having real
namespaces. I think it should (ideally) be possible to reference
namespaces that are currently loaded, without the need to have them on
the classpath.

Have a great day!

Curran
On May 11, 7:26 am, fendres <198...@web.de> wrote:
> On May 8, 4:25 am, Curran Kelleher <curran.kelle...@gmail.com> wrote:
>
>
>
> > Hello,
>
> > I've posted an example of a simple model-view-controller GUI skeleton
> > in Clojure 
> > here:http://lifeofaprogrammergeek.blogspot.com/2009/05/model-view-controll...
>
> > The GUI has a text box and a panel which draws what you type. It's not
> > much, but I learned a lot doing it, and thought perhaps others could
> > benefit from seeing it.
>
> > The add-watch function is so cool!
>
> > There's probably lots of room for improvement, I would appreciate any
> > recommendations. I've started looking at neman.cells, but don't really
> > understand it yet. Might using cells simplify this code?
>
> > Best,
> > Curran
>
> Hi, nice example. The application doesn't quit on window-close (alt
> +f4) though.
> Regards,
> Felix
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to