Я пытаюсь получить println
для вывода в произвольное место либо на emacs-cider repl, либо в JavaFX TextArea. Я ссылался на Why can't I print from background threads, и это позволило мне сделать println
из потока JavaFX, перевязав *out*
на начальный поток.Clojure rebinding * out * для элементов интерфейса JavaFX
Однако это не работает, когда println
вызывается из ChangeListener
, независимо от того, создан он вне или внутри потока JFX.
В тексте ниже я два TextField
с, один созданный в основном потоке, один созданный в JFX тему, а также два экземпляра ChangeListener, один в качестве defstruct
, который реализует интерфейс, а другой в качестве reify
, оба из которых создаются из потока JFX.
Каждый раз, когда я набираю символ в любом из двух TextField
s, текст ответа отображается в потоке исходного потока *out*
.
Как исправить это, так что все println
s найти правильный *out*
, как планировалось?
благодаря
(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))
Отлично, это сработало, спасибо :) Почему это работает? – Sonicsmooth
Фактически, он работал для первого текстового поля 'alter'ing' * out * 'to' (постоянно * out *) 'или другого' PrintWriter', но для второго текстового поля он работал только для 'alter'ing' * out * 'to' (постоянно * out * ')', но не к другому PW, по-видимому, имеющему отношение к тому, в какой поток был создан PW. Я просто снимаюсь в темноте. Мне нужно изучить это лучше. Благодарю. – Sonicsmooth
Я обновил свой ответ с кратким описанием того, почему это работает. Вам нужно только один раз изменить корневое связывание и не нужно вызывать его в каждом потоке, который вы создаете. Я не вижу изменений, которые вы внесли в свой код после добавления alter-var-root, но я бы предположил, что вы пытаетесь вызвать его в каждом потоке, а не просто привязывать его один раз к желаемому значению. – Symfrog