【问题标题】:When ArrayList is updated in Model JList should be updated in View当 ArrayList 在 Model 中更新时 JList 应该在 View 中更新
【发布时间】:2012-10-19 22:54:01
【问题描述】:

我已经玩了一段时间了,但没有成功。我看过 ListModel,但很难将它实施到我当前的项目中。

我有一个生产者类线程将元素添加到模型中的 ArrayList。这工作正常,并且 ArrayList 正在运行时更新。我的问题是,然后我希望将添加到 ArrayList 的新对象添加到 View 类中的 JList 中。我看不到如何将 ListModel 或 DefaultListModel 合并到我当前的设置中。非常感谢您的帮助。

public class Person
{
    private String name;
    private int    age;

    public Person(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public int getAge()
    {
        return age;
    }

    public String toString()
    {
        return this.name;
    }
}

public class Producer extends Thread
{
    private Model model;

    public Producer(Model model)
    {
        this.model = model;
    }

    public void run()
    {
        Person fred     = new Person("Fred Flintstone", 37);
        Person wilma    = new Person("Wilma Flintstone", 18);
        Person pebbles  = new Person("Pebbles Flintstone", 15);
        Person dino     = new Person("Dino Flintstone", 45);
        Person barney   = new Person("Barney Rubble", 76);
        Person betty    = new Person("Betty Rubble", 76);
        Person bamm     = new Person("Bamm-Bamm Rubble", 76);

        try
        {
            model.addPerson(fred);
            Thread.sleep(1500);
            model.addPerson(wilma);
            Thread.sleep(1500);
            model.addPerson(pebbles);
            Thread.sleep(1500);
            model.addPerson(dino);
            Thread.sleep(1500);
            model.addPerson(barney);
            Thread.sleep(1500);
            model.addPerson(betty);
            Thread.sleep(1500);
            model.addPerson(bamm);
        }
        catch(Exception e)
        {
            System.out.println("Error adding Person object to Model.people
                                ArrayList" + e);
        }
    }
}

public class Model 
{
    private List <Person> people;

    public Model()
    {
        people = new ArrayList<Person>();
    }

    public List<Person> getPeople()
    {
        return people;
    }

    public void addPerson(Person aPerson)
    {
        people.add(aPerson);
        System.out.println("Person object added to people list:" + aPerson);
    }

    public void removePerson(Person aPerson)
    {
        people.remove(aPerson);
    }
}

public class View extends JFrame
{
    private JPanel              topPanel, botPanel;
    private JList               peopleList;
    private JScrollPane         scrollPane;
    private Model               model;

    public View(Model model)
    {
        this.model = model;
        setSize(200, 220);
        setTitle("View");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        topPanel = new JPanel();
        botPanel = new JPanel();
        peopleList = new JList(model.getPeople().toArray());
        scrollPane = new JScrollPane(peopleList);
        topPanel.setLayout(new GridLayout(1, 1));
        topPanel.add(scrollPane);
        topPanel.setBorder(BorderFactory.createTitledBorder
       (BorderFactory.createEtchedBorder(), "People list"));

        Container cp = getContentPane();
        cp.add(topPanel, BorderLayout.NORTH);
        cp.add(botPanel, BorderLayout.SOUTH);
    }
}

public class Main 
{
    public static void main(String[] args)
    {
        Model model = new Model();
        View theView = new View(model);
        theView.setVisible(true);
        Producer producer = new Producer(model);
        producer.start();
    }
}

【问题讨论】:

    标签: java swing model-view-controller arraylist jlist


    【解决方案1】:

    在此处使用适当的 MVC 模式:视图侦听模型中的更改并根据来自模型的通知进行更新:

    1. 在您的模型上添加PropertyChangeSupport,并在修改模型时触发PropertyChangeEvent
    2. 将视图添加为模型的PropertyChangeListener
    3. 相应地对通知做出反应(如果将Person 添加到您的模型中,当您收到“添加新人”的事件时,将其添加到您的peopleListListModel,对于“人删除”等...)

    http://docs.oracle.com/javase/7/docs/api/java/beans/PropertyChangeSupport.html

