当前位置: 首页 > 知识库问答 >
问题:

在JComponent和模型对象之间传输数据

终安和
2023-03-14

我需要用UI组件更新模型类的数据,同时用数据对象中的更改更新UI组件。详细说明了大量数据依赖于其他数据。E.A.:A和B的总和。这个总和需要在UI上显示并存储在模型类中。

在实际情况下,我有大约58个可编辑的字段,混合了文本和数字。和一半的计算字段。

  1. 第一个步骤是将DocumentListeners添加到所有可编辑的UI字段中。当发生更改时,它们更新模型中的数据,并调用一个方法来更新UI中的所有字段。缺点--我粗略的看法--是我有50多个字段。如果不为每个UI组件编写特定的侦听器,我不知道如何编写它。Wich还可以在以后使用dificult来处理代码中的更改。
  2. 创建注册每个可编辑或计算UI组件的类数组。该类不仅将注册UI组件,还将使用反射注册要调用的方法,以便从模型对象中设置或检索信息。Document Lister仍将处理更改,但现在对于所有UI组件都可以是相同的,因为数组可以处理更改。很好的一点是,模型和UI之间的所有转换都可以在一个类中编码。缺点是沉思,人们似乎总是建议避免沉思。

什么是最好的,或好的,处理这种情况的方法?

我用来测试的代码:

public class Comunication {
    public static void main(String[] args) {      
        EventQueue.invokeLater(new Runnable() {
            public void run() {

                            //Main Window
                            JFrame frame = new JFrame();
                            frame.setTitle("SumTest");
                            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                            frame.setMinimumSize(new Dimension(500,200));
                            frame.setVisible(true);

                            //Main Panel
                            JPanel pane = new JPanel();
                            frame.setContentPane(pane);

                            //Component
                            JTextField valueA = new JTextField("VALUE A");
                            JTextField valueB = new JTextField("VALUE B");
                            JTextField valueSum = new JTextField("VALUE SUM");                           
                            pane.add(valueA);
                            pane.add(valueB);
                            pane.add(valueSum);
            }
        });
        }       
}

class Data {
    private int a;
    private int b;
    private int sum;

    public Data() {
        a = 1;
        b = 2;
        Calculate();
    }

    public void Calculate() {
        sum = a + b;
    }

    public int getA() { return a; }
    public int getB() { return b; }
    public int getSUM() { return sum; }
    public void setA(int i) { a = i; }
    public void setB(int i) { b = i; }
}

在尝试用户提供的信息时,我有了尝试其他东西的自由。一个解决方案是创建一个连接视图和模型的侦听器类。这个侦听器每次添加到一个字段(视图)时都应该改变一点,这是在不使用反射的情况下将一个字段与模型中的一个方法链接起来的唯一方法。

所以,更新的算法是:当视图发生变化时,更新模型。之后:一个gobal控制器用模型上的新信息更新所有视图。

我发现的问题,可能是由于缺乏经验:

import java.awt.*;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class Comunication {
    public static void main(String[] args) {      
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {

                            //Main Window
                            JFrame frame = new JFrame();
                            frame.setTitle("SumTest");
                            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                            frame.setMinimumSize(new Dimension(500,200));
                            frame.setVisible(true);

                            //Main Panel
                            JPanel pane = new JPanel();
                            frame.setContentPane(pane);

                            //Data Model
                            DataModel model = new DataModel();
                            GlobalUpdateController viewUpdateController = new GlobalUpdateController();

                            //Component
                            JTextField valueA = new JTextField("");
                            JTextField valueB = new JTextField("");
                            JTextField valueSum = new JTextField("");                           
                            valueA.setPreferredSize(new Dimension(30, 20));
                            valueB.setPreferredSize(new Dimension(30, 20));
                            valueSum.setPreferredSize(new Dimension(30, 20));                            
                            pane.add(valueA);
                            pane.add(valueB);
                            pane.add(valueSum);

                            //Listeners
                            valueA.getDocument().addDocumentListener(new StealthListener(valueA , viewUpdateController) {

                                    @Override
                                    public void updateView() { 
                                        this.view.setText( Integer.toString( model.getA() ) );
                                    }

                                    @Override
                                    public void updateModel() {
                                        model.setA( Integer.parseInt( this.view.getText() ) );
                                    }

                            });

                            valueB.getDocument().addDocumentListener(new StealthListener(valueB , viewUpdateController) {

                                    @Override
                                    public void updateView() { 
                                        this.view.setText( Integer.toString( model.getB() ) );
                                    }

                                    @Override
                                    public void updateModel() {
                                        model.setB( Integer.parseInt( this.view.getText() ) );
                                    }

                            });

                            valueSum.getDocument().addDocumentListener(new StealthListener(valueSum , viewUpdateController) {

                                    @Override
                                    public void updateView() { 
                                        this.view.setText( Integer.toString( model.getSUM() ) );
                                    }

                                    @Override
                                    public void updateModel() {
                                        //Do nothing
                                    }

                            });

                            //Initial Update
                            viewUpdateController.updateAllViews(null);


            }
        });
        }       
}

class DataModel {
    private int a;
    private int b;
    private int sum;

    public DataModel() {
        a = 3;
        b = 5;
        Calculate();
    }

    public void Calculate() {
        sum = a + b;
    }

    public int getA() { return a; }
    public int getB() { return b; }
    public int getSUM() { return sum; }

    public void setA(int i) { a = i; Calculate(); }
    public void setB(int i) { b = i; Calculate(); }
}


class StealthListener implements DocumentListener {

    JTextField view;
    GlobalUpdateController viewList;
    private boolean silent;

    public StealthListener(JTextField view, GlobalUpdateController viewList) {        
        this.view = view;
        this.viewList = viewList;
        this.silent = false;
        this.viewList.add(this);        
    }

    public void setSilent(boolean val) {
        this.silent = val;
    }

    public void updateView() { 
        // Unique to each view, to be Overriden
    }

    public void updateModel() {
        // Unique to each view, to be Overriden
    }

    public void update() {
        //The silent flag is meant to avoid ListenerLoop when changing the document.
        //When the silent is true is meant to listen to internal changes.
        if(this.silent == false) {
            updateModel();
            this.viewList.updateAllViews(this);
        }
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        update();
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
        update();
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        update();
    }
}


class GlobalUpdateController {
    private ArrayList<StealthListener> viewList;

    public GlobalUpdateController() {
        this.viewList = new ArrayList<StealthListener>();
    }

    public void add(StealthListener control) {
        this.viewList.add(control);
    }

    public void updateAllViews(StealthListener caller) {
        for( StealthListener view : viewList) {
            if( caller==null || view != caller ) {

                view.setSilent(true);
                view.updateView();
                view.setSilent(false);
            }
        }
    }
}

共有1个答案

习海
2023-03-14

>

  • 在此相关示例中,任意数量的可编辑文本字段中的每一个都添加PropertyChangeListenerFocusListener的实例。每个侦听器调用一个公共的update()方法来重新计算派生的sum。在下面的变体中,字段共享UpdateListener的单个实例,该实例同时是FocusListenerPropertyChangeListener。只有当需要在每次击键时updateListener更新()时,才允许updateListener也实现documentListener

    实际上,模型列表 中的数据,控制器是公共的Update()方法,用于强制输入字段之间的关系。这种方法的可伸缩性取决于update()的复杂性。该示例使用JFormattedTextField方便地设置相关字段的格式。

    每当我考虑使用反射时,我也会考虑将策略模式与enum结合起来作为替代方案。例子见这里和这里。

    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.event.FocusAdapter;
    import java.awt.event.FocusEvent;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.text.NumberFormat;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.JFormattedTextField;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    /**
     * @see https://stackoverflow.com/a/31764798/230513
     * @see https://stackoverflow.com/q/8703464/230513
     * @see https://stackoverflow.com/questions/6803976
     */
    public class Adder extends JPanel {
    
        private static final int MAX = 3;
        private final List<JFormattedTextField> fields = new ArrayList<>();
        private final NumberFormat format = NumberFormat.getNumberInstance();
        private final JFormattedTextField sum = new JFormattedTextField(format);
        private final UpdateListener listener = new UpdateListener();
    
        private class UpdateListener extends FocusAdapter implements PropertyChangeListener {
    
            @Override
            public void propertyChange(PropertyChangeEvent e) {
                update();
            }
    
            @Override
            public void focusLost(FocusEvent e) {
                EventQueue.invokeLater(new Runnable() {
    
                    @Override
                    public void run() {
                        update();
                    }
                });
            }
        }
    
        public Adder() {
            this.setLayout(new GridLayout(0, 1));
            for (int i = 0; i < MAX; i++) {
                JFormattedTextField tf = init();
                fields.add(tf);
                this.add(tf);
            }
            sum.setHorizontalAlignment(JFormattedTextField.RIGHT);
            sum.setEditable(false);
            sum.setFocusable(false);
            this.add(sum);
        }
    
        private JFormattedTextField init() {
            JFormattedTextField jtf = new JFormattedTextField(format);
            jtf.setValue(0);
            jtf.setHorizontalAlignment(JFormattedTextField.RIGHT);
            jtf.addFocusListener(listener);
            jtf.addPropertyChangeListener("value", listener);
            return jtf;
        }
    
        private void update() {
            long total = 0;
            for (JFormattedTextField tf : fields) {
                Number v = (Number) tf.getValue();
                total += v.longValue();
            }
            sum.setValue(total);
        }
    
        private void display() {
            JFrame f = new JFrame("Adder");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(this);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    new Adder().display();
                }
            });
        }
    }
    

  •  类似资料:
    • 问题内容: 您能否简单地解释一下Transfer对象和Domain对象之间的区别?如果您可以举一个Java示例,那就太好了。 问题答案: DTO没有任何逻辑。他们只有字段(州)。在将数据从一个层/子系统传输到另一层/子系统时使用它们 域对象可以具有逻辑(取决于您使用的是域驱动设计还是贫乏的数据模型),并且它们通常与数据库结构相关。 如果使用贫乏的数据模型(即您的域对象没有任何逻辑),则DTO和域对

    • 问题内容: 在Java中,序列化对象非常容易。在C 中 ,只要对象像C结构一样就安全(?)(无多态性)。在C 中, 如果编译器能够生成默认的(琐碎的)复制构造函数,那么为什么它不能生成用于自动序列化的代码? 在Java中,只能从ctor访问静态函数和数据成员。 在C ++中,我可以愉快地使用ctor中的非静态成员和函数。 在Java中,我可以在类中内联初始化数据成员。在C ++中,这是一个编译错误

    • 主要内容:实现,步骤 1,StudentVO.java,步骤 2,StudentBO.java,步骤 3,TransferObjectPatternDemo.java,步骤 4传输对象模式(Transfer Object Pattern)用于从客户端向服务器一次性传递带有多个属性的数据。传输对象也被称为数值对象。传输对象是一个具有 getter/setter 方法的简单的 POJO 类,它是可序列化的,所以它可以通过网络传输。它没有任何的行为。服务器端的业务类通常从数据库读取数据,然后填充 PO

    • 传输对象模式(Transfer Object Pattern)用于从客户端向服务器一次性传递带有多个属性的数据。传输对象也被称为数值对象。传输对象是一个具有 getter/setter 方法的简单的 POJO 类,它是可序列化的,所以它可以通过网络传输。它没有任何的行为。服务器端的业务类通常从数据库读取数据,然后填充 POJO,并把它发送到客户端或按值传递它。对于客户端,传输对象是只读的。客户端可

    • 传输对象模式(Transfer Object Pattern)用于从客户端向服务器一次性传递带有多个属性的数据。传输对象也被称为数值对象。传输对象是一个具有 getter/setter 方法的简单的 POJO 类,它是可序列化的,所以它可以通过网络传输。它没有任何的行为。服务器端的业务类通常从数据库读取数据,然后填充 POJO,并把它发送到客户端或按值传递它。对于客户端,传输对象是只读的。客户端可

    • 问题内容: 关于如何在Hibernate实体和Web服务要返回的数据传输对象之间进行转换,我也有类似的问题和疑虑,如以下问题所述: 此处提到的因素之一是,如果域模型发生更改,则在Web服务的情况下,一组DTO将保护使用者。 即使看起来它将为我的项目添加大量代码,这种推理也似乎是合理的。 是否可以使用一种好的设计模式将一个Hibernate实体(实现一个接口)转换为一个实现相同接口的DTO? 因此,