Search code examples
javaswingprogress-barobserver-patternpropertychangelistener

ProgressBar properychangeListener not updating in this case


I have a static boolean variable inProgress in a MainPanel containing a progressbar. A communicator class changes the value of this variable to true false.

The propertyListener is as follows

          @Override
          public void propertyChange(PropertyChangeEvent evt) {

            System.out.println("Property change check none");
            if(true ==MainPanel.inProgress){
                progressInformationPanel.getProgressBar().setIndeterminate(true);
                progressInformationPanel.getCurrentProcesLabel().setText("Processing...");
            }
            else if(false ==MainPanel.inProgress){
                System.out.println("Property change check none" + false);
                progressInformationPanel.getProgressBar().setIndeterminate(false);
              progressInformationPanel.getCurrentProcesLabel().setText("Finished....");
            }
        }
    });

The communicator class is an observer. That is listening to some other class. Now as soon as there is a progress communicator class updates the variable of the MainPanel but the propertyChangeListener does not act. I am not getting idea about why this is happening. Also please see my linked Question here

Here is the SSCCE

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

import javax.swing.JFrame;
import javax.swing.JProgressBar;


public class MainFrame extends JFrame{

    public static  boolean inProgress = true;
    private JProgressBar bar;
    public Communicator diplayFacade;
    public MainFrame() {
        this.setSize(500, 500);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        diplayFacade = new Communicator();
        bar = new JProgressBar();
        setLayout(new GridBagLayout());
        add(bar);
        addProgressListener();
    }



    public void addProgressListener(){
        bar.addPropertyChangeListener(new PropertyChangeListener() {

            @Override
            public void propertyChange(PropertyChangeEvent evt) {

                if(true == MainFrame.inProgress){
                    System.out.println("Property change check none" + true);
                    bar.setIndeterminate(true);
                }
                else if(false ==MainFrame.inProgress){
                    System.out.println("Property change check none" + false);
                    bar.setIndeterminate(false);

                }


            }
        });
    }

    public static void main(String[] args) {
        MainFrame frame = new MainFrame();
        frame.diplayFacade.methodCalled();


    }

}

And the Communicator class

import javax.swing.JOptionPane;

public class Communicator {



    public void methodCalled(){

        JOptionPane.showInputDialog("Hi");
        MainFrame.inProgress = true;
    }
}

Solution

  • The problem is, I don't think you understand what the PropertyChangeListener actually does. A PropertyChangeListener monitors for changes to the properties of the Object it is registered to.

    This notification doesn't happen by chance or automatically, you need to provide it, normally via PropertyChangeSupport which helps you manage the PropertyChangeListeners and triggering events...

    By adding a PropertyChangeListener to the JProgressBar, you are monitoring for changes to it, not your frame. Equally, by modifying the state of the JProgressBar from within the PropertyChangeListener, you risk ending up in an infinite loop, as the object tries to notify you of the changes that you have already made, over and over again....

    First of all, you really should avoid using static in this manner, it would be better to have an instance variable and a setter to change it's state. You would need to pass a reference of the frame to those people interested in changing the state, which raises another issue, you really don't want to expose your elements of your program unnecessarily, so it would be better to encompass this functionality in some kind of interface, for example...

    public interface Progressable {
        public void addPropertyChangeListener(PropertyChangeListener listener);
        public void removePropertyChangeListener(PropertyChangeListener listener);
        public void setInProgress(boolean inProgress);
        public boolean isInProgress();
    }
    

    Then you implement this interface. The Communicator would then take a reference to an instance of the this interface and call setInProgress as required, for example...

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.GridBagLayout;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import javax.swing.JFrame;
    import javax.swing.JProgressBar;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class MainFrame extends JFrame implements Progressable {
    
        private JProgressBar bar;
        public Communicator diplayFacade;
        private boolean inProgress;
    
        public MainFrame() {
            diplayFacade = new Communicator(this);
            bar = new JProgressBar();
            setLayout(new GridBagLayout());
            add(bar);
            addPropertyChangeListener("inProgress", new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if (isInProgress()) {
                        bar.setIndeterminate(true);
                    } else {
                        bar.setIndeterminate(false);
                    }
                }
            });
        }
    
        @Override
        public void setInProgress(boolean value) {
            if (inProgress != value) {
    
                inProgress = value;
                firePropertyChange("inProgress", !inProgress, inProgress);
    
            }
        }
    
        @Override
        public boolean isInProgress() {
            return inProgress;
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException ex) {
                    } catch (InstantiationException ex) {
                    } catch (IllegalAccessException ex) {
                    } catch (UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new MainFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
    }