Updating JLables In CardLayout When Showing Next Panel

516 views Asked by At

I have a CardLayout composed of numerous different JPanels which I show at will. This GUI is linked to a backend, and the purpose of the GUI is to allow the user to manipulate the data which is stored in the backend.

The problem is, when the user changes some data in the backend, my JLabels are not reflecting the change in that data. I understand that this is because the JLabels are initialized once, and when I update the variables that they are initialized to, I must call setText again in order for them to experience the change.

Example: Here is how my JLabel is initialized

CurrentBAName = new javax.swing.JLabel();
CurrentBAName.setText(GUI.currentBankAccount.getAccountName());

The problem is, when I change the value of GUI.currentBankAccount.getAccountName(), the text on my JLabel does not update. I have JLabels like this all over the place, and it would be a pain to have to go through and manually call setText on all of them each time a user makes any kind of change. Is there any way that I can have the JLabel automatically update itself when the value of that variable changes?

Perhaps I could implement some sort of Observer pattern? How would I do this with JLabels?
Or maybe I could use a focusGained Event so that every time I switch to a panel, the focusGained event fires so that I can update things. I am not sure how to do this though, and I am not sure how focus works with CardLayout. Maybe just a method that gets called every time I show a panel with layout.show(..). How would I implement this?
Is there a better way?

Update: Sample Code

GUI.java is my main GUI class and will consist of a JPanel to which all of my pages will be added and shown at will.

import javax.swing.*;

public class GUI extends javax.swing.JFrame
{
    public static String item;
    private javax.swing.JPanel MainPanel;

    public GUI()
    {
        // creates a JPanel called MainPanel which will hold the cards
        // in my CardLayout
        initComponents();
    }

    private void initComponents()
    {

        MainPanel = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        MainPanel.setBackground(new java.awt.Color(198, 118, 38));
        MainPanel.setMaximumSize(new java.awt.Dimension(1000, 1000));
        MainPanel.setName(""); // NOI18N
        MainPanel.setPreferredSize(new java.awt.Dimension(1024, 768));
        MainPanel.setLayout(new java.awt.CardLayout());

        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(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(MainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap())
        );
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(MainPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addContainerGap())
        );

        pack();
        setLocationRelativeTo(null);

    }

    // Grab the panel that was created in initComponents() so that I can add
    // other panels to it
    public JPanel getMainPanel()
    {
        return MainPanel;
    }

    public static void main(String args[])
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                GUI mainGUI = new GUI();

                // The JLabel in DisplayPanel.java will initially say root
                item = "root";

                JPanel cardHolder = mainGUI.getMainPanel();
                //This panel contains a button which will update the name of
                //the currentUserAccount
                MainMenuPanel mainMenu = new MainMenuPanel(cardHolder);
                cardHolder.add(mainMenu, "MainMenu");

                //This panel holds a JLabel that I want to have updated automatically
                //when the user presses the button on MainMenuPanel
                DisplayPanel display = new DisplayPanel(cardHolder);
                cardHolder.add(display, "Display");

                mainGUI.pack();
                mainGUI.setVisible(true);
            }
        });
    }
}

DisplayPanel.java will be a JPanel with the JLabel that I want to be updated on it

import java.awt.*;
import javax.swing.*;

public class DisplayPanel extends javax.swing.JPanel
{
    private JPanel MainPanel;

    public DisplayPanel(JPanel MainPanel)
    {

        this.MainPanel = MainPanel;
        initComponents(); // Creates my panel with the JLabels/buttons etc
    }

