Ein Observable Value Viewer ist ein Widget, welches einen Observable Value visualisiert und (optional) eine Modifikation des Wertes ermöglicht.
Die Schnittstelle IObservableValueViewer
ist wie folgt definiert:
public interface IObservableValueViewer<VALUE_TYPE> { IObservableValue<VALUE_TYPE> getObservableValue(); }
Die Schnittstelle wird derzeit von den folgenden Widgets implementiert:
Die BluePrints dieser Widgets haben jeweils die Methode:
BLUE_PRINT_TYPE setObservableValue(IObservableValue<VALUE_TYPE> value);
Dadurch wird der übergebene Obserservable Value an den neu erzeugten Viewer gebunden. Das Binding wird wieder gelöst, wenn das Widget disposed wird. Man kann dadurch anstatt:
1 final IObservableValue<Double> value = new ObservableValue<Double>(0.0d); 2 3 //add slider 4 final ISliderViewerBluePrint<Double> sliderBp = BPF.sliderViewerDouble(-1.0d, 1.0d); 5 final ISliderViewer<Double> sliderViewer = frame.add(sliderBp, "w 50::"); 6 7 final IBinding binding = Bind.bind(value, sliderViewer.getObservableValue()); 8 sliderViewer.addDisposeListener(new IDisposeListener() { 9 @Override 10 public void onDispose() { 11 binding.dispose(); 12 } 13 });
einfach das folgende Schreiben:
1 final IObservableValue<Double> value = new ObservableValue<Double>(0.0d); 2 3 //add slider 4 final ISliderViewerBluePrint<Double> sliderBp = BPF.sliderViewerDouble(-1.0d, 1.0d); 5 sliderBp.setObservableValue(value); 6 frame.add(sliderBp, "w 50::");
Das ObservableValueSnipped verwendet einen Observable Value, um ein SliderViewer und ein InputField aneinander zu binden:
1 public final class ObservableValueViewerSnipped implements IApplication { 2 3 @Override 4 public void start(final IApplicationLifecycle lifecycle) { 5 6 //create the root frame 7 final IFrameBluePrint frameBp = BPF.frame("Observable value viewer snipped"); 8 final IFrame frame = Toolkit.createRootFrame(frameBp, lifecycle); 9 frame.setLayout(new MigLayoutDescriptor("wrap", "[][][]", "[]")); 10 11 //create panorama observable value 12 final IObservableValue<Double> panorama = new ObservableValue<Double>(0.0d); 13 14 //add panorama label 15 final ITextLabelBluePrint labelBp = BPF.textLabel("Panorama"); 16 labelBp.setForegroundColor(Colors.STRONG).setMarkup(Markup.STRONG); 17 frame.add(labelBp); 18 19 //add panorama slider 20 final ISliderViewerBluePrint<Double> sliderBp = BPF.sliderViewerDouble(-1.0d, 1.0d); 21 sliderBp.setObservableValue(panorama); 22 frame.add(sliderBp, "growx, w 150!"); 23 24 //add panorama input field 25 final IInputFieldBluePrint<Double> inputFieldBp = BPF.inputFieldDoubleNumber(); 26 inputFieldBp.setObservableValue(panorama); 27 frame.add(inputFieldBp, "w 50!"); 28 29 //set the root frame visible 30 frame.setVisible(true); 31 } 32 }
Änderungen am Slider modifizieren das Eingabefeld und umgekehrt. Die folgende Abbildung zeigt das Ergebnis:
Das BindingSnipped verwendet mehrere Observable Values, um jeweils ein SliderViewer und ein InputField aneinander zu binden. Zudem kann man über eine Checkbox das Binding aller Observable Values untereinander aktivieren oder deaktivieren, wodurch sich die Slider und Eingabefelder synchron oder unabhängig voneinander sind:
1 public final class BindingSnipped implements IApplication { 2 3 private static final int COLUMNS = 10; 4 private static final double MIN_VALUE = -1.0d; 5 private static final double MAX_VALUE = 1.0d; 6 private static final double DEFAULT_VALUE = 0.0d; 7 8 @Override 9 public void start(final IApplicationLifecycle lifecycle) { 10 11 //create the root frame 12 final IFrame frame = Toolkit.createRootFrame(BPF.frame("Binding snipped"), lifecycle); 13 frame.setLayout(new MigLayoutDescriptor( 14 "wrap", 15 StringUtils.loop("[]10", COLUMNS - 1) + "[]", 16 "[]0[]20[]")); 17 18 //create observable values and bindings 19 final ArrayList<IObservableValue<Double>> observableValues 20 = new ArrayList<IObservableValue<Double>>(COLUMNS); 21 final ArrayList<IBinding> bindings = new ArrayList<IBinding>(COLUMNS - 1); 22 for (int i = 0; i < COLUMNS; i++) { 23 final IObservableValue<Double> observableValue = new ObservableValue<Double>(); 24 observableValues.add(observableValue); 25 if (i > 0) { 26 //bind next value to the previous 27 final IBinding binding = Bind.bind( 28 observableValues.get(i - 1), 29 observableValue); 30 bindings.add(binding); 31 } 32 } 33 34 //add sliders 35 for (int i = 0; i < COLUMNS; i++) { 36 final ISliderViewerBluePrint<Double> sliderBp 37 = BPF.sliderViewerDouble(MIN_VALUE, MAX_VALUE); 38 sliderBp.setVertical(); 39 sliderBp.setDefaultValue(DEFAULT_VALUE); 40 sliderBp.setObservableValue(observableValues.get(i)); 41 frame.add(sliderBp, "w 50::"); 42 } 43 44 //add input fields 45 for (int i = 0; i < COLUMNS; i++) { 46 final IInputFieldBluePrint<Double> inputFieldBp 47 = BPF.inputFieldDoubleNumber(); 48 inputFieldBp.setObservableValue(observableValues.get(i)); 49 frame.add(inputFieldBp, "w 50::"); 50 } 51 52 //add binding checkbox 53 final ICheckBox bindingCb = frame.add(BPF.checkBox().setText("Bind")); 54 bindingCb.setSelected(true); 55 bindingCb.addInputListener(new IInputListener() { 56 @Override 57 public void inputChanged() { 58 for (final IBinding binding : bindings) { 59 binding.setBindingState(bindingCb.isSelected()); 60 } 61 } 62 }); 63 64 //set the root frame visible 65 frame.setVisible(true); 66 } 67 }
Die folgende Abbildung zeigt das Ergebnis: