title: Using PropertyChangeListener to refresh JFrame (without triggering infinite loop)
body: <p>Using java, I have a JFrame containing several JPanels which include various JComboBoxes, JTextFields, etc... which connect to entries in xml files, organized and viewed by date. Everything syncs up and is working but I've been having trouble getting the JFrame to update/refresh when changes are being made to the entries (i.e. adding/removing etc), although it does refresh when I change the date. I've got to the point where I have a PropertyChangeListener that gets triggered (prints to console) but when I try to use that Listener to refresh the frame I think I'm only revalidating the listener? </p>
  
  <p>Here's the code from the JFrame (I've used comments to indicate the failed segments):    </p>
  
  <pre><code>package interfaceComponents;
  
  import java.beans.*;
  import javax.swing.*;
  import org.jdesktop.swingx.JXDatePicker;
  import java.awt.*;
  import java.awt.event.*;
  import java.text.*;
  import java.io.IOException;
  import java.util.*;
  import java.time.*;
  import java.time.format.*;
  
  public class DailyView extends Frame {
      private static final long serialVersionUID = 7827570917642254745L;
      private final JXDatePicker calendar = new JXDatePicker();
      private JLabel focusPoint;
  
      public DailyView(LocalDate d) throws IOException {
          DefaultDateModel model = new DefaultDateModel(d);
  
          OperatorMenus menus = new OperatorMenus();
          setJMenuBar(menus);
  
          JPanel body = new JPanel();
          body.setLayout(new BoxLayout(body, BoxLayout.Y_AXIS));
  
          DayView anchorDay = new DayView(0);
          anchorDay.setModel(model);
          DayView nextDay = new DayView(1);
          nextDay.setModel(model);
  
          body.addPropertyChangeListener(new PropertyChangeListener() {
              public void propertyChange(PropertyChangeEvent evt) {
                  System.out.println("OperatorView.propertyChange");
                  //***This is where I'm trying to TRIGGER the REFRESH***
                  refreshFrame(); }
          });
          body.add(anchorDay);
          body.add(nextDay);
          add(new JScrollPane(body), BorderLayout.CENTER);
  
          JPanel footer = new JPanel();
          NavButtons navPanel = new NavButtons(model);
          focusPoint = new JLabel(DateTimeFormatter.ofPattern("E, dd MMM yyyy").format(model.getDate()));
          focusPoint.setForeground(Color.RED);
          footer.setLayout(new BorderLayout());
          footer.add(focusPoint, BorderLayout.CENTER);
          footer.add(navPanel, BorderLayout.EAST);
          footer.setBackground(Color.BLACK);
          add(footer, BorderLayout.SOUTH);
  
          pack(); }
  
      public DailyView() throws IOException { this(LocalDate.now()); }
  
      //interfaces
      public interface DateModel {
          public LocalDate getDate();
          public void addObserver(Observer o);
          public void removeObserver(Observer o); }
  
      public interface MutableDateModel extends DateModel {
          public void setDate(LocalDate date); }
  
      //methods
      public void refreshFrame() {     //***This is where I'm trying to TRIGGER the REFRESH***
          this.revalidate();
          this.repaint(); }
  
      //inner classes
      public class DefaultDateModel extends Observable implements MutableDateModel {
          private LocalDate date;
  
          public DefaultDateModel(LocalDate d) { date = d; }        
  
          @Override
          public void setDate(LocalDate d) {
              date = d;
              setChanged();
              notifyObservers(); }
  
          @Override
          public LocalDate getDate() {
              return date; }
  
          @Override
          public void removeObserver(Observer o) {
              deleteObserver(o); }
      }
  
      public class ShiftFocus extends AbstractAction implements Observer {
          private static final long serialVersionUID = 680383526965967229L;
          private MutableDateModel model; 
          private int shift;
  
          public ShiftFocus(MutableDateModel m, int i) {
              setModel(m);
              shift = i; }
  
          public void actionPerformed(ActionEvent event) {
              MutableDateModel model = getModel();
              if (model != null) { 
                  model.setDate(model.getDate().plusDays(shift));
                      calendar.setDate(Date.from(model.getDate().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
                  pack(); }
          }
  
          public void setModel(MutableDateModel value) {
              if (model != null) {
                  model.removeObserver(this); }
              this.model = value;
              if (model != null) {
                  model.addObserver(this); }
          }
  
          public MutableDateModel getModel() {
              return model; }
  
          @Override
          public void update(Observable o, Object arg) { 
              focusPoint.setText(DateTimeFormatter.ofPattern("E, dd MMM yyyy").format(model.getDate())); }
      }
  
      class NavButtons extends JPanel implements Observer {
          private static final long serialVersionUID = 914087518688373731L;
  
          //instance variables
          private JToolBar toolBar = new JToolBar("Navigation");
          private JButton weekBack = new JButton("&lt;&lt;");
          private JButton dayBack = new JButton("&lt;");
          private JButton returnToday = new JButton("Today");
          private JButton nextDay = new JButton("&gt;");
          private JButton nextWeek = new JButton("&gt;&gt;");
          private MutableDateModel model;
  
          //constructor
          public NavButtons(MutableDateModel model) {
              weekBack.addActionListener(new ShiftFocus(model, -7));
              dayBack.addActionListener(new ShiftFocus(model, -1));
              returnToday.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent event) {
                      MutableDateModel m = getModel();
                      m.setDate(LocalDate.now());
                      setModel(m); 
                      pack(); }
              });
              nextDay.addActionListener(new ShiftFocus(model, 1)); 
              nextWeek.addActionListener(new ShiftFocus(model, 7));
  
              toolBar.add(weekBack);
              toolBar.add(dayBack);
              toolBar.add(returnToday);
              toolBar.add(nextDay);
              toolBar.add(nextWeek);
  
              calendar.setEditable(true);
              calendar.setFormats("E, dd MMM yyyy");
              calendar.setDate(Date.from(model.getDate().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant()));
              calendar.addActionListener(new ActionListener() {
                  public void actionPerformed(ActionEvent event) {
                      MutableDateModel model = getModel();
                      if (model != null) { 
                          model.setDate(LocalDate.parse(new SimpleDateFormat("yyyy-MM-dd").format(calendar.getDate())));
                          pack(); }
                  }
              });
              toolBar.add(calendar);
              toolBar.add(new GalileoMode());
  
              add(toolBar); 
              setModel(model); }          
  
          public void setModel (MutableDateModel value) {
              if (model != null) {
                  model.removeObserver(this); }
              this.model = value;
              if (model != null) {
                  model.addObserver(this); }
          }
          public MutableDateModel getModel() {
              return model; }
  
          @Override
          public void update(Observable o, Object arg) {/* models data changes */}
      }
  }
  </code></pre>
  
  <p><strong><em>EDIT</em></strong></p>
  
  <p>After some feedback, have tried this so far:</p>
  
  <pre><code>        thisFrame = this;
          body.addPropertyChangeListener(new PropertyChangeListener() {
              public void propertyChange(PropertyChangeEvent evt) {
                  System.out.println("OperatorView.propertyChange");
  //              thisFrame.removeAll();
  //              thisFrame.dispose();
  //              thisFrame.remove(body);
  //              thisFrame.add(new JScrollPane(body),     BorderLayout.CENTER);
                  thisFrame.getContentPane().validate();
  //              thisFrame.revalidate();
                  thisFrame.getContentPane().repaint();
  //              thisFrame.refreshFrame(); 
                  }
          });
  </code></pre>
  
  <p>with <code>DailyView thisFrame;</code> declared as an instance variable at the top.</p>
  
  <p><strong><em>EDIT</em></strong></p>
  
  <p>In case there's anyone out there reading this, I am getting the propertyChangeListener to trigger certain events that would refresh the underlying panels, but that causes an infinite loop as the propertyChangeListener gets called again. (re)validate() and repaint() don't seem to have this issue but they're not refreshing the panels' content...anyone who could point me in the right direction/link to a similar question, etc would be greatly appreciated.</p>