【问题标题】:ProgressBar properychangeListener not updating in this caseProgressBar propertyychangeListener 在这种情况下不更新
【发布时间】:2014-10-08 05:44:32
【问题描述】:

我在包含进度条的MainPanel 中有一个静态布尔变量inProgress。通信器类将此变量的值更改为真假。

propertyListener如下

          @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....");
            }
        }
    });

通信器类是观察者。那是在听别的课。现在,一旦有进度通信器类更新 MainPanel 的变量,但 propertyChangeListener 不动作。我不知道为什么会这样。也请在此处查看我的链接Question

这里是 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();


    }

}

还有 Communicator 类

import javax.swing.JOptionPane;

public class Communicator {



    public void methodCalled(){

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

【问题讨论】:

  • inProgress 值如何变化?属性更改事件是如何产生的?简单地改变一个变量的状态不会神奇地触发一个属性改变事件......
  • @MadProgrammer Communicator 类将 MainPanel.inProgress 更新为 true 或 false。当 Communicator 类收到来自它正在观察的类的通知并根据此通知更新 inProgress 变量时
  • 那么有人怎么知道inProgress 发生了变化?谁触发了此属性更改事件?考虑提供一个runnable example 来证明您的问题。这将减少混乱并获得更好的响应
  • @MadProgrammer 添加了 sscce :)

标签: java swing progress-bar observer-pattern propertychangelistener


【解决方案1】:

问题是,我认为您不了解 PropertyChangeListener 的实际作用。 PropertyChangeListener 监视其注册到的 Object 的属性的更改。

此通知不是偶然或自动发生的,您需要提供它,通常通过PropertyChangeSupport 提供,它可以帮助您管理PropertyChangeListeners 和触发事件...

通过将PropertyChangeListener 添加到JProgressBar,您正在监控它的变化,而不是您的框架。同样,通过在PropertyChangeListener 中修改JProgressBar 的状态,您可能会陷入无限循环,因为该对象会一遍又一遍地通知您您已经做出的更改... .

首先,你真的应该避免以这种方式使用static,最好有一个实例变量和一个setter来改变它的状态。您需要将框架的引用传递给那些对更改状态感兴趣的人,这引发了另一个问题,您真的不想不必要地公开您的程序元素,因此最好在一些中包含此功能一种界面,例如...

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

然后你实现这个接口。然后Communicator 将引用this 接口的实例并根据需要调用setInProgress,例如...

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

}

【讨论】:

    【解决方案2】:

    这是可行的解决方案。感谢 MadProgrammer 的投入。必须添加 PropertyChangeSupport 以继续检查 inProgress 属性何时更改。

    package progressbarPoc;
    
    import java.awt.DisplayMode;
    import java.awt.GridBagLayout;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    
    import javax.swing.JFrame;
    import javax.swing.JProgressBar;
    
    
    public class MainFrame extends JFrame{
    
        public PropertyChangeSupport propertChangeSupport;
        public boolean inProgress;
        private JProgressBar bar;
        public Communicator diplayFacade;
        private PropertyChangeListener listener;
        public MainFrame() {
            this.setSize(500, 500);
            this.setVisible(true);
            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            diplayFacade = new Communicator();
            diplayFacade.frame = this;
            bar = new JProgressBar();
            setLayout(new GridBagLayout());
            add(bar);
            addProgressListener();
            propertChangeSupport = new PropertyChangeSupport(this);
    
    
            addListener();
    
            bar.addPropertyChangeListener(listener);
            this.addPropertyChangeListener(listener);
        }
    
        public void addPropertyChangeListener(PropertyChangeListener listener) {
            this.propertChangeSupport.addPropertyChangeListener(listener);
        }
    
    
    
        public void fireProperty(boolean oldValue , boolean newValue){
            this.propertChangeSupport.firePropertyChange("inProgress", oldValue, newValue);
        }
    
        public void addProgressListener(){
    
            System.out.println("Here");
    
    
    
    
    
        }
    
        public static void main(String[] args) {
            MainFrame frame = new MainFrame();
            frame.diplayFacade.methodCalled();
    
    
        }
    
    
        public void addListener(){
    
    
            listener = new PropertyChangeListener() {
    
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    addPropertyChangeListener(this);
                    if(true == inProgress){
                        System.out.println("Property change check none" + true);
                        bar.setIndeterminate(true);
                    }
                    else if(false ==inProgress){
                        System.out.println("Property change check none" + false);
                        bar.setIndeterminate(false);
    
                    }
    
                }
            };
        }
    
    }
    

    还有 Communicator 类

    package progressbarPoc;
    
    import java.beans.PropertyChangeListener;
    import java.beans.PropertyChangeSupport;
    
    import javax.swing.JOptionPane;
    
    public class Communicator {
    
        public MainFrame frame;
    
        public void methodCalled(){
    
            JOptionPane.showInputDialog("Hi");
            frame.inProgress = true;
    
            frame.fireProperty(frame.inProgress, !frame.inProgress);
        }
    
    }
    

    【讨论】:

    • 你不应该使用frame.fireProperty,你应该使用某种触发状态变化的setter,触发事件不是Communicator的责任......还有frame在您的示例中将是 null...
    • @MadProgrammer 不,为什么 framebe 会为 null 在 MainPanel 中我分配了“diplayFacade.frame = this”,我还是将其公开。虽然应该是私有的并且有getter和setter
    • 更糟糕的是……你已经将你的班级暴露给另一个不应被允许访问它的班级
    • @MadProgrammer frame.fireProperty 调用 MainFrame 中实际触发Property 的方法。请不要对名称感到困惑,他们可能会误导。它也工作得很好。我已经测试过了。
    • 您不应该修改您正在监控的对象的状态,因为这可能会触发无限循环并以股权溢出结束...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 2021-08-13
    • 2015-11-23
    • 1970-01-01
    • 2016-08-12
    • 1970-01-01
    相关资源
    最近更新 更多