有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

SwingJava。util。多帧观测器

我试图用多个JFrame实例实现Observer模式。但是,当调用notifyObservers()时,只更新最后一个实例化的JFrame实例

这是我的代码:

购物中心。java

    import java.util.ArrayList;
    import java.util.Observable;

    public class Mall extends Observable{
        private ArrayList<String> stores;

        public Mall(){
           stores = new ArrayList<String>();
        }

        public void addNewStore(String store){
           stores.add(store);
           System.out.println(store);
           setChanged();
           notifyObservers(store);
        }

        public ArrayList<String> getStores(){
            return stores;
        }
    }

定制框架。java

    public class CustomerFrame extends javax.swing.JFrame {

        public CustomerFrame() {
           initComponents();
        }

        public CustomerFrame(Mall theMall) {
            initComponents();
            MallObserver mallObs = new MallObserver();
            theMall.addObserver(mallObs);

        }

        private void initComponents() {

            jScrollPane1 = new javax.swing.JScrollPane();
            jList1 = new javax.swing.JList();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            jList1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
            jScrollPane1.setViewportView(jList1);

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 249, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(141, Short.MAX_VALUE))
            );
            layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 165, javax.swing.GroupLayout.PREFERRED_SIZE)
            .addContainerGap(124, Short.MAX_VALUE))
            );

            pack();
        }                   

        public static javax.swing.JList jList1;
        private javax.swing.JScrollPane jScrollPane1;                  
    }

MallObserver。java

    import java.util.Observable;
    import java.util.Observer;
    import javax.swing.DefaultListModel;

    public class MallObserver implements Observer{

        private Mall mallUpdate;

        @Override
        public void update(Observable o, Object arg) {
           mallUpdate = (Mall) o;
           DefaultListModel listModel = new DefaultListModel();
           for(int i = 0; i < mallUpdate.getStores().size(); i++)
               listModel.addElement(mallUpdate.getStores().get(i));
           CustomerFrame.jList1.setModel(listModel);
        }

    }

AdminFrame。java

        public class AdminFrame extends javax.swing.JFrame {

        Mall theMall;

        public AdminFrame() {
            initComponents();
            theMall = new Mall();
        }
    @SuppressWarnings("unchecked")                         
        private void initComponents() {

            jTextField1 = new javax.swing.JTextField();
            jLabel1 = new javax.swing.JLabel();
            jButton1 = new javax.swing.JButton();
            jButton2 = new javax.swing.JButton();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            jTextField1.setText("jTextField1");

            jLabel1.setText("jLabel1");

            jButton1.setText("Add Store");
            jButton1.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jButton1ActionPerformed(evt);
                }
            });

            jButton2.setText("New Customer");
            jButton2.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jButton2ActionPerformed(evt);
                }
            });

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addContainerGap(143, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jButton2)
                .addComponent(jButton1)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(jLabel1)
                    .addGap(26, 26, 26)
                    .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
            .addGap(138, 138, 138))
            );
            layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(129, 129, 129)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(jLabel1))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(jButton1)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
            .addComponent(jButton2)
            .addContainerGap(88, Short.MAX_VALUE))
            );

            pack();
        }

     private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {                                         
            CustomerFrame newCust = new CustomerFrame();
            newCust.setVisible(true);
        } 

     private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
           theMall.addNewStore(jTextField1.getText());
        }

     public static void main(String args[]) {

            try {
                for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
                        java.util.logging.Logger.getLogger(AdminFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
                    }

     java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new AdminFrame().setVisible(true);
                }
            });
        }


        private javax.swing.JButton jButton1;
        private javax.swing.JButton jButton2;
        private javax.swing.JLabel jLabel1;
        private javax.swing.JTextField jTextField1;

    }                

这个想法是,当顾客进入商店时,商店会为顾客打开一个新的JFrame。当admin添加存储时,所有JFrameCustomerFrame.java都将更新其列表项。然而,在我的例子中,只有最后实例化的CustomerFrame.java会得到更新,而其他的保持不变

通过打开2个新客户并尝试在AdminFrame.java添加存储,可以重现上述问题

这里有什么问题


