2015-08-15 39 views
1

我試圖用多個JFrame實例實現觀察者模式。但是,當調用notifyObservers()時,只更新最後一個實例化的JFrame實例。具有多個JFrame的java.util.observer

這是我的代碼:

Mall.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; 
     } 
    } 

CustomerFrame.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。當管理員添加商店時,所有JFrame CustomerFrame.java都將更新其列表項目。但是,在我的情況下,只有最後實例化的CustomerFrame.java會得到更新,而其他實例保持不變。

上面的問題可以通過開2新客戶,嘗試AdminFrame.java

添加商店有什麼問題就在這裏被複制?

+0

見(http://stackoverflow.com/q/9554636/418556) –

回答

2

您不會在MallCustomer的update(...)方法中調用thisFrame上的任何方法。在storeList(來自哪裏?)設置模型,而不是在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不應該是公共或靜態的。使其成爲私人實例字段。
  • 再次(正如我一直建議的),給客戶窗口一個公共的setListModel類型的方法。
  • 應用程序應該只有一個主JFrame,所以CustomerFrame JFrame不應該是JFrame,而應該是非模態的JDialog,或者更好的是可以放在任何位置的JPanel--在它自己的JDialog中,主要的JFrame。
  • 將主JFrame傳遞給您的JDialogs,以便對話框可以在其超級構造函數中註冊父JFrame。
  • 將CustomerDialog實例傳入您的MallObserver實例,然後用它在MallObserver中設置一個字段。
  • 在更新方法中,創建或更新模型並調用MallObserver保存的客戶對話實例上的`setListModel。
  • 創建商城實例之前致電initComponents()。這樣,您可以在動作偵聽器方法中使用相同的Mall實例。
  • 挑剔:在創建和發佈MCVE時,擺脫混亂和分散注意力的NetBeans生成的代碼。相反,只需發佈​​自己創建的簡單代碼和簡單的GUI,類似於下面所做的更改。
  • 而你的MCVE應該都適合在一個文件中。該文件可以有幾個類,但是應該很容易剪切並粘貼到我們的IDE中,然後運行。

例如:?使用多個JFrames,好/壞實踐。

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; 
    } 


} 
+0

對不起,我複製了代碼錯誤,編輯它。 –

+1

@RyanLiew:你的不完整的問題已經改變,現在我的答案無效。將來,請提出完整的問題,包括髮布[mcve],以免我們浪費時間。請閱讀[mcve]鏈接,以便您可以創建一個,發佈它,並讓您的問題可以回覆。 –

+0

非常抱歉...我用編碼重新編輯了問題。 –