Clojure为JavaFXUI元素重新绑定*out*
我试图将Clojure为JavaFXUI元素重新绑定*out*,clojure,javafx,Clojure,Javafx,我试图将println输出到任意位置,无论是在emacs苹果汁repl上还是在JavaFX文本区域。我已经引用了,这允许我通过将*out*重新绑定到起始线程,从JavaFX线程中执行println 但是,当从ChangeListener调用println时,无论是在JFX线程外部还是内部创建的,这都不起作用 在下面的文本中,我有两个TextFields,一个在主线程中创建,一个在JFX线程中创建,还有两个ChangeListener实例,一个作为实现接口的defstruct,另一个作为reify
println
输出到任意位置,无论是在emacs苹果汁repl上还是在JavaFX文本区域。我已经引用了,这允许我通过将*out*
重新绑定到起始线程,从JavaFX线程中执行println
但是,当从ChangeListener
调用println
时,无论是在JFX线程外部还是内部创建的,这都不起作用
在下面的文本中,我有两个TextField
s,一个在主线程中创建,一个在JFX线程中创建,还有两个ChangeListener实例,一个作为实现接口的defstruct
,另一个作为reify
,都是从JFX线程中实例化的
每次我在两个TextField
s中的任意一个字段中键入一个字符时,响应文本都会显示在原始线程的*out*
流中
如何修复此问题,以便所有的println
s都能按预期找到正确的*输出*
谢谢
您是否尝试过更改out的var根?e、 g 使用
binding
将仅为当前线程将var解析为绑定值
其他线程将继续看到var的根值,除非在这些线程中也使用了binding
回调(例如ChangeListener)是从不受您控制的线程调用的,因此没有每线程绑定。它们将解析var的根值
因此,您必须更改out的根值,以便这些线程解析您想要的值
关于var绑定还有更多信息。实际上,它对第一个文本字段
alter
ing*out*
到(持续*out*)
或另一个PrintWriter
有效,但对第二个文本字段,它只对alter
ing*out*
到(持续*out*
)有效`但不是另一个PW,可能与PW是在哪个线程中创建的有关。我只是在黑暗中拍摄。我需要更好地研究这个。谢谢。我已经更新了我的答案,简短地描述了为什么这是有效的。您只需更改根绑定一次,而不必在实例化的每个线程中调用它。在添加altervar root之后,我看不到您在代码中所做的修改,但我想您正在尝试在每个线程中调用它,而不是只将它绑定一次到所需的值。
(ns junk.core
(:gen-class )
(:use jfxutils.core)
(:import (javafx.beans.value ObservableValue ChangeListener)
(javafx.stage Stage)
(javafx.scene Scene)
(javafx.scene.control TextArea TextField)
(javafx.scene.layout VBox)
(java.io PrintStream PrintWriter)))
(defn make-vbox-scene [& items]
(let [vb (VBox.)
scene (Scene. vb)]
(apply add-to-children vb items)
scene))
(defn make-window [scene & [width height]]
(let [stage (Stage.)]
(.setScene stage scene)
(when width (.setWidth stage width))
(when height (.setHeight stage height))
stage))
(defrecord myobservable []
ChangeListener
(^void changed [this ^ObservableValue obsval oldval newval]
;; This println goes to the original *out* stream
(println "Myobservable thread" (Thread/currentThread) ", *out* is " *out*)))
(def text1 (TextField. "hi")) ;; Created in main thread
(defn -start [myout]
;; Everything here is in JFX thread
(println "JFX thread is " (Thread/currentThread) ",JFX *out* is " *out*)
(binding [*out* myout] ;; only works for obvious/direct println, not from UI
(let [myobs (myobservable.) ;; Created in JFX thread
text2 (TextField. "bye") ;; Created in JFX thread
vbscene1 (make-vbox-scene text1 text2)
window1 (make-window vbscene1)]
;; This println works! Output goes to cider-repl or other PrintWriter pointed to by myout.
(println "After rebinding out, thread is " (Thread/currentThread) "*out* is " *out*)
;; These printlns go to the original *out* stream in the *nrepl-server junk* buffer, not cider
;; This means I also can't reassign the myout arg to some other PrintWriter
(-> text1 .textProperty (.addListener myobs))
(-> text1 .textProperty (.addListener (reify ChangeListener
(changed [this obsval oldval newval]
(println "Anonymous listener 1, thread is " (Thread/currentThread) "*out* is " *out*)))))
(-> text2 .textProperty (.addListener myobs))
(-> text2 .textProperty (.addListener (reify ChangeListener
(changed [this obsval oldval newval]
(println "Anonymous listener 2, thread is " (Thread/currentThread) "*out* is " *out*)))))
(.show window1))))
(defn main []
(println "main thread is " (Thread/currentThread) ", *out* is " *out*)
(run-now (-start *out*)))
(defn -main []
(javafx.application.Platform/setImplicitExit true) ;; Undoes false from jfxutils
(main))
(alter-var-root #'*out* (constantly *out*))