共 (1) 个答案

  1. # 1 楼答案

    您不能从MallCustomer的update(...)方法中调用thisFrame上的任何方法。而不是将模型设置为storeList(这到底是从哪里来的?),为CustomerFrame提供一个公共方法,比如调用setStoreListModel(ListModel listModel),在update中调用,并传入storeModel

    public class CustomerFrame extends javax.swing.JFrame {
        privarte Mall theMall;
        private JList storesList = new JList();
    
        public CustomerFrame(Customer customer, Mall theMall){
            MallCustomer mallObserver = new MallCustomer(this);
            theMall.addObserver(mallObserver);
        }
    
        public setStoresListModel(ListModel listModel) {
            storesList.setModel(listModel);
        }
    }
    

    @Override
    public void update(Observable o, Object arg) {
        mallUpdate = (Mall) o;
        DefaultListModel storeModel = new DefaultListModel();
    
        //Stores update
        for(int i = 0; i < mallUpdate.getStores().size();i++) {
            storeModel.addElement(mallUpdate.getStores().get(i));
        }
        // storesList.setModel(storeModel);//a JList variable
        thisFrame.setStoresListModel(storeModel);
    }    
    

    注意:代码未编译或测试


    编辑

    我可以看到您有几个问题:

    • 您的JList不应是公共的或静态的。将其设置为私有实例字段
    • 同样(正如我一直建议的那样),为Customer窗口提供一个公共的setListModel类型的方法
    • 一个应用程序应该只有一个主JFrame,因此CustomerFrame JFrame不应该是一个JFrame,而应该是一个非模态的JDialog,或者最好是一个可以放在主JFrame中自己的JDialog中任何位置的JPanel
    • 将主JFrame传递到JDialogs中,这样对话框就可以在其super的构造函数中注册父JFrame
    • 将CustomerDialog实例传递到MallObserver实例中,然后使用它在MallObserver内部设置一个字段
    • 在update方法中,创建或更新模型,并在MallObserver持有的customer对话框实例上调用`setListModel
    • 在调用initComponents()之前创建Mall实例。这样,您就可以在action listener方法中使用相同的Mall实例
    • 吹毛求疵:在创建和发布MCVE时,要去掉NetBeans生成的混乱和分散注意力的代码。相反,只发布您自己创建的简单代码和简单GUI,类似于我在下面所做的更改
    • 你的MCVE都应该放在一个文件中。该文件可以有几个类,但是我们可以很容易地剪切并粘贴到IDE中,然后运行

    例如:

    import java.util.ArrayList;
    import java.util.Observable;
    import java.util.Observer;
    import java.awt.event.*;
    import javax.swing.*;
    
    @SuppressWarnings("serial")
    public class AdminFrame extends javax.swing.JFrame {
    
        private Mall theMall = new Mall(); //!!
    
        public AdminFrame() {
            initComponents();
            //!! theMall = new Mall();
        }
    
        private void initComponents() {
    
            jTextField1 = new javax.swing.JTextField();
            jLabel1 = new javax.swing.JLabel();
            addStoreBtn = new javax.swing.JButton();
            newCustBtn = new javax.swing.JButton();
    
            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    
            jTextField1.setText("jTextField1");
    
            jLabel1.setText("jLabel1");
    
            addStoreBtn.setText("Add Store");
            addStoreBtn.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    theMall.addNewStore(jTextField1.getText());
                }
            });
            addStoreBtn.setMnemonic(KeyEvent.VK_S);
    
            newCustBtn.setText("New Customer");
            newCustBtn.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    // !! CustomerFrame newCust = new CustomerFrame();
                    CustomerDialog newCust = new CustomerDialog(AdminFrame.this, theMall);
                    newCust.pack();
                    newCust.setLocationByPlatform(true);
                    newCust.setVisible(true);
                }
            });
            newCustBtn.setMnemonic(KeyEvent.VK_C);
    
            JPanel mainPanel = new JPanel();
            mainPanel.add(jLabel1);
            mainPanel.add(jTextField1);
            mainPanel.add(addStoreBtn);
            mainPanel.add(newCustBtn);
    
            add(mainPanel);
    
            pack();
            setLocationRelativeTo(null);
        }
    
        public static void main(String args[]) {
    
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new AdminFrame().setVisible(true);
                }
            });
        }
    
        private javax.swing.JButton addStoreBtn;
        private javax.swing.JButton newCustBtn;
        private javax.swing.JLabel jLabel1;
        private javax.swing.JTextField jTextField1;
    
    }
    
    class MallObserver implements Observer {
    
        private Mall mallUpdate;
        private CustomerDialog customerDialog; // !!
    
        // !!
        public MallObserver(CustomerDialog customerFrame) {
            this.customerDialog = customerFrame; // !!
        }
    
        @Override
        public void update(Observable o, Object arg) {
            mallUpdate = (Mall) o;
            DefaultListModel<String> listModel = new DefaultListModel<>();
            for (int i = 0; i < mallUpdate.getStores().size(); i++) {
                listModel.addElement(mallUpdate.getStores().get(i));
            }
    
            customerDialog.setListModel(listModel);
        }
    
    }
    
    @SuppressWarnings("serial")
    class CustomerDialog extends JDialog {  //!!
    
        // !!!!!!! public CustomerFrame() {
        // initComponents();
        // }
    
        public void setListModel(ListModel<String> listModel) {
            jList1.setModel(listModel);
        }
    
        public CustomerDialog(AdminFrame adminFrame, Mall theMall) {
            super(adminFrame, "Customer Dialog", ModalityType.MODELESS);
            initComponents();
            // !! MallObserver mallObs = new MallObserver();
            MallObserver mallObs = new MallObserver(this); // !!
            theMall.addObserver(mallObs);
        }
    
        private void initComponents() {
    
            jScrollPane1 = new javax.swing.JScrollPane();
            jList1 = new JList<>();
            jList1.setPrototypeCellValue("                               ");
            jList1.setVisibleRowCount(15);
    
            setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
    
            jList1.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
            jScrollPane1.setViewportView(jList1);
    
            add(jScrollPane1);
    
            pack();
        }
    
        // public static javax.swing.JList jList1;
        private JList<String> jList1;
        private JScrollPane jScrollPane1;
    }
    
    class Mall extends Observable {
        private ArrayList<String> stores;
    
        public Mall() {
            stores = new ArrayList<String>();
        }
    
        public void addNewStore(String store) {
            stores.add(store);
            setChanged();
            notifyObservers(store);
        }
    
        public ArrayList<String> getStores() {
            return stores;
        }
    
    
    }