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*))