    注意:由于您的模型将被除 EDT(事件调度线程)之外的另一个线程修改,因此请确保您在 EDT 上修改您的 UI(查看 SwingUtilities.isEventDispatchingThread()SwingUtilities.invokeLater()

    更新:

    这是一个 sn-p,它说明了我在上面试图解释的内容(对不起,如果它有点冗长,但我试图尽可能接近你的原始代码):

    import java.awt.BorderLayout;
    import java.awt.Container;
    import java.awt.GridLayout;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    import javax.swing.BorderFactory;
    import javax.swing.DefaultListModel;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.SwingUtilities;
    
    public class Main {
    
        public class Person {
    
            private String name;
            private int age;
    
            public Person(String name, int age) {
                this.name = name;
                this.age = age;
            }
    
            public String getName() {
                return name;
            }
    
            public int getAge() {
                return age;
            }
    
            @Override
            public String toString() {
                return this.name;
            }
        }
    
        public class Producer extends Thread {
            private Model model;
    
            public Producer(Model model) {
                this.model = model;
            }
    
            @Override
            public void run() {
                Random random = new Random();
                Person fred = new Person("Fred Flintstone", 37);
                Person wilma = new Person("Wilma Flintstone", 18);
                Person pebbles = new Person("Pebbles Flintstone", 15);
                Person dino = new Person("Dino Flintstone", 45);
                Person barney = new Person("Barney Rubble", 76);
                Person betty = new Person("Betty Rubble", 76);
                Person bamm = new Person("Bamm-Bamm Rubble", 76);
                while (true) {
                    try {
                        model.addPerson(fred);
                        Thread.sleep(1500);
                        model.addPerson(wilma);
                        Thread.sleep(1500);
                        model.addPerson(pebbles);
                        Thread.sleep(1500);
                        model.addPerson(dino);
                        Thread.sleep(1500);
                        model.addPerson(barney);
                        Thread.sleep(1500);
                        model.addPerson(betty);
                        Thread.sleep(1500);
                        model.addPerson(bamm);
                        while (model.getPeople().size() > 0) {
                            Person p = model.getPeople().get(random.nextInt(model.getPeople().size()));
                            model.removePerson(p);
                            Thread.sleep(1000);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        public class Model {
            private static final String PEOPLE = "people";
    
            private List<Person> people;
    
            private PropertyChangeSupport propertyChangeSupport;
    
            public Model() {
                people = new ArrayList<Person>();
                propertyChangeSupport = new PropertyChangeSupport(this);
            }
    
            public PropertyChangeSupport getPropertyChangeSupport() {
                return propertyChangeSupport;
            }
    
            public List<Person> getPeople() {
                return people;
            }
    
            public void addPerson(Person aPerson) {
                people.add(aPerson);
                System.out.println("Person object added to people list:" + aPerson);
                getPropertyChangeSupport().firePropertyChange(PEOPLE, null, aPerson);
            }
    
            public void removePerson(Person aPerson) {
                people.remove(aPerson);
                getPropertyChangeSupport().firePropertyChange(PEOPLE, aPerson, null);
            }
        }
    
        public class View extends JFrame implements PropertyChangeListener {
            private JPanel topPanel, botPanel;
            private JList peopleList;
            private JScrollPane scrollPane;
            private Model model;
            private DefaultListModel peopleListModel;
    
            public View(Model model) {
                this.model = model;
                setSize(200, 220);
                setTitle("View");
                setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                topPanel = new JPanel();
                botPanel = new JPanel();
                peopleListModel = new DefaultListModel();
                for (Person p : model.getPeople()) {
                    peopleListModel.addElement(p);
                }
                peopleList = new JList(peopleListModel);
                model.getPropertyChangeSupport().addPropertyChangeListener(Model.PEOPLE, this);
                scrollPane = new JScrollPane(peopleList);
                topPanel.setLayout(new GridLayout(1, 1));
                topPanel.add(scrollPane);
                topPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), "People list"));
    
                Container cp = getContentPane();
                cp.add(topPanel, BorderLayout.NORTH);
                cp.add(botPanel, BorderLayout.SOUTH);
            }
    
            @Override
            public void propertyChange(final PropertyChangeEvent evt) {
                if (!SwingUtilities.isEventDispatchThread()) {
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            propertyChange(evt);
                        }
                    });
                    return;
                }
                if (evt.getSource() == model) {
                    if (Model.PEOPLE.equals(evt.getPropertyName())) {
                        if (evt.getOldValue() != null && evt.getNewValue() == null) {
                            peopleListModel.removeElement(evt.getOldValue());
                        } else if (evt.getOldValue() == null && evt.getNewValue() != null) {
                            peopleListModel.addElement(evt.getNewValue());
                        }
                    }
                }
            }
        }
    
        public static void main(String[] args) {
            new Main().init();
        }
    
        private void init() {
            final Model model = new Model();
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    View theView = new View(model);
                    theView.setVisible(true);
                }
            });
            Producer producer = new Producer(model);
            producer.start();
        }
    }
    

    【讨论】:

    • 1+。还将使用 PropertyChangeSupport 的 Swing 变体,即使用 SwingPropertyChangeSupport 对象来帮助确保在 Swing 事件线程上通知 PropertyChangeListener。
    • @HovercraftFullOfEels 是的,我读过它,在某些情况下它可能很方便,但我个人认为模型不应该依赖/依赖 UI 技术。如果您使用 SwingPropertyChangeSupport,您将间接使用可以启动 AWT-EventQueue 的 SwingUtilities.invokeLater。现在,如果您在 SWT 中运行该代码,您将收到一个错误,因为 SWT 和 AWT 不能同时存在于同一个 JVM 中。但万一用户只关注 Swing,这是个好主意。
    • @Paul 是新手 - 请不要混淆他 :-) 主要问题是要了解对数据结构(模型中的人员列表)的修改不会被 ListModel 自动看到,它是缠绕在它周围。所以主要的解决方案是实现一个自定义的 ListModel 来触发适当的 ListDataEvents。一个小问题(他还没有偶然发现)是 listDataEvent 必须在包含的 Person 的属性(如 f.i. name)发生更改时触发。这就是 PropertyChangeEvents 发挥作用的地方。
    • @kleopatra 我不确定 Paul 是否完全是新手,因为他显然发现了 ListModel/DefaultListModel。他还明确地试图建立一个 MVC 模式。属性更改支持也可以用于数据结构更改。剩下要做的就是根据通知操作 DefaultListModel。我用完整的示例代码更新了我的帖子(主要基于 OP 代码)。
    • 这在有效 propertyChangeEvent 的边界上很难 ;-) 如果您将 getPeople() 方法重命名为其他名称,它可能是一个仅通知属性。这是可能的,但不会过度扩展:f.i.如果您开始收听 Person 上的 propertyChanges 会发生什么(假设它将演变成一个 bean)? PropertyChanges 根本不是为了通知结构修改 - 从长远来看,阻抗不匹配会让你发疯。干净的出路是一个可观察的数据结构(尽管它也有它的问题)
    猜你喜欢
    • 2011-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    • 2021-02-20
    • 2021-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多