我正在使用带有DatePickerCell的CellTable,我希望能够显示未设置的日期,例如“空”日期。但在实现getValue方法时,我必须返回一些内容:
Column<EventProxy, Date> startTimeColumn = new Column<EventProxy, Date>(
new DatePickerCell()) {
@Override
public Date getValue(EventProxy object) {
Date ret = object.getStartTime();
return ret != null ? ret : new Date();
}
};
如果object.getStartTime()为null,则表示未设置它,我想要显示它。或者使用空标签或文本为“空”。正如我所说,方法getValue必须返回一些东西。如果我返回null,我稍后会得到异常,如果我返回具体日期,则将其显示为有效日期。还有其他选择吗? DatePickerCell会识别为空或未设置值的一些特殊日期标记或对象?
答案 0 :(得分:2)
你想知道显示日期,对吧?然后将焦点从getValue()移开,并查看覆盖render()方法(在Column类中找到)。 render()方法有一个object参数,就像getValue()一样,还有一个SafeHtmlBuilder的参数,你可以在其中附加对象值的表示。测试getStartTime(),如果为null,则将“[unset]”(或其他)附加到该SafeHtmlBuilder。您甚至可以附加一个带有红色三角形的钟面图像(使用HTML img标签)或您关心的任何内容,因为渲染只是附加将放入单元格的HTML。
在Guava的第10版中提供的新类不是直接相关的,但可能在另一个上下文中有用。它被称为Optional。它是一个包含您正在使用的类的泛型,在本例中为Date。它提供了一种使用提供的方法明确区分空值和取消设置值等的方法。快速阅读 - 因为您正在处理空日期,这可能在您设计的其他地方有用。
答案 1 :(得分:2)
DatePickerCell
不支持空值。覆盖render
是不够的,因为当您点击渲染的单元格时,方法NPE
会抛出onEnterKeyDown
。
您必须在“onEnterKeyDown”中实现自己的具有空保护的单元格:
if (date != null) {
datePicker.setCurrentMonth(date);
}
完整课程:
public class DatePickerCell extends AbstractEditableCell<Date, Date> {
private static final int ESCAPE = 27;
private final DatePicker datePicker;
private final DateTimeFormat format;
private int offsetX = 10;
private int offsetY = 10;
private Object lastKey;
private Element lastParent;
private int lastIndex;
private int lastColumn;
private Date lastValue;
private PopupPanel panel;
private final SafeHtmlRenderer<String> renderer;
private ValueUpdater<Date> valueUpdater;
/**
* Constructs a new DatePickerCell that uses the date/time format given by
* {@link DateTimeFormat#getFullDateFormat}.
*/
@SuppressWarnings("deprecation")
public DatePickerCell() {
this(DateTimeFormat.getFullDateFormat(), SimpleSafeHtmlRenderer.getInstance());
}
/**
* Constructs a new DatePickerCell that uses the given date/time format and
* a {@link SimpleSafeHtmlRenderer}.
* @param format a {@link DateTimeFormat} instance
*/
public DatePickerCell(DateTimeFormat format) {
this(format, SimpleSafeHtmlRenderer.getInstance());
}
/**
* Constructs a new DatePickerCell that uses the date/time format given by
* {@link DateTimeFormat#getFullDateFormat} and the given
* {@link SafeHtmlRenderer}.
* @param renderer a {@link SafeHtmlRenderer SafeHtmlRenderer<String>}
* instance
*/
public DatePickerCell(SafeHtmlRenderer<String> renderer) {
this(DateTimeFormat.getFormat(PredefinedFormat.DATE_FULL), renderer);
}
/**
* Constructs a new DatePickerCell that uses the given date/time format and
* {@link SafeHtmlRenderer}.
* @param format a {@link DateTimeFormat} instance
* @param renderer a {@link SafeHtmlRenderer SafeHtmlRenderer<String>}
* instance
*/
public DatePickerCell(DateTimeFormat format, SafeHtmlRenderer<String> renderer) {
super(CLICK, KEYDOWN);
if (format == null) {
throw new IllegalArgumentException("format == null");
}
if (renderer == null) {
throw new IllegalArgumentException("renderer == null");
}
this.format = format;
this.renderer = renderer;
this.datePicker = new DatePicker();
this.panel = new PopupPanel(true, true) {
@Override
protected void onPreviewNativeEvent(NativePreviewEvent event) {
if (Event.ONKEYUP == event.getTypeInt()) {
if (event.getNativeEvent().getKeyCode() == ESCAPE) {
// Dismiss when escape is pressed
panel.hide();
}
}
}
};
panel.addCloseHandler(new CloseHandler<PopupPanel>() {
public void onClose(CloseEvent<PopupPanel> event) {
lastKey = null;
lastValue = null;
lastIndex = -1;
lastColumn = -1;
if (lastParent != null && !event.isAutoClosed()) {
// Refocus on the containing cell after the user selects a
// value, but
// not if the popup is auto closed.
lastParent.focus();
}
lastParent = null;
}
});
panel.add(datePicker);
// Hide the panel and call valueUpdater.update when a date is selected
datePicker.addValueChangeHandler(new ValueChangeHandler<Date>() {
public void onValueChange(ValueChangeEvent<Date> event) {
// Remember the values before hiding the popup.
Element cellParent = lastParent;
Date oldValue = lastValue;
Object key = lastKey;
int index = lastIndex;
int column = lastColumn;
panel.hide();
// Update the cell and value updater.
Date date = event.getValue();
setViewData(key, date);
setValue(new Context(index, column, key), cellParent, oldValue);
if (valueUpdater != null) {
valueUpdater.update(date);
}
}
});
}
@Override
public boolean isEditing(Context context, Element parent, Date value) {
return lastKey != null && lastKey.equals(context.getKey());
}
@Override
public void onBrowserEvent(Context context, Element parent, Date value, NativeEvent event, ValueUpdater<Date> valueUpdater) {
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if (CLICK.equals(event.getType())) {
onEnterKeyDown(context, parent, value, event, valueUpdater);
}
}
@Override
public void render(Context context, Date value, SafeHtmlBuilder sb) {
// Get the view data.
Object key = context.getKey();
Date viewData = getViewData(key);
if (viewData != null && viewData.equals(value)) {
clearViewData(key);
viewData = null;
}
String s = null;
if (viewData != null) {
s = format.format(viewData);
} else if (value != null) {
s = format.format(value);
}
if (s != null) {
sb.append(renderer.render(s));
}
}
@Override
protected void onEnterKeyDown(Context context, Element parent, Date value, NativeEvent event, ValueUpdater<Date> valueUpdater) {
this.lastKey = context.getKey();
this.lastParent = parent;
this.lastValue = value;
this.lastIndex = context.getIndex();
this.lastColumn = context.getColumn();
this.valueUpdater = valueUpdater;
Date viewData = getViewData(lastKey);
Date date = (viewData == null) ? lastValue : viewData;
if (date != null) {
datePicker.setCurrentMonth(date);
}
datePicker.setValue(date);
panel.setPopupPositionAndShow(new PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
panel.setPopupPosition(lastParent.getAbsoluteLeft() + offsetX, lastParent.getAbsoluteTop() + offsetY);
}
});
}
}