2015-01-07 3 views
1

Я пытаюсь получить 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)) 

ответ

1

Вы пробовали изменять корень из уага из? например

(alter-var-root #'*out* (constantly *out*)) 

с помощью binding разрешит вар к связанному значение только для текущего потока.

Другие темы будут продолжать видеть корневое значение var, если только binding не используется в этих потоках.

Обратные вызовы (например, ChangeListener) вызываются из потоков, которые не находятся под вашим контролем, и поэтому не имеют привязок к потокам. Они разрешат корневое значение var.

Поэтому вы должны изменить значение корня вне, чтобы эти потоки разрешали значение, которое вы хотите.

Имеется дополнительная информация о привязках к перепадам. here.

+0

Отлично, это сработало, спасибо :) Почему это работает? – Sonicsmooth

+0

Фактически, он работал для первого текстового поля 'alter'ing' * out * 'to' (постоянно * out *) 'или другого' PrintWriter', но для второго текстового поля он работал только для 'alter'ing' * out * 'to' (постоянно * out * ')', но не к другому PW, по-видимому, имеющему отношение к тому, в какой поток был создан PW. Я просто снимаюсь в темноте. Мне нужно изучить это лучше. Благодарю. – Sonicsmooth

+0

Я обновил свой ответ с кратким описанием того, почему это работает. Вам нужно только один раз изменить корневое связывание и не нужно вызывать его в каждом потоке, который вы создаете. Я не вижу изменений, которые вы внесли в свой код после добавления alter-var-root, но я бы предположил, что вы пытаетесь вызвать его в каждом потоке, а не просто привязывать его один раз к желаемому значению. – Symfrog

Смежные вопросы