使用PropertyChangeListener刷新JFrame(不触发无限循环)

时间:2015-06-03 19:49:29

标签: java swing javabeans repaint propertychangelistener

使用java,我有一个包含多个JPanel的JFrame,其中包括各种JComboBox,JTextFields等...它们连接到xml文件中的条目,按日期组织和查看。一切都同步并正在工作,但是当我对条目进行更改(即添加/删除等)时,我一直无法更新/刷新JFrame,尽管它在我更改日期时会刷新。我已经到了我有一个触发的PropertyChangeListener(打印到控制台),但当我尝试使用该Listener刷新帧时,我想我只是重新验证了监听器?

以下是JFrame中的代码(我使用注释来表示失败的段):

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("<<");
        private JButton dayBack = new JButton("<");
        private JButton returnToday = new JButton("Today");
        private JButton nextDay = new JButton(">");
        private JButton nextWeek = new JButton(">>");
        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 */}
    }
}

修改

经过一些反馈,到目前为止已经尝试过这个:

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

DailyView thisFrame;声明为顶部的实例变量。

修改

如果有人在那里读这个,我得到propertyChangeListener来触发某些会刷新底层面板的事件,但是这会导致无限循环,因为propertyChangeListener再次被调用。 (重新)验证()和重绘()似乎没有这个问题,但他们没有刷新面板的内容......任何能指出我正确方向/链接到类似问题等的人都会非常感谢。

1 个答案:

答案 0 :(得分:1)

当你使用'this'指针时,它总是引用你所在的类。我相信你的问题即将到来,因为'this'指针确实引用了你的监听器而不是JPanel。也许你的问题可以通过

来解决
Frame thisFrame = this;
body.addPropertyChangeListener(new PropertyChangeListener() {
        public void propertyChange(PropertyChangeEvent evt) {
            System.out.println("OperatorView.propertyChange");
            //***This is where I'm trying to TRIGGER the REFRESH***
            thisFrame.refreshFrame(); }
    });