【问题标题】:Leveraging the observer pattern in JavaFX GUI design在 JavaFX GUI 设计中利用观察者模式
【发布时间】:2015-11-01 19:11:47
【问题描述】:

正如在 Swing 上下文中提到的here,GUI 设计经常使用observer pattern。经常使用EventListenerList 中规定的方案,是否有Java FX 示例,例如Converter,专注于模式本身?

【问题讨论】:

    标签: swing javafx observer-pattern observable


    【解决方案1】:

    here 所述,JavaFX 架构倾向于通过实现 Observable 接口的类来绑定 GUI 元素。为此,Irina Fedortsova 在 JavaFX for Swing Developers 的第 5 章中将原始的 Converter 改编为 JavaFX:Implementing a Swing Application in JavaFX

    我已经概括了下面的程序,更新到Java 8 并删除了对现在deprecated builder API 的依赖。在下面的变体中,

    • 名为metersDoubleProperty 用作应用程序的Observable 模型

    • Control 的实例,例如 TextFieldComboBoxSlider,每个函数都作为 modelview,如并为用户提供一种控制交互的方式。

    • ConversionPanel内,添加到ComboBoxInvalidationListener会更新模型TextField视图 em> 根据需要反映当前选中的Unit;添加到TextField 的类似侦听器会在用户键入时更新 模型 本身。

    • SliderConversionPanel 的 个实例之间共享相同的模型,链接滑块和任何监听模型的控件.

      slider.valueProperty().bindBidirectional(meters);
      
    • 每个ComboBox 也有一个模型ObservableList,用户可以从中选择Unit 的实例。

    代码:

    /*
     * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     *   - Redistributions of source code must retain the above copyright
     *     notice, this list of conditions and the following disclaimer.
     *
     *   - Redistributions in binary form must reproduce the above copyright
     *     notice, this list of conditions and the following disclaimer in the
     *     documentation and/or other materials provided with the distribution.
     *
     *   - Neither the name of Oracle or the names of its
     *     contributors may be used to endorse or promote products derived
     *     from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    package converter;
    
    /**
     * @see http://docs.oracle.com/javafx/2/swing/port-to-javafx.htm
     */
    public class Unit {
    
        String description;
        double multiplier;
    
        Unit(String description, double multiplier) {
            super();
            this.description = description;
            this.multiplier = multiplier;
        }
    
        @Override
        public String toString() {
            String s = "Meters/" + description + " = " + multiplier;
            return s;
        }
    }
    
    /*
     * Copyright (c) 2012, 2013 Oracle and/or its affiliates. All rights reserved.
     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     */
    package converter;
    
    /**
     * @see http://docs.oracle.com/javafx/2/swing/port-to-javafx.htm
     */
    import java.text.NumberFormat;
    import javafx.beans.InvalidationListener;
    import javafx.beans.Observable;
    import javafx.beans.property.DoubleProperty;
    import javafx.collections.ObservableList;
    import javafx.scene.control.*;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.VBox;
    import javafx.util.StringConverter;
    
    public class ConversionPanel extends TitledPane {
    
        private static final int MAX = 10000;
        private static final int DIGITS = 3;
    
        private final TextField textField = new TextField();
        private final Slider slider = new Slider(0, MAX, 0);
        private final ComboBox<Unit> comboBox;
        private NumberFormat numberFormat = NumberFormat.getNumberInstance();
        private DoubleProperty meters;
    
        {
            numberFormat.setMaximumFractionDigits(DIGITS);
        }
    
        private InvalidationListener fromMeters = (Observable o) -> {
            if (!textField.isFocused()) {
                textField.setText(numberFormat.format(meters.get() / getMultiplier()));
            }
        };
    
        private InvalidationListener toMeters = (Observable o) -> {
            if (textField.isFocused()) {
                try {
                    Number n = numberFormat.parse(textField.getText());
                    meters.set(n.doubleValue() * getMultiplier());
                } catch (Exception ignored) {
                }
            }
        };
    
        public ConversionPanel(String title, ObservableList<Unit> units, DoubleProperty meters) {
            setText(title);
            setCollapsible(false);
            comboBox = new ComboBox<>(units);
            comboBox.getSelectionModel().select(0);
            comboBox.setConverter(new StringConverter<Unit>() {
    
                @Override
                public String toString(Unit t) {
                    return t.description;
                }
    
                @Override
                public Unit fromString(String string) {
                    throw new UnsupportedOperationException("Not supported yet.");
                }
            });
            setContent(new HBox(new VBox(textField, slider), comboBox));
    
            this.meters = meters;
            meters.addListener(fromMeters);
            comboBox.valueProperty().addListener(fromMeters);
            textField.textProperty().addListener(toMeters);
            slider.valueProperty().bindBidirectional(meters);
            fromMeters.invalidated(null);
        }
    
        /**
         * Returns the multiplier for the currently selected unit of measurement.
         */
        public double getMultiplier() {
            return comboBox.getValue().multiplier;
        }
    }
    
    /*
     * Copyright (c) 2012, 2013 Oracle and/or its affiliates. All rights reserved.
     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     */
    package converter;
    
    import javafx.application.Application;
    import javafx.beans.property.DoubleProperty;
    import javafx.beans.property.SimpleDoubleProperty;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.scene.Scene;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    
    /**
     * @see https://stackoverflow.com/a/31909942/230513
     * @see http://docs.oracle.com/javafx/2/swing/port-to-javafx.htm
     */
    public class Converter extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        private final ObservableList<Unit> metricDistances;
        private final ObservableList<Unit> usaDistances;
        private final DoubleProperty meters = new SimpleDoubleProperty(1);
    
        public Converter() {
            //Create Unit objects for metric distances, and then
            //instantiate a ConversionPanel with these Units.
            metricDistances = FXCollections.observableArrayList(
                new Unit("Centimeters", 0.01),
                new Unit("Meters", 1.0),
                new Unit("Kilometers", 1000.0));
    
            //Create Unit objects for U.S. distances, and then
            //instantiate a ConversionPanel with these Units.
            usaDistances = FXCollections.observableArrayList(
                new Unit("Inches", 0.0254),
                new Unit("Feet", 0.3048),
                new Unit("Yards", 0.9144),
                new Unit("Miles", 1609.34));
        }
    
        @Override
        public void start(Stage stage) {
            stage.setScene(new Scene(new VBox(
                new ConversionPanel("Metric System", metricDistances, meters),
                new ConversionPanel("U.S. System", usaDistances, meters))));
            stage.show();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2010-12-24
      • 1970-01-01
      • 1970-01-01
      • 2011-11-25
      • 2011-09-25
      • 1970-01-01
      • 2010-12-31
      • 2011-03-22
      • 2020-12-28
      相关资源
      最近更新 更多