我将JDateChooser用于正在开发的Java swing项目,因此可以用两种方式设置日期:最终用户或以编程方式设置日期。

因此,我在相应的类中定义了一个propertychangelistener(变量trig初始化为零,并跟踪监听了多少次属性更改)。

public class WriteEntry{
private int trig=0;
private Date currentDate = new Date();
public JDateChooser dateChooser = new JDateChooser();
public CustomDate selectedDate = DateConverter.convertDate(currentDate);
private static String filename = StorageSpace.currentpath+CurrentUser.getInstance().getUserName()+"\\"+
        Integer.toString(selectedDate.getYear())+"\\"
          +Integer.toString(selectedDate.getMonth())+"\\"+Integer.toString(selectedDate.getDay())+".txt";
private JLabel dayinfo = new JLabel("");
private JTextArea contentfield = new JTextArea("");
private PropertyChangeListener lis = new PropertyChangeListener(){
      @Override
      public void propertyChange(PropertyChangeEvent e) {
          System.out.println("triggered "+trig++);
            if(dateBoundary())  {
                selectedDate = DateConverter.convertDate(dateChooser);
                filename = StorageSpace.currentpath+CurrentUser.getInstance().getUserName()+"\\"+
                        Integer.toString(selectedDate.getYear())+"\\"
                          +Integer.toString(selectedDate.getMonth())+"\\"+Integer.toString(selectedDate.getDay())+".txt";
            }
            else {
                updateDateChooser(selectedDate);
            }
            if(isAlreadyWritten())
            {
                try {
                    updateEditFields(selectedDate, "content");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            else
            {
                contentfield.setText("Start writing here");
                dayinfo.setText("You are making entry for: "+ new SimpleDateFormat("dd/MM/yyyy").format(dateChooser.getDate()));
            }
      }
    };
WriteEntry() //constructor
{
dateChooser.setDateFormatString("dd MM yyyy");
dateChooser.addPropertyChangeListener(lis);
updateEditFields(DateConverter.convertDate(currentDate), "Start");
}
}


这是dateBoundary()的代码:

public static boolean dateBoundary() {
    Object[] option = {"I get it","My Bad!"};
    if(dateChooser.getDate().compareTo(currentDate)>0) {
        JOptionPane.showOptionDialog(HomePage.getFrame(),"message1",
                "",JOptionPane.DEFAULT_OPTION,JOptionPane.ERROR_MESSAGE,null,option,option[0]);
        return false;
    }
    if(dateChooser.getDate().compareTo(DateConverter.convertfromCustom(CurrentUser.getInstance().getDob()))<0){
JOptionPane.showOptionDialog(HomePage.getFrame(),"message2",
                "",JOptionPane.DEFAULT_OPTION,JOptionPane.ERROR_MESSAGE,null,option,option[0]);
        return false;
    }
    return true;
}


isAlreadyWritten()的代码:

public static boolean isAlreadyWritten() {
    File f = new File(filename);
    if(f.length()!=0)
    {
        Object[] option = {"Read","Edit"};
        JOptionPane.showOptionDialog(HomePage.getFrame(),"You already updated diary for this day. Do you want to edit?",
                "",JOptionPane.DEFAULT_OPTION,JOptionPane.INFORMATION_MESSAGE,null,option,option[0]);
        return true;
    }
    else
        return false;
}


updateDateChooser()的代码:

public static void updateDateChooser(CustomDate date) {
dateChooser.removePropertyChangeListener(lis); //to stop it from getting triggered when date is set programatically
dateChooser.setDate(DateConverter.convertfromCustom(date));
dateChooser.addPropertyChangeListener(lis);
}


updateEditFields()的代码:

public static void updateEditFields(CustomDate searchDate, String excontent) {
updateDateChooser(searchDate);
selectedDate = DateConverter.convertDate(dateChooser);
dayinfo.setText("You are editing entry for: "+ new SimpleDateFormat("dd/MM/yyyy").format(dateChooser.getDate()));
contentfield.setText(excontent);


}

现在,我的dateboundary函数正在按预期方式工作。每当选择一个大于当前日期的日期时,都会显示option对话框,并在单击后消失,并且datechooser设置为最后选择的日期,尽管propertychange方法被称为三次:


在对话框显示之前一次
对话框关闭后两次。


但是我的isAlreadyWritten()不能按预期方式工作,而optiondialog被显示4次,而propertychange()方法被调用了4次:
每次显示该对话框之前,请单击一次。

我想了解为什么即使以编程方式设置日期时,即使datechooser从侦听器中分离出来,propertychange仍被调用4次?

最佳答案

因此,我整理并运行了此摘要

import com.toedter.calendar.JDateChooser;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                JDateChooser dateChooser = new JDateChooser();
                dateChooser.addPropertyChangeListener(new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        System.out.println(evt.getPropertyName());
                    }
                });
                dateChooser.setDate(new Date());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(dateChooser);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}


