This is a kind of continuation of monitoring violations of flow rules when mixing Swing / FX and linking both parts to the same model.
Meanwhile, I experimented a bit: use a custom property whose only task is to take care of access / notification in EDT / fx-thread, respectively. The idea is that a custom property
- supported by property to be accessed by EDT
- used on the fx side, i.e. its fx api is called from FX-AT
- its task is to call / runLater accordingly
Gets an exemption from flow rule violations ... at a price: when you enter the fx text field, the carriage is placed at the beginning of the text, thereby adding each character. Before continuing, questions
- Is it possible that a wrapper like the one below might work?
- is something wrong? (Being a bloody newbie in the game, I could be doing something incredibly stupid ;-)
- What is the reason for setting the carriage?
Code (can be reproduced in SSCCE of the previous question, one change is to uncomment the creation of the shell and use this instead of directly linking text to the field)
@SuppressWarnings({ "unchecked", "rawtypes" })
public class PropertyWrapper<T> extends ObjectPropertyBase<T> {
private Property<T> delegate;
private volatile T value;
private String delegateName;
private ChangeListener<T> changeListener;
public PropertyWrapper(Property<T> delegate) {
this.delegate = delegate;
bindDelegate();
}
@Override
public T get() {
return value;
}
@Override
public void set(T value) {
updateToDelegate(value);
}
protected void updateToDelegate(final T value) {
if (SwingUtilities.isEventDispatchThread()) {
doUpdateToDelegate(value);
} else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
doUpdateToDelegate(value);
}
});
}
}
private void doUpdateToDelegate(T value) {
delegate.setValue(value);
}
private void bindDelegate() {
if (changeListener != null) throw new IllegalStateException("cannot bind twice");
value = delegate.getValue();
delegateName = delegate.getName();
changeListener = createChangeListener();
delegate.addListener(
changeListener);
}
private ChangeListener<T> createChangeListener() {
ChangeListener<T> l = new ChangeListener<T>() {
@Override
public void changed(ObservableValue<? extends T> observable,
T oldValue, T newValue) {
updateFromDelegate(newValue);
}
};
return l;
}
protected void updateFromDelegate(final T newValue) {
if (Platform.isFxApplicationThread()) {
doUpdateFromDelegate(newValue);
} else {
Platform.runLater(new Runnable() {
@Override
public void run() {
doUpdateFromDelegate(newValue);
}});
}
}
protected void doUpdateFromDelegate(T newValue) {
value = newValue;
fireValueChangedEvent();
}
@Override
protected void fireValueChangedEvent() {
if (Platform.isFxApplicationThread()) {
superFireChangedEvent();
} else {
Platform.runLater(new Runnable() {
@Override
public void run() {
superFireChangedEvent();
}});
}
}
protected void superFireChangedEvent() {
super.fireValueChangedEvent();
}
@Override
public Object getBean() {
return null;
}
@Override
public String getName() {
return delegateName;
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger.getLogger(PropertyWrapper.class
.getName());
}
source
share