    @SuppressWarnings("unchecked")                 
    private void initComponents()
    {

        jLabel1 = new javax.swing.JLabel();
        GoToMainMenuButton = new javax.swing.JButton();

        jLabel1.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
        jLabel1.setText(GUI.item); // sets the JLabel to the GUI.item variable

        GoToMainMenuButton.setText("Go to MainMenuPanel");
        GoToMainMenuButton.addMouseListener(new java.awt.event.MouseAdapter()
        {
            public void mouseClicked(java.awt.event.MouseEvent evt)
            {
                GoToMainMenuButtonMouseClicked(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(269, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(GoToMainMenuButton)
                    .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 145, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(266, 266, 266))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(168, 168, 168)
                .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(83, 83, 83)
                .addComponent(GoToMainMenuButton)
                .addContainerGap(116, Short.MAX_VALUE))
        );
    }                       

    private void GoToMainMenuButtonMouseClicked(java.awt.event.MouseEvent evt)                                                
    {
        // go back to the MainPanel                                        
        CardLayout layout = (CardLayout) (MainPanel.getLayout());
        layout.show(MainPanel, "MainMenu");
    }                                               

    private javax.swing.JButton GoToMainMenuButton;
    private javax.swing.JLabel jLabel1;

}

MainMenuPanel.java will be a JPanel with a button on it which when pressed, will update the variable that the text of the JLabel in DisplayPanel is set to.

import java.awt.*;
import javax.swing.*;

public class MainMenuPanel extends javax.swing.JPanel
{

    private JPanel MainPanel;

    public MainMenuPanel(JPanel MainPanel)
    {

        this.MainPanel = MainPanel;
        initComponents(); // Creates my panel with the JLabels/buttons etc
    }

    @SuppressWarnings("unchecked")                        
    private void initComponents()
    {

        GoToDisplayPanelButton = new javax.swing.JButton();

        GoToDisplayPanelButton.setText("Press Me");
        GoToDisplayPanelButton.addMouseListener(new java.awt.event.MouseAdapter()
        {
            public void mouseClicked(java.awt.event.MouseEvent evt)
            {
                GoToDisplayPanelButtonMouseClicked(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(252, 252, 252)
                .addComponent(GoToDisplayPanelButton)
                .addContainerGap(260, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap(198, Short.MAX_VALUE)
                .addComponent(GoToDisplayPanelButton)
                .addGap(175, 175, 175))
        );
    }                      

    private void GoToDisplayPanelButtonMouseClicked(java.awt.event.MouseEvent evt)                                                    
    {                                                        
        // Changes the value of item. I want this change to be reflected on my
        // JLabel in DisplayPanel.java, but it is not because I do not explicitly
        // call setText on the JLabel here. I am wondering if there is a way to 
        // have my JLabel automatically update when the variable in its setText
        // is changed, without having to directly call setText. Or some other 
        // way to update it without calling setText every time I change something.
        GUI.item = "new value";

        // Switches to my DisplayPanel which should show the updated name in its JLabel
        CardLayout layout = (CardLayout)(MainPanel.getLayout());
        layout.show(MainPanel, "Display");
    }                                                   

    private javax.swing.JButton GoToDisplayPanelButton;                   
}
1

There are 1 answers

9
Hovercraft Full Of Eels On BEST ANSWER

You need to use a notification system by having the view (the GUI) be notified by the model (the "backend") when data has been changed. Then the view can request the updated information and use it to update the JLabel display. The details of this will depend on the specifics of your code, but I often give my model (or a wrapper around the model) a SwingPropertyChangeSupport field as well as addPropertyChangeListener(...) and the similar remove listener methods, and then in the model's methods where a property is changed (a bound property), fire the SwingPropertyChangeSupport's notification method. For more details on an implementation, you should consider showing some details of your code, preferably a minimal example program.

For example


Edit

Note that if all you want is notification of when show is called, you can always extend CardLayout and override its show(...) method. But if you do this, don't forget to call the super.show(...) method as well.


Edit
Note changes made to code indicated by // !!

import java.awt.CardLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

@SuppressWarnings("serial")
public class GUI extends javax.swing.JFrame {
   public static final String ITEM = "item";
   public String item; // !! this should not be static!
   private javax.swing.JPanel MainPanel;

   public GUI() {
      // creates a JPanel called MainPanel which will hold the cards
      // in my CardLayout
      initComponents();
   }

   // !!
   public void setItem(String item) {
      String oldValue = this.item;
      String newValue = item;
      this.item = item;
      firePropertyChange(ITEM, oldValue, newValue);
   }

   //!!
   public String getItem() {
      return item;
   }

   private void initComponents() {

      MainPanel = new javax.swing.JPanel();

      setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

      MainPanel.setBackground(new java.awt.Color(198, 118, 38));
      MainPanel.setMaximumSize(new java.awt.Dimension(1000, 1000));
      MainPanel.setName(""); // NOI18N
      MainPanel.setPreferredSize(new java.awt.Dimension(1024, 768));
      MainPanel.setLayout(new java.awt.CardLayout());

      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(javax.swing.GroupLayout.DEFAULT_SIZE,
                        Short.MAX_VALUE)
                  .addComponent(MainPanel,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addContainerGap()));
      layout.setVerticalGroup(layout.createParallelGroup(
            javax.swing.GroupLayout.Alignment.LEADING).addGroup(
            javax.swing.GroupLayout.Alignment.TRAILING,
            layout.createSequentialGroup()
                  .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE,
                        Short.MAX_VALUE)
                  .addComponent(MainPanel,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.DEFAULT_SIZE,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addContainerGap()));

      pack();
      setLocationRelativeTo(null);

   }

   // Grab the panel that was created in initComponents() so that I can add
   // other panels to it
   public JPanel getMainPanel() {
      return MainPanel;
   }

   public static void main(String args[]) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         @Override
         public void run() {
            final GUI mainGUI = new GUI();

            // The JLabel in DisplayPanel.java will initially say root
            // !! item = "root";
            mainGUI.setItem("root"); // !!

            JPanel cardHolder = mainGUI.getMainPanel();
            // This panel contains a button which will update the name of
            // the currentUserAccount
            final MainMenuPanel mainMenu = new MainMenuPanel(cardHolder,
                  mainGUI); // !!
            cardHolder.add(mainMenu, "MainMenu");

            // This panel holds a JLabel that I want to have updated
            // automatically
            // when the user presses the button on MainMenuPanel
            final DisplayPanel display = new DisplayPanel(cardHolder, mainGUI); // !!
            cardHolder.add(display, "Display");

            mainGUI.pack();
            mainGUI.setVisible(true);

            // !!
            mainGUI.addPropertyChangeListener(ITEM,
                  new PropertyChangeListener() {

                     @Override
                     public void propertyChange(PropertyChangeEvent pcEvt) {
                        String itemText = mainGUI.getItem();
                        display.setJLabel1Text(itemText);
                     }
                  });
         }
      });
   }
}

@SuppressWarnings("serial")
class DisplayPanel extends javax.swing.JPanel {
   private JPanel mainPanel;
   private GUI mainGui; // !!

