I'd like my Clojure program to exit when a JFrame is closed.
I'm attempting to trap and handle the close event as such:
(def exit-action (proxy [WindowAdapter] []
(windowClosing [event] (fn [] (System/exit 0)))
)
)
(.addWindowListener frame exit-action)
This doesn't throw any obvious errors but it also doesn't appear to do what I want.
Assistance is appreciated.
Answer:
Adapting Rekin's answer did the trick:
(.setDefaultCloseOperation frame JFrame/EXIT_ON_CLOSE)
Note that that is:
setDefaultCloseOperation
not:
setDefaultOperationOnClose
In Java it's:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
More elaborate examples can be found in official Java Swing tutorial about Frames
I would use EXIT_ON_CLOSE, but the reason your first attempt didn't work is that the body of proxy should contain (System/exit 0), not (fn [] (System/exit 0)). Rather than exiting, you were returning (and then throwing away) a function that, when called, would exit.
Here's a short demonstration program I showed on my blog a while ago
(ns net.dneclark.JFrameAndTimerDemo
(:import (javax.swing JLabel JButton JPanel JFrame Timer))
(:gen-class))
(defn timer-action [label counter]
(proxy 1 []
(actionPerformed
[e]
(.setText label (str "Counter: " (swap! counter inc))))))
(defn timer-fn []
(let [counter (atom 0)
label (JLabel. "Counter: 0")
timer (Timer. 1000 (timer-action label counter))
panel (doto (JPanel.)
(.add label))]
(.start timer)
(doto (JFrame. "Timer App")
(.setContentPane panel)
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(.setLocation 300 300)
(.setSize 200 200)
(.setVisible true)))
(println "exit timer-fn"))
(defn -main []
(timer-fn))
Note the line in timer-fn[] that sets the default close operation. Just about like Java but with a little syntax fiddling.
The purpose of the blog entry was to show an example of a closure in Clojure.
Related
I want to make a click handler function for an Om component. The docs and Stack Overflow examples I've found always declare anonymous functions like this
(defn main-view [_ owner]
(reify
om/IRender
(render [_]
(let [xs (items)]
(dom/div nil
(om/build sub-view {:title "View A"})
(om/build sub-view {:title "View B"})
(dom/button
#js {:onClick
(fn [e] (om/transact! xs #(assoc % 1 {:text "zebra"})))}
"Switch To Zebra!"))))))
I think it's cleaner to declare click functions outside the jsx/template area, within the component, the way it's commonly done in regular React. Is there a way do this in Om within the component? I tried this, but it doesn't work because onClick is undefined:
(defn my-component []
(reify
om/IRender
(render [this]
; Using Sablono syntax
(html [:h1 "Here is a heading" {:on-click 'onClick} ]))
onClick
(onClick [this]
; this part never gets executed when you click
(.log js/console "click"))))
I'd like to avoid defining a separate function outside the component if it's possible.
Your question is sensible and it's about handling scope of data.
It is possible but the problem with this approach in most cases you will need local scope data from the outside code block (in your case, it's an Om component).
I would explain in code. Let's say you want to move handler function out:
(anything
(let [a 1 b 2]
(on-event (fn my-handler [evt] (log (+ a b (.someAttr evt)))))))
You'll end up with this which is way longer:
(defn local-data->handler [a b]
(fn [evt] (log (+ a b (.someAttr evt)))))
(anything
(let [a 1 b 2]
(on-event (local-data->handler a b))))
in case you just want to move around inside the component definition:
(anything
(let [a 1
b 2
my-handler (fn [evt] (log (+ a b (.someAttr evt))))]
(on-event my-handler)))
Please note: to keep event handler work, ensure your non-anonymous function (created with defn or let) is the same as the anonymous form, especially argument list.
onClick is undefined because you use it as if it's an Om protocol. Please consult Om lifecycle protocols for correct usage.
https://github.com/swannodette/om/wiki/Documentation
Per your requirements, you should move the function definition out of the component.
You should then be able to pass the function's name to the event listener:
(defn foo [] (println "foo"))
(defn my-component [text owner]
(reify
om/IRender
(render [_]
(dom/button
#js { :onClick foo }
"Click Here"))))
Everybody is talking about how great core.async is, and how it will improve event handling in clojurescript. I've been following the ClojureScript 101 tutorial, and I don't see any clear advantage from these code examples. What am I missing?
Why is the use of core.async any better here?
(defn listen [el type]
(let [out (chan)]
(events/listen el type
(fn [e] (put! out e)))
out))
(defn dosomethingasync
[e]
(js/console.log "async: " e))
(let [clicks (listen (dom/getElement "search1") "click")]
(go (while true (dosomethingasync (<! clicks)))))
vs.
(defn dosomethingcallback
[e]
(js/console.log "callback: " e))
(events/listen (dom/getElement "search2") "click" dosomethingcallback)
Great question!
I think your first step to understand the advantage would be Timothy Baldridge Video
And below my try:
I think that the differences will clear up if we change a bit your code.
Firstly, trying to highlight the sentence "There comes a time in all good programs when components or subsystems must stop communicating directly with one another" extracted from the presentation of core.async posted on the clojure blog. I think that we can separate the input events channel from the let fn:
(def clicks (listen (dom/getElement "search1") "click"))
(go
(while true
(dosomethingasync (<! clicks))))
(put! clicks "this channel can be written from differents parts of your code")
Secondly, with core.async we can write asynchronous calls as we'll write synchronous calls (sequential code). An example of this situation require more than one channel:
(def clicks (listen (dom/getElement "search1") "click"))
(def keys-pressed (listen (dom/getElement "search1") "keypress"))
(def to-out (chan))
(go
(while true
(let [click-recieved (<! clicks)]
(dosomethingasync click-recieved)
(>! to-out "click recieved!")
(let [other-input-waited (<! keys-pressed)]
(dosomethingwithkey other-input-waited)
(>! to-out "keypressed recieved!")
)
)
))
And lastly, i think that you are not properly using the meaning of callback function. When we talk of a callback function i think we are referring to a function that besides its own parameters it receives a function "callback". At the end of the execution of the function we call the callback function to return the execution flow to the original point.
Changing your "callback" function come up as follow:
(defn dosomethingcallback
[e call-back-fn]
(js/console.log "callback: " e)
(call-back-fn))
And if we try to issue something similar to the same behaviour achieved with previous code core.async example:
(defn do-key
[call-back-fn e]
(.log js/console "before callback key" )
(call-back-fn e))
(defn do-click
[call-back-fn e]
(.log js/console "before callback click")
(call-back-fn e))
(defn key-callback-fn [e]
(.log js/console (str "doing some work with this key: " e))
)
(defn click-callback-fn [e]
(.log js/console (str "doing some work with this click" e))
(events/listen (dom/getElement "search2") "keypress" (partial do-key key-callback-fn)))
(events/listen (dom/getElement "search2") "click" (partial do-click click-callback-fn))
I have adapted this method from p.216 Joy of Clojure.
(defn makeButton [txt func panel]
(let [btn (JButton. txt) ] ;bfun (symbol func) ]
(doto btn
(.addActionListener
(proxy [ActionListener] [] (actionPerformed [_]
(func))) ;(bfun)))
))
(.add panel btn)
))
Plus this test code:
(defn fba [] (prn "fba"))
(defn fbb [] (prn "fbb"))
(def funs [fba fbb])
(def btnames ["B1" "B2"])
Buttons & actionPerformed are created thusly in a gui setup function:
(doseq [i (range (count btnames)) ]
(makeButton (get btnames i) (nth funs i) aJpanel))
This works as I want; clicking "B1" prints string "fba", etc. My difficulty arises when I want to attach to 'actionPerformed' something such as: ns1.ns2/myFunction instead of these simple cases (i.e. use a list/vector of several namespaced qualified functions). The exception reported is
wrong number of args (0) passed to Symbol
From the 'makeButton' function above my attempt to solve this is commented out. What is an idiomatic clojure solution to this?
This code works for me in the REPL. I'm using clojure.pprint/pprint as an example of a function that is in a different namespace:
(import '[javax.swing JFrame JPanel JButton]
'[java.awt.event ActionListener])
(def panel (JPanel.))
(def frame (doto (JFrame. "Hello Frame")
(.setContentPane panel)
(.setSize 200 200)
(.setVisible true)))
(defn make-button [label f panel]
(let [button (JButton. label)]
(doto button
(.addActionListener
(proxy [ActionListener] []
(actionPerformed [evt]
(f evt)))))
(.add panel button)))
(make-button "One" clojure.pprint/pprint panel)
(.revalidate frame)
Environment: Clojure 1.4
I'm trying to pull function metadata dynamically from a vector of functions.
(defn #^{:tau-or-pi: :pi} funca "doc for func a" {:ans 42} [x] (* x x))
(defn #^{:tau-or-pi: :tau} funcb "doc for func b" {:ans 43} [x] (* x x x))
(def funcs [funca funcb])
Now, retrieving the metadata in the REPL is (somewhat) straight-forward:
user=>(:tau-or-pi (meta #'funca))
:pi
user=>(:ans (meta #'funca))
42
user=>(:tau-or-pi (meta #'funcb))
:tau
user=>(:ans (meta #'funcb))
43
However, when I try to do a map to get the :ans, :tau-or-pi, or basic :name from the metadata, I get the exception:
user=>(map #(meta #'%) funcs)
CompilerException java.lang.RuntimeException: Unable to resolve var: p1__1637# in this context, compiling:(NO_SOURCE_PATH:1)
After doing some more searching, I got the following idea from a posting in 2009 (https://groups.google.com/forum/?fromgroups=#!topic/clojure/VyDM0YAzF4o):
user=>(map #(meta (resolve %)) funcs)
ClassCastException user$funca cannot be cast to clojure.lang.Symbol clojure.core/ns-resolve (core.clj:3883)
I know that the defn macro (in Clojure 1.4) is putting the metadata on the Var in the def portion of the defn macro so that's why the simple (meta #'funca) is working, but is there a way to get the function metadata dynamically (like in the map example above)?
Maybe I'm missing something syntactically but if anyone could point me in the right direction or the right approach, that'd would be great.
Thanks.
the expression #(meta #'%) is a macro that expands to a call to defn (actually def) which has a parameter named p1__1637# which was produced with gensym and the call to meta on that is attempting to use this local parameter as a var, since no var exists with that name you get this error.
If you start with a vector of vars instead of a vector of functions then you can just map meta onto them. You can use a var (very nearly) anywhere you would use a function with a very very minor runtime cost of looking up the contents of the var each time it is called.
user> (def vector-of-functions [+ - *])
#'user/vector-of-functions
user> (def vector-of-symbols [#'+ #'- #'*])
#'user/vector-of-symbols
user> (map #(% 1 2) vector-of-functions)
(3 -1 2)
user> (map #(% 1 2) vector-of-symbols)
(3 -1 2)
user> (map #(:name (meta %)) vector-of-symbols)
(+ - *)
user>
so adding a couple #'s to your original code and removing an extra trailing : should do the trick:
user> (defn #^{:tau-or-pi :pi} funca "doc for func a" {:ans 42} [x] (* x x))
#'user/funca
user> (defn #^{:tau-or-pi :tau} funcb "doc for func b" {:ans 43} [x] (* x x x))
#'user/funcb
user> (def funcs [#'funca #'funcb])
#'user/funcs
user> (map #(meta %) funcs)
({:arglists ([x]), :ns #<Namespace user>, :name funca, :ans 42, :tau-or-pi :pi, :doc "doc for func a", :line 1, :file "NO_SOURCE_PATH"} {:arglists ([x]), :ns #<Namespace user>, :name funcb, :ans 43, :tau-or-pi :tau, :doc "doc for func b", :line 1, :file "NO_SOURCE_PATH"})
user> (map #(:tau-or-pi (meta %)) funcs)
(:pi :tau)
user>
Recently, I found it useful to attach metadata to the functions themselves rather than the vars as defn does.
You can do this with good ol' def:
(def funca ^{:tau-or-pi :pi} (fn [x] (* x x)))
(def funcb ^{:tau-or-pi :tau} (fn [x] (* x x x)))
Here, the metadata has been attached to the functions and then those metadata-laden functions are bound to the vars.
The nice thing about this is that you no longer need to worry about vars when considering the metadata. Since the functions contain metadata instead, you can pull it from them directly.
(def funcs [funca funcb])
(map (comp :tau-or-pi meta) funcs) ; [:pi :tau]
Obviously the syntax of def isn't quite as refined as defn for functions, so depending on your usage, you might be interested in re-implementing defn to attach metadata to the functions.
I'd like to elaborate on Beyamor's answer. For some code I'm writing, I am using this:
(def ^{:doc "put the-func docstring here" :arglists '([x])}
the-func
^{:some-key :some-value}
(fn [x] (* x x)))
Yes, it is a bit unwieldy to have two metadata maps. Here is why I do it:
The first metadata attaches to the the-func var. So you can use (doc the-func) which returns:
my-ns.core/the-func
([x])
put the-func docstring here
The second metadata attaches to the function itself. This lets you use (meta the-func) to return:
{:some-key :some-value}
In summary, this approach comes in handy when you want both docstrings in the REPL as well as dynamic access to the function's metadata.
I am using ClojureScript to detect which browser-specific version of 'requestAnimationFrame' method is defined. I use the following code:
(defn animationFrameMethod []
(let [window (dom/getWindow)
options (list #(.-requestAnimationFrame window)
#(.-webkitRequestAnimationFrame window)
#(.-mozRequestAnimationFrame window)
#(.-oRequestAnimationFrame window)
#(.-msRequestAnimationFrame window))]
((fn [[current & remaining]]
(cond
(nil? current) #((.-setTimeout window) % (/ 1000 30))
(fn? (current)) (current)
:else (recur remaining)))
options)))
This works fine, and it's not terrible, but I would really like to be able to put the method names in a list, i.e.
'(requestAnimationFrame webkitRequestAnimationFrame ...)
And then call a macro for each symbol in the list to generate the anonymous function code.
I would like something to work like so:
user> (def name webkitRequestAnimationFrame)
user> (macroexpand '(macros/anim-method name window))
#(.-webkitRequestAnimationFrame window)
But I played around with macros for a while, and was unable to achieve this effect. Part of the problem is that method names and the dot notation work strangely, and I'm not even sure if this is possible.
Any tips to get this working? Thanks!
Remember that javascript objects are also associative hashes, so something like this should work without resorting to macros (untested)....
(def method-names ["requestAnimationFrame"
"webkitRequestAnimationFrame"
"mozRequestAnimationFrame"
"oRequestAnimationFrame"
"msRequestAnimationFrame"])
(defn animationFrameMethod []
(let [window (dom/getWindow)
options (map (fn [n] #(aget window n)) method-names)]
((fn [[current & remaining]]
(cond
(nil? current) #((.-setTimeout window) % (/ 1000 30))
(fn? (current)) (current)
:else (recur remaining)))
options)))