我打开了日期选择器并选择了一个日期。程序输出...

date
ancestor
date
date



是我以编程方式设置日期吗
ancestor是否已添加到容器中
是我选择日期选择器吗
我要选择一个日期吗


因此,如您所见,不仅您不仅收到大量“日期”属性更改的垃圾邮件,而且还获得了所有“其他”属性更改的信息😓

因此,您要做的第一件事就是将通知仅限制为“ date”属性,例如...

dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println(evt.getPropertyName());
    }
});


这至少意味着您不会被所有无关的其他信息所困扰。

虽然您可以添加和删除侦听器,但由于我并不总是具有对侦听器的引用,因此我倾向于发现它很痛苦,相反,我倾向于使用状态标志来代替

private boolean manualDate = false;
//...
dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (manualDate) {
            return;
        }
        System.out.println(evt.getPropertyName());
    }
});

manualDate = true;
dateChooser.setDate(new Date());
manualDate = false;


变化不大,但这仅意味着您现在只有两个事件通知。

相反,您应该将oldValuenewValuePropertyChangeEvent

JDateChooser dateChooser = new JDateChooser();
dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (manualDate) {
            return;
        }
        Date newDate = (Date) evt.getNewValue();
        Date oldDate = (Date) evt.getOldValue();
        if (newDate != null && oldDate != null) {
            LocalDate newLD = LocalDate.ofInstant(newDate.toInstant(), ZoneId.systemDefault());
            LocalDate oldLD = LocalDate.ofInstant(oldDate.toInstant(), ZoneId.systemDefault());
            if (newLD.equals(oldLD)) {
                return;
            }
        }
        System.out.println(evt.getPropertyName());
    }
});


现在,我们要进行一次变更活动。唯一的缺点是,当他们重新选择当前日期时,它不会告诉您。

更好的工作流程可能是完全忽略所有这些,而只是让用户可以按JButton执行您需要执行的所有相关操作

可运行的示例...

import com.toedter.calendar.JDateChooser;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    private boolean manualDate;

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                JDateChooser dateChooser = new JDateChooser();
                dateChooser.addPropertyChangeListener("date", new PropertyChangeListener() {
                    @Override
                    public void propertyChange(PropertyChangeEvent evt) {
                        if (manualDate) {
                            return;
                        }
                        Date newDate = (Date) evt.getNewValue();
                        Date oldDate = (Date) evt.getOldValue();
                        if (newDate != null && oldDate != null) {
                            LocalDate newLD = LocalDate.ofInstant(newDate.toInstant(), ZoneId.systemDefault());
                            LocalDate oldLD = LocalDate.ofInstant(oldDate.toInstant(), ZoneId.systemDefault());
                            if (newLD.equals(oldLD)) {
                                return;
                            }
                        }
                        System.out.println(evt.getPropertyName());
                    }
                });
                manualDate = true;
                dateChooser.setDate(new Date());
                manualDate = false;

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(dateChooser);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

07-25 21:14
查看更多