   public DisplayPanel(JPanel mainPanel, GUI mainGui) { // !!

      this.mainPanel = mainPanel;
      this.mainGui = mainGui;// !!
      initComponents(); // Creates my panel with the JLabels/buttons etc
   }

   // !! added
   public void setJLabel1Text(String text) {
      jLabel1.setText(text);
   }

   private void initComponents() {

      jLabel1 = new javax.swing.JLabel();
      GoToMainMenuButton = new javax.swing.JButton();

      jLabel1.setFont(new java.awt.Font("Tahoma", 0, 18)); // NOI18N
      // !! jLabel1.setText(GUI.item); // sets the JLabel to the GUI.item
      // variable
      jLabel1.setText(mainGui.getItem()); // !!

      GoToMainMenuButton.setText("Go to MainMenuPanel");
      GoToMainMenuButton.addMouseListener(new java.awt.event.MouseAdapter() {
         public void mouseClicked(java.awt.event.MouseEvent evt) {
            GoToMainMenuButtonMouseClicked(evt);
         }
      });

      javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
      this.setLayout(layout);
      layout.setHorizontalGroup(layout
            .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(
                  javax.swing.GroupLayout.Alignment.TRAILING,
                  layout.createSequentialGroup()
                        .addContainerGap(269, Short.MAX_VALUE)
                        .addGroup(
                              layout.createParallelGroup(
                                    javax.swing.GroupLayout.Alignment.LEADING)
                                    .addComponent(GoToMainMenuButton)
                                    .addComponent(
                                          jLabel1,
                                          javax.swing.GroupLayout.PREFERRED_SIZE,
                                          145,
                                          javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addGap(266, 266, 266)));
      layout.setVerticalGroup(layout.createParallelGroup(
            javax.swing.GroupLayout.Alignment.LEADING).addGroup(
            layout.createSequentialGroup()
                  .addGap(168, 168, 168)
                  .addComponent(jLabel1,
                        javax.swing.GroupLayout.PREFERRED_SIZE, 63,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                  .addGap(83, 83, 83).addComponent(GoToMainMenuButton)
                  .addContainerGap(116, Short.MAX_VALUE)));
   }

   private void GoToMainMenuButtonMouseClicked(java.awt.event.MouseEvent evt) {
      // go back to the MainPanel
      CardLayout layout = (CardLayout) (mainPanel.getLayout());
      layout.show(mainPanel, "MainMenu");
   }

   private javax.swing.JButton GoToMainMenuButton;
   private javax.swing.JLabel jLabel1;

}

@SuppressWarnings("serial")
class MainMenuPanel extends javax.swing.JPanel {

   private JPanel MainPanel;
   private GUI mainGui; // !!

   public MainMenuPanel(JPanel MainPanel, GUI mainGui) { // !!

      this.MainPanel = MainPanel;
      this.mainGui = mainGui; // !!
      initComponents(); // Creates my panel with the JLabels/buttons etc
   }

   private void initComponents() {

      GoToDisplayPanelButton = new javax.swing.JButton();

      GoToDisplayPanelButton.setText("Press Me");
      GoToDisplayPanelButton
            .addMouseListener(new java.awt.event.MouseAdapter() {
               public void mouseClicked(java.awt.event.MouseEvent evt) {
                  GoToDisplayPanelButtonMouseClicked(evt);
               }
            });

      javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
      this.setLayout(layout);
      layout.setHorizontalGroup(layout.createParallelGroup(
            javax.swing.GroupLayout.Alignment.LEADING).addGroup(
            layout.createSequentialGroup().addGap(252, 252, 252)
                  .addComponent(GoToDisplayPanelButton)
                  .addContainerGap(260, Short.MAX_VALUE)));
      layout.setVerticalGroup(layout.createParallelGroup(
            javax.swing.GroupLayout.Alignment.LEADING).addGroup(
            javax.swing.GroupLayout.Alignment.TRAILING,
            layout.createSequentialGroup()
                  .addContainerGap(198, Short.MAX_VALUE)
                  .addComponent(GoToDisplayPanelButton).addGap(175, 175, 175)));
   }

   private void GoToDisplayPanelButtonMouseClicked(java.awt.event.MouseEvent evt) {
      // Changes the value of item. I want this change to be reflected on my
      // JLabel in DisplayPanel.java, but it is not because I do not explicitly
      // call setText on the JLabel here. I am wondering if there is a way to
      // have my JLabel automatically update when the variable in its setText
      // is changed, without having to directly call setText. Or some other
      // way to update it without calling setText every time I change something.
      // !! GUI.item = "new value";
      mainGui.setItem("new value"); // !!

      // Switches to my DisplayPanel which should show the updated name in its
      // JLabel
      CardLayout layout = (CardLayout) (MainPanel.getLayout());
      layout.show(MainPanel, "Display");
   }

   private javax.swing.JButton GoToDisplayPanelButton;
}