Reputation: 33
I am trying to implement Observer pattern with multiple JFrame instances. However, when notifyObservers()
is called, only the last instantiated JFrame instance is updated.
This is my code:
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;
}
The idea is, when a customer enters the store, the store will open up a new JFrame for the customer. When admin adds a store, all the JFrame CustomerFrame.java
will have their list item updated. However, in my case, only the CustomerFrame.java
that is last instantiated will get the update while the others remains the same.
The problem above can be reproduced by Opening 2 New Customer and try to Add Store at AdminFrame.java
What is the problem here?
Upvotes: 1
Views: 923
Reputation: 285403
You don't call any methods on thisFrame
from within the MallCustomer's update(...)
method. Rather than setting the model on storeList
(where the heck does that come from?), give CustomerFrame a public method, say called setStoreListModel(ListModel listModel)
that you call in update
, passing in the storeModel.
i.e.,
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);
}
}
and
@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);
}
Note: code not compiled nor tested
Edit
You've got several issues that I can see:
initComponents()
. This way you can use the same Mall instance inside of your action listener methods.For example:
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;
}
}
Upvotes: 2