これは、Swing/FXを混在させ、両方のパーツを同じモデルにバインドするときに、スレッド ルール違反を確認するための一種のフォローアップです。
その間、私は少し実験しました: EDT/fx スレッドでのアクセス/通知をそれぞれ処理する唯一のタスクを持つカスタム プロパティを使用します。アイデアは、カスタムプロパティ
- EDT でアクセスする必要があるプロパティによってサポートされている
 - fx 側で使用されます。つまり、その fx API は FX-AT から呼び出されます。
 - そのタスクは、必要に応じて呼び出し/実行することです
 
スレッド ルール違反を取り除きます ... 代償を払って: fx テキスト フィールドに入力すると、キャレットがテキストの先頭に設定されるため、各文字が先頭に追加されます。先に進む前に、質問は
- 以下のようなラッパーが機能する可能性はありますか?
 - それは何か間違ったことをしていますか?(ゲームの血まみれの初心者である私は、信じられないほど愚かなことをしているかもしれません;-)
 - キャレット設定の理由は何ですか?
 
コード (前の質問の SSCCE で再生できます。単一の変更は、ラッパー作成のコメントを解除し、フィールドへの直接テキスト バインドの代わりにそれを使用することです)
/**
 * Wrapper that switches to FX-AT/EDT as appropriate. The assumption is
 * that the delegate needs to be accessed on the EDT while this property 
 * allows client access on the FX-AT.
 * 
 * @author Jeanette Winzenburg, Berlin
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class PropertyWrapper<T> extends ObjectPropertyBase<T> {
    // the delegate we are keeping synched to
    private Property<T> delegate;
    // the value which is kept in synch (on being notified) with the delegate's value
    // JW: does this make sense at all?
    private volatile T value;
    // keeping a copy of the bean ... ? better not allow accessing at all? 
    // private Object delegateBean;
    private String delegateName;
    private ChangeListener<T> changeListener;
    public PropertyWrapper(Property<T> delegate) {
        this.delegate = delegate;
        bindDelegate();
    }
    /**
     * Returns the value which is kept synched to the delegate's value.
     */
    @Override
    public T get() {
        return value;
    }
    /**
     * Implemented to update the delegate on the EDT
     */
    @Override
    public void set(T value) {
        // PENDING: think about uni-directional binding
        updateToDelegate(value);
    }
    /**
     * Updates the delegate's value to the given value. 
     * Guarantees to do the update on the EDT.
     * 
     * @param value
     */
    protected void updateToDelegate(final T value) {
        if (SwingUtilities.isEventDispatchThread()) {
            doUpdateToDelegate(value);
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    doUpdateToDelegate(value);
                }
            });
        }
    }
    /**
     * Updates the delegate's value to the given value
     * This methods runs on the thread that it is called from.
     * 
     * @param the value to set. 
     * 
     */
    private void doUpdateToDelegate(T value) {
        delegate.setValue(value);
    }
    /**
     * Adds a ChangeListener to the delegate and synchs the value
     * to the delegate's value.
     * 
     * This is called once from the constructor, assuming that the thread it is
     * called on is compatible with the delegates threading rules.
     */
    private void bindDelegate() {
        if (changeListener != null) throw new IllegalStateException("cannot bind twice");
        value = delegate.getValue();
        delegateName = delegate.getName();
        changeListener = createChangeListener();
        delegate.addListener( 
                changeListener); 
    }
    /**
     * Creates and returns the ChangeLister that's registered to the delegate.
     * @return
     */
    private ChangeListener<T> createChangeListener() {
        ChangeListener<T> l = new ChangeListener<T>() {
            @Override
            public void changed(ObservableValue<? extends T> observable,
                    T oldValue, T newValue) {
                updateFromDelegate(newValue);
            }
        };
        // weakchangelistener doesn't work ... for some reason
        // we seem to need a strong reference to the wrapped listener
        // return new WeakChangeListener<T>(l);
        return l;
    }
    /**
     * Updates the internal value and notifies its listeners. Schedules the
     * activity for execution on the fx-thread, if not already called on it.
     * 
     * @param newValue
     */
    protected void updateFromDelegate(final T newValue) {
        if (Platform.isFxApplicationThread()) {
            doUpdateFromDelegate(newValue);
        } else {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    doUpdateFromDelegate(newValue);
                }}); 
        }
    }
    /**
     * Updates the internal value and notifies its listeners. It
     * runs on the thread it is called from.
     * 
     * @param newValue the new value.
     */
    protected void doUpdateFromDelegate(T newValue) {
        value = newValue;
        fireValueChangedEvent();
    }
    /**
     * Overridden to guarantee calling super on the fx-thread.
     */
    @Override
    protected void fireValueChangedEvent() {
        if (Platform.isFxApplicationThread()) {
            superFireChangedEvent();
        } else {
            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    superFireChangedEvent();
                }}); 
        }
    }
    protected void superFireChangedEvent() {
        super.fireValueChangedEvent();
    }
    /**
     * Implemented to return null.<p>
     * PENDING: allow access to delegate's bean? It's risky, as this method
     * most probably will be called on the fx-thread: even if we keep a copy
     * around, clients might poke around the bean without switching to the EDT.
     */
    @Override
    public Object getBean() {
        return null; //delegate != null ? delegate.getBean() : null;
    }
    @Override
    public String getName() {
        return delegateName; //delegate != null ? delegate.getName() : null;
    }
    @SuppressWarnings("unused")
    private static final Logger LOG = Logger.getLogger(PropertyWrapper.class
            .getName());
}