Java 为什么firePropertyChange(字符串propertyName、对象oldValue、对象newValue)受保护而不是公共的?
问题是,我正在从库中开发一个Java 为什么firePropertyChange(字符串propertyName、对象oldValue、对象newValue)受保护而不是公共的?,java,swing,event-handling,jcalendar,Java,Swing,Event Handling,Jcalendar,问题是,我正在从库中开发一个IDateEditor接口实现,我注意到该方法不是公共的,而是受保护的。情况如下: public class DateFormattedTextField implements IDateEditor { private JFormattedTextField editor; private DateUtil dateUtil; ... @Override public void setDate(Date
IDateEditor
接口实现,我注意到该方法不是公共的,而是受保护的。情况如下:
public class DateFormattedTextField implements IDateEditor {
private JFormattedTextField editor;
private DateUtil dateUtil;
...
@Override
public void setDate(Date date) {
Date oldDate = (Date)editor.getValue();
if(dateUtil.checkDate(date)){
editor.setValue(date);
editor.firePropertyChange("date", oldDate, date); // <-- error here
}
}
}
公共类DateFormattedTextField实现IDateEditor{
私有JFormattedTextField编辑器;
私有DateUtil-DateUtil;
...
@凌驾
公共作废设置日期(日期){
Date oldDate=(Date)editor.getValue();
if(dateUtil.checkDate(日期)){
编辑器.设置值(日期);
firePropertyChange(“date”,oldDate,date);//更改通知是任何可观察对象(通常是java bean)的固有责任:如果在其绑定属性发生更改时不触发PropertyChangeEvent,则会违反其合同。在这种情况下,任何其他方都不需要使用fireXX方法
因此,范围比受保护的范围更广是没有任何意义的。如果你觉得需要它,你就做错了。我添加这个答案只是为了完整性。在@kleopatra明智的解释和评论之后,我意识到我混淆了概念和责任。在这种情况下,属性更改通知作为底层编辑器组件使用的JFormattedTextField
不负责初始化,而是IDateEditor
实现本身的责任
因此,为了实现我用来保存属性更改侦听器列表的接口,并通过以下方式通知它们:
正如您所见,添加/删除PropertyChangeListeners
并在属性更改事件中通知他们的任务被委托给PropertyChangeSupport
类成员,但事件的源是this
,即IDateEdit
接口实现者。正如@kleopatra所说,这是客户端的源应该是事件的源,而不是参考线编辑器组件
下面是生成类的完整代码(很抱歉进行了扩展)。如果您愿意,请随意使用/修改或玩它
/**
* Custom implementation of {@code IDateEditor} interface. Unlike the default
* implementation provided with JCalendar library, this won't allow invalid
* inputs of any kind from the user.
*
* @author dic19
*/
public class DefaultDateEditor implements IDateEditor {
private Date date;
private String dateFormatString;
private Locale locale;
private SimpleDateFormat dateFormat;
private final DateFormatter dateFormatter;
private final JFormattedTextField editor;
private final DateUtil dateUtil;
private final PropertyChangeSupport propertyChangeSupport;
public DefaultDateEditor() {
date = new Date();
dateUtil = new DateUtil();
propertyChangeSupport = new PropertyChangeSupport(this);
addPropertyChangeListener("dateFormatString", new DateFormatStringChangeListener());
addPropertyChangeListener("locale", new LocaleChangeListener());
dateFormatString = "yyyy-MM-dd HH:mm:ss";
locale = Locale.getDefault();
dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
dateFormat.applyPattern(dateFormatString);
dateFormatter = new DateFormatter();
dateFormatter.setCommitsOnValidEdit(true);
dateFormatter.setAllowsInvalid(false);
dateFormatter.setOverwriteMode(true);
editor = new JFormattedTextField();
editor.setValue(date);
editor.setColumns(15);
editor.setToolTipText(dateFormatString);
editor.addPropertyChangeListener("value", new EditorValueChangeListener());
installFormatterFactoryOnEditor();
}
private void installFormatterFactoryOnEditor() {
dateFormatter.setFormat(dateFormat);
DefaultFormatterFactory factory = editor.getFormatterFactory() instanceof DefaultFormatterFactory
? (DefaultFormatterFactory) editor.getFormatterFactory()
: new DefaultFormatterFactory();
factory.setDefaultFormatter(dateFormatter);
factory.setDisplayFormatter(dateFormatter);
factory.setEditFormatter(dateFormatter);
factory.setNullFormatter(dateFormatter);
editor.setFormatterFactory(factory);
}
@Override
public Date getDate() {
return date != null ? new Date(date.getTime()) : null;
}
@Override
public void setDate(Date date) {
if (dateUtil.checkDate(date)) {
Date oldValue = this.date;
this.date = date != null ? new Date(date.getTime()) : null;
editor.setValue(this.date);
firePropertyChangeEvent("date", oldValue, date);
}
}
@Override
public void setDateFormatString(String dateFormatString) {
String oldDateFormat = this.dateFormatString;
this.dateFormatString = dateFormatString;
firePropertyChangeEvent("dateFormatString", oldDateFormat, dateFormatString);
}
@Override
public String getDateFormatString() {
return dateFormatString;
}
@Override
public void setSelectableDateRange(Date min, Date max) {
dateUtil.setSelectableDateRange(min, max);
}
@Override
public Date getMaxSelectableDate() {
return dateUtil.getMaxSelectableDate();
}
@Override
public Date getMinSelectableDate() {
return dateUtil.getMinSelectableDate();
}
@Override
public void setMaxSelectableDate(Date max) {
dateUtil.setMaxSelectableDate(max);
}
@Override
public void setMinSelectableDate(Date min) {
dateUtil.setMinSelectableDate(min);
}
@Override
public JComponent getUiComponent() {
return editor;
}
@Override
public void setLocale(Locale locale) {
Locale oldLocale = this.locale;
this.locale = locale;
firePropertyChangeEvent("locale", oldLocale, locale);
}
@Override
public void setEnabled(boolean enabled) {
editor.setEnabled(enabled);
}
@Override
public final void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
@Override
public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
@Override
public final void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
@Override
public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
public final PropertyChangeListener[] getPropertyChangeListeners() {
return propertyChangeSupport.getPropertyChangeListeners();
}
public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
return propertyChangeSupport.getPropertyChangeListeners(propertyName);
}
protected final void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
private class EditorValueChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("value".equals(evt.getPropertyName())) {
System.out.println("Old value:" + evt.getOldValue());
System.out.println("New value:" + evt.getNewValue());
setDate((Date)evt.getNewValue());
}
}
}
private class DateFormatStringChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("dateFormatString".equals(evt.getPropertyName())) {
dateFormat.applyPattern(dateFormatString);
editor.setToolTipText(dateFormatString);
installFormatterFactoryOnEditor();
}
}
}
private class LocaleChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("locale".equals(evt.getPropertyName())) {
dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
dateFormat.applyPattern(dateFormatString);
editor.setLocale(locale);
installFormatterFactoryOnEditor();
}
}
}
}
因为变更通知是编辑的固有责任——其他人不应该这样做interfere@kleopatra您需要回答这个问题!在您的实现中有一个小错误:向某个对象添加侦听器的客户端希望该对象作为事件源,所以干净地路由到某个委托意味着拦截任何通知rom代表,并在将源设置为itself@kleopatra感谢您指出这一点,我会记住:)您好!谢谢您的回答:)这对我来说完全有意义,但它会让我自动问为什么会有公共方法触发属性更改事件?例如:public void firePropertyChange(字符串propertyName、双oldValue、双newValue)
。这些方法是从AWT继承的吗,之前是Swing?这些方法是为了向后兼容吗?我不认为我需要这个方法公共的,正如我所说的那样,我可以简单地从JFormattedTextField扩展我的类并解决问题。事实上,我认为这样做完全符合你的答案。设计意外?我的猜测与您的:-)顺便说一句,为什么要扩展JFormattedTextField?通常,JXX用于按原样使用,因此您在扩展时走错方向的概率为非零。。。
public class DateFormattedTextField implements IDateEditor {
private JFormattedTextField editor;
private DateUtil dateUtil;
private DateFormat dateFormat;
private String dateFormatString;
public DateFormattedTextField(){
dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM);
editor = new JFormattedTextField(dateFormat);
editor.setColumns(10);
editor.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
dateUtil = new DateUtil();
}
@Override
public Date getDate() {
return (Date)editor.getValue();
}
@Override
public void setDate(Date date) {
Date oldDate = (Date)editor.getValue();
if(dateUtil.checkDate(date)){
editor.setValue(date);
editor.firePropertyChange("date", oldDate, date); // <-- error here
}
}
@Override
public void setDateFormatString(String dateFormatString) {
this.dateFormatString = dateFormatString;
}
@Override
public String getDateFormatString() {
return this.dateFormatString;
}
@Override
public void setSelectableDateRange(Date min, Date max) {
dateUtil.setSelectableDateRange(min, max);
}
@Override
public Date getMaxSelectableDate() {
return dateUtil.getMaxSelectableDate();
}
@Override
public Date getMinSelectableDate() {
return dateUtil.getMinSelectableDate();
}
@Override
public void setMaxSelectableDate(Date max) {
dateUtil.setMaxSelectableDate(max);
}
@Override
public void setMinSelectableDate(Date min) {
dateUtil.setMinSelectableDate(min);
}
@Override
public JComponent getUiComponent() {
return editor;
}
@Override
public void setLocale(Locale locale) {
editor.setLocale(locale); // to be reviewed
}
@Override
public void setEnabled(boolean enabled) {
editor.setEnabled(enabled);
}
@Override
public void addPropertyChangeListener(PropertyChangeListener listener) {
editor.addPropertyChangeListener(listener);
}
@Override
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
editor.addPropertyChangeListener(propertyName, listener);
}
@Override
public void removePropertyChangeListener(PropertyChangeListener listener) {
editor.removePropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
editor.removePropertyChangeListener(propertyName, listener);
}
}
public class DefaultDateEditor implements IDateEditor {
...
private final JFormattedTextField editor;
private final PropertyChangeSupport propertyChangeSupport;
...
public DefaultDateEditor() {
...
propertyChangeSupport = new PropertyChangeSupport(this);
...
editor = new JFormattedTextField();
...
}
@Override
public final void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
@Override
public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
@Override
public final void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
@Override
public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
public final PropertyChangeListener[] getPropertyChangeListeners() {
return propertyChangeSupport.getPropertyChangeListeners();
}
public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
return propertyChangeSupport.getPropertyChangeListeners(propertyName);
}
protected final void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
...
}
/**
* Custom implementation of {@code IDateEditor} interface. Unlike the default
* implementation provided with JCalendar library, this won't allow invalid
* inputs of any kind from the user.
*
* @author dic19
*/
public class DefaultDateEditor implements IDateEditor {
private Date date;
private String dateFormatString;
private Locale locale;
private SimpleDateFormat dateFormat;
private final DateFormatter dateFormatter;
private final JFormattedTextField editor;
private final DateUtil dateUtil;
private final PropertyChangeSupport propertyChangeSupport;
public DefaultDateEditor() {
date = new Date();
dateUtil = new DateUtil();
propertyChangeSupport = new PropertyChangeSupport(this);
addPropertyChangeListener("dateFormatString", new DateFormatStringChangeListener());
addPropertyChangeListener("locale", new LocaleChangeListener());
dateFormatString = "yyyy-MM-dd HH:mm:ss";
locale = Locale.getDefault();
dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
dateFormat.applyPattern(dateFormatString);
dateFormatter = new DateFormatter();
dateFormatter.setCommitsOnValidEdit(true);
dateFormatter.setAllowsInvalid(false);
dateFormatter.setOverwriteMode(true);
editor = new JFormattedTextField();
editor.setValue(date);
editor.setColumns(15);
editor.setToolTipText(dateFormatString);
editor.addPropertyChangeListener("value", new EditorValueChangeListener());
installFormatterFactoryOnEditor();
}
private void installFormatterFactoryOnEditor() {
dateFormatter.setFormat(dateFormat);
DefaultFormatterFactory factory = editor.getFormatterFactory() instanceof DefaultFormatterFactory
? (DefaultFormatterFactory) editor.getFormatterFactory()
: new DefaultFormatterFactory();
factory.setDefaultFormatter(dateFormatter);
factory.setDisplayFormatter(dateFormatter);
factory.setEditFormatter(dateFormatter);
factory.setNullFormatter(dateFormatter);
editor.setFormatterFactory(factory);
}
@Override
public Date getDate() {
return date != null ? new Date(date.getTime()) : null;
}
@Override
public void setDate(Date date) {
if (dateUtil.checkDate(date)) {
Date oldValue = this.date;
this.date = date != null ? new Date(date.getTime()) : null;
editor.setValue(this.date);
firePropertyChangeEvent("date", oldValue, date);
}
}
@Override
public void setDateFormatString(String dateFormatString) {
String oldDateFormat = this.dateFormatString;
this.dateFormatString = dateFormatString;
firePropertyChangeEvent("dateFormatString", oldDateFormat, dateFormatString);
}
@Override
public String getDateFormatString() {
return dateFormatString;
}
@Override
public void setSelectableDateRange(Date min, Date max) {
dateUtil.setSelectableDateRange(min, max);
}
@Override
public Date getMaxSelectableDate() {
return dateUtil.getMaxSelectableDate();
}
@Override
public Date getMinSelectableDate() {
return dateUtil.getMinSelectableDate();
}
@Override
public void setMaxSelectableDate(Date max) {
dateUtil.setMaxSelectableDate(max);
}
@Override
public void setMinSelectableDate(Date min) {
dateUtil.setMinSelectableDate(min);
}
@Override
public JComponent getUiComponent() {
return editor;
}
@Override
public void setLocale(Locale locale) {
Locale oldLocale = this.locale;
this.locale = locale;
firePropertyChangeEvent("locale", oldLocale, locale);
}
@Override
public void setEnabled(boolean enabled) {
editor.setEnabled(enabled);
}
@Override
public final void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
@Override
public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
@Override
public final void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
@Override
public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
public final PropertyChangeListener[] getPropertyChangeListeners() {
return propertyChangeSupport.getPropertyChangeListeners();
}
public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
return propertyChangeSupport.getPropertyChangeListeners(propertyName);
}
protected final void firePropertyChangeEvent(String propertyName, Object oldValue, Object newValue) {
propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
private class EditorValueChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("value".equals(evt.getPropertyName())) {
System.out.println("Old value:" + evt.getOldValue());
System.out.println("New value:" + evt.getNewValue());
setDate((Date)evt.getNewValue());
}
}
}
private class DateFormatStringChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("dateFormatString".equals(evt.getPropertyName())) {
dateFormat.applyPattern(dateFormatString);
editor.setToolTipText(dateFormatString);
installFormatterFactoryOnEditor();
}
}
}
private class LocaleChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("locale".equals(evt.getPropertyName())) {
dateFormat = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
dateFormat.applyPattern(dateFormatString);
editor.setLocale(locale);
installFormatterFactoryOnEditor();
}
}
}
}