Java 自定义标题包含搜索框和焦点问题的CellTable
我正在尝试实现一个具有自定义列标题的CellTable,该标题在正常列文本下方显示一个搜索框(简单文本框)。Java 自定义标题包含搜索框和焦点问题的CellTable,java,gwt,gwt-2.2-celltable,Java,Gwt,Gwt 2.2 Celltable,我正在尝试实现一个具有自定义列标题的CellTable,该标题在正常列文本下方显示一个搜索框(简单文本框)。搜索框应允许用户过滤CellTable。它应该是这样的: |Header 1|Header 2 | |SEARCHBOX|SEARCHBOX| ------------------------------------------------------- | ROW 1 ---------------------------------------------
搜索框应允许用户过滤CellTable。它应该是这样的:
|Header 1|Header 2 |
|SEARCHBOX|SEARCHBOX|
-------------------------------------------------------
| ROW 1
------------------------------------------------------
| ROW 2
一旦用户在搜索框中键入一个字符,就会触发一个RangeChangeEvent,导致服务器请求,并使用新的筛选列表更新CellTable。基本上一切正常。但是,一旦刷新CellTable,SearchBox就会失去焦点,用户必须再次用鼠标点击SearchBox以键入新字符。
这可能与在CellTable刷新后调用自定义标题及其单元格的render方法有关。
有没有办法将焦点设置回SearchBox?我试图设置tabindex=0,但没有效果。
自定义头类
公共静态类SearchHeader扩展了Header{
@凌驾
公共void呈现(上下文上下文,SafeHtmlBuilder sb){
(上下文,某人);
}
私人搜索术语搜索术语;
公共SearchHeader(SearchTerm SearchTerm、ValueUpdater ValueUpdater){
超级(新SearchCell());
setUpdater(valueUpdater);
this.searchTerm=searchTerm;
}
@凌驾
公共搜索术语getValue(){
返回搜索条件;
}
}
自定义搜索单元格(用于自定义标题)
当用户在搜索框中键入内容时,isChanged布尔标志设置为true,如果搜索框失去焦点,则返回到false。我添加此标志是为了区分哪个SearchBox获得焦点(如果我使用多个SearchBox)
公共静态类SearchCell扩展了AbstractCell{
接口模板扩展了安全HtmlTemplates{
@模板(“{0}”)
安全HTML标题(字符串列名称);
@模板(“”)
安全HTML输入(字符串值);
}
私有静态模板;
私有布尔值isChanged=false;
公共搜索单元(){
超级(“向下键”、“向上键”、“更改”、“模糊”);
如果(模板==null){
template=GWT.create(template.class);
}
}
@凌驾
public void render(com.google.gwt.cell.client.cell.Context),
SearchTerm值,安全HTMLBuilder sb){
sb.append(template.header(value.getCriteria().toString());
sb.append(template.input(value.getValue());
}
@凌驾
public void onBrowserEvent(上下文上下文、元素父级、SearchTerm值、NativeEvent事件、ValueUpdater ValueUpdater){
如果(值==null)
返回;
onBrowserEvent(上下文、父级、值、事件、值更新程序);
if(“keyup”.equals(event.getType()))
{
isChanged=true;
InputElem=getInputElement(父级);
setValue(elem.getValue());
if(valueUpdater!=null)
valueUpdater.update(值);
}
else if(“blur”.equals(event.getType())){
isChanged=false;
}
}
受保护的InputElement getInputElement(元素父级){
Element elem=parent.getElementsByTagName(“输入”).getItem(0);
断言(elem.getClass()==InputElement.class);
返回元素cast();
}
}
CellTable的初始化代码
NameColumn是具有适当类型的抽象Column类的实现。它在内部使用TextCell
ValueUpdater<SearchTerm> searchUpdater = new ValueUpdater<SearchTerm>() {
@Override
public void update(AccessionCellTableColumns.SearchTerm value) {
// fires a server request to return the new filtered list
RangeChangeEvent.fire(table, new Range(table.getPageStart(), table.getPageSize()));
}
};
table.addColumn(new NameColumn(searchTerm),new SearchHeader(searchTerm,searchUpdater));
ValueUpdater searchUpdater=newvalueUpdater(){
@凌驾
公共无效更新(AccessionCellTableColumns.SearchTerm值){
//激发服务器请求以返回新的筛选列表
RangeChangeEvent.fire(表,新范围(表.getPageStart(),表.getPageSize());
}
};
table.addColumn(新名称列(searchTerm),新搜索头(searchTerm,searchUpdater));
瘦子
不幸的是,至少可以说GWT对自定义列标题的支持有点不稳定。如果有人喜欢使用AbstractCell类,你就会明白我的意思。此外,在列标题单元格中实现复合(嵌套小部件)的正确方法是半身像,因为我无法让它正常工作,也没有找到任何可使用的复合单元格示例
如果datagrid实现了ColumnSortHandler排序(LOL thats phunny),那么可能具有键或鼠标事件的嵌套UI对象将触发列排序。失败。我同样找不到一种方法来重载columnsort事件,以排除通过与嵌套的列标题ui组件/小部件交互而触发的触发器。更不用说,您需要通过将内联HTML写入构建单元格的模板接口来抽象地定义嵌套组件。这几乎不是一个优雅的选择,因为它迫使开发人员必须编写本机JavaScript代码来创建和控制与列标题中的嵌套组件/小部件相关联的处理程序
这种“适当”的实现技术也不能解决这个问题所解决的焦点问题,而且对于需要AsyncProvider(或ListProvider)数据集和列单元过滤或自定义呈现的复杂数据网格来说,它也不是一个很好的解决方案。这方面的性能也远远不是一个合适的解决方案
严重吗?
为了实现功能性的列单元格过滤,您必须从GWT和疯狂的JQuery库之前的更传统的动态javascript/css方法中解决这个问题。我的功能解决方案是“适当”方式与一些狡猾的css的混合
psuedo代码如下所示:
public static class SearchCell extends AbstractCell<SearchTerm> {
interface Template extends SafeHtmlTemplates {
@Template("<div style=\"\">{0}</div>")
SafeHtml header(String columnName);
@Template("<div style=\"\"><input type=\"text\" value=\"{0}\"/></div>")
SafeHtml input(String value);
}
private static Template template;
private boolean isChanged = false;
public SearchCell() {
super("keydown","keyup","change","blur");
if (template == null) {
template = GWT.create(Template.class);
}
}
@Override
public void render(com.google.gwt.cell.client.Cell.Context context,
SearchTerm value, SafeHtmlBuilder sb) {
sb.append(template.header(value.getCriteria().toString()));
sb.append(template.input(value.getValue()));
}
@Override
public void onBrowserEvent(Context context,Element parent, SearchTerm value,NativeEvent event,ValueUpdater<SearchTerm> valueUpdater) {
if (value == null)
return;
super.onBrowserEvent(context, parent, value, event, valueUpdater);
if ("keyup".equals(event.getType()))
{
isChanged = true;
InputElement elem = getInputElement(parent);
value.setValue(elem.getValue());
if (valueUpdater != null)
valueUpdater.update(value);
}
else if ("blur".equals(event.getType())) {
isChanged =false;
}
}
protected InputElement getInputElement(Element parent) {
Element elem = parent.getElementsByTagName("input").getItem(0);
assert(elem.getClass() == InputElement.class);
return elem.cast();
}
}
ValueUpdater<SearchTerm> searchUpdater = new ValueUpdater<SearchTerm>() {
@Override
public void update(AccessionCellTableColumns.SearchTerm value) {
// fires a server request to return the new filtered list
RangeChangeEvent.fire(table, new Range(table.getPageStart(), table.getPageSize()));
}
};
table.addColumn(new NameColumn(searchTerm),new SearchHeader(searchTerm,searchUpdater));
public abstract class PagingFilterDataGrid<T> extends LayoutPanel {
public PagingFilterDataGrid() {
//ctor initializers
initDataGrid();
initColumns();
updateColumns();
initPager();
setupDataGrid();
}
}
public abstract class GridStringColumn<M> extends Column<VwGovernorRule, String> {
private String text_;
private String tooltip_;
private boolean defaultShown_ = true;
private boolean hidden_ = false;
public GridStringColumn(String fieldName, String text, String tooltip, boolean defaultShown, boolean sortable, boolean hidden) {
super(new TextCell());
setDataStoreName(fieldName);
this.text_ = text;
this.tooltip_ = tooltip;
this.defaultShown_ = defaultShown;
setSortable(sortable);
this.hidden_ = hidden;
}
}
public abstract class PagingFilterDataGrid<T> extends LayoutPanel {
private List<GridStringColumn<T>> columns_ = new ArrayList<GridStringColumn<T>>();
}
@Override
public void initColumns() {
getColumns().add(new GridStringColumn<MyPOJODataModel>("columnName", "dataStoreFieldName", "column tooltip / description information about this column", true, true, false) {
@Override
public String getValue(MyPOJODataModelobject) {
return object.getFieldValue();
}
});
}
@SuppressWarnings("unchecked")
public void updateColumns() {
if (dataGrid_.getColumnCount() > 0) {
clearColumns();
}
for (GridStringColumn<T> column : getColumns()) {
if (!column.isHidden()) {
dataGrid_.addColumn((Column<T, ?>) column, new ColumnHeader(column.getText(), column.getDataStoreName()));
}
}
initFilters();
}
final public class ColumnHeaderFilterCell extends AbstractCell<String> {
interface Templates extends SafeHtmlTemplates {
@SafeHtmlTemplates.Template("<div class=\"headerText\">{0}</div>")
SafeHtml text(String value);
@SafeHtmlTemplates.Template("<div class=\"headerFilter\"><input type=\"text\" value=\"\"/></div>")
SafeHtml filter();
}
private static Templates templates = GWT.create(Templates.class);
@Override
public void render(Context context, String value, SafeHtmlBuilder sb) {
if (value == null) {
return;
}
SafeHtml renderedText = templates.text(value);
sb.append(renderedText);
SafeHtml renderedFilter = templates.filter();
sb.append(renderedFilter);
}
}
public static class ColumnHeader extends Header<String> {
private String name_;
public ColumnHeader(String name, String field) {
super(new ColumnHeaderFilterCell());
this.name_ = name;
setHeaderStyleNames("columnHeader " + field);
}
@Override
public String getValue() {
return name_;
}
}
.gridData table {
overflow: hidden;
white-space: nowrap;
table-layout: fixed;
border-spacing: 0px;
}
.gridData table td {
border: none;
border-right: 1px solid #DBDBDB;
border-bottom: 1px solid #DBDBDB;
padding: 2px 9px
}
.gridContainer .filterContainer {
position: relative;
z-index: 1000;
top: 28px;
}
.gridContainer .filterContainer td {
padding: 0 13px 0 5px;
width: auto;
text-align: center;
}
.gridContainer .filterContainer .filterInput {
width: 100%;
}
.gridData table .columnHeader {
white-space: normal;
vertical-align: bottom;
text-align: center;
background-color: #EEEEEE;
border-right: 1px solid #D4D4D4;
}
.gridData table .columnHeader div img {
position: relative;
top: -18px;
}
.gridData table .columnHeader .headerText {
font-size: 90%;
line-height: 92%;
}
.gridData table .columnHeader .headerFilter {
visibility: hidden;
height: 32px;
}
private HorizontalPanel filterContainer_ = new HorizontalPanel();
public void initFilters() {
filterContainer_.setStylePrimaryName("filterContainer");
for (GridStringColumn<T> column : getColumns()) {
if (!column.isHidden()) {
Filter filterInput = new Filter(column);
filters_.add(filterInput);
filterContainer_.add(filterInput);
filterContainer_.setCellWidth(filterInput, "auto");
}
}
}
public class Filter extends TextBox {
final private GridStringColumn<T> boundColumn_;
public Filter(GridStringColumn<T> column) {
super();
boundColumn_ = column;
addStyleName("filterInput " + boundColumn_.getDataStoreName());
addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
filterTimer.cancel();
filterTimer.schedule(FILTER_DELAY);
}
});
}
public GridStringColumn<T> getBoundColumn() {
return boundColumn_;
}
}
public void setupDataGrid() {
add(pagerContainer_);
setWidgetTopHeight(pagerContainer_, 0, Unit.PX, PAGER_HEIGHT, Unit.PX);
add(filterContainer_);
setWidgetTopHeight(filterContainer_, PAGER_HEIGHT + FILTER_HEIGHT, Unit.PX, FILTER_HEIGHT, Unit.PX);
add(dataGrid_);
setWidgetTopHeight(dataGrid_, PAGER_HEIGHT, Unit.PX, ScreenManager.getScreenHeight() - PAGER_HEIGHT - BORDER_HEIGHT, Unit.PX);
pager_.setVisible(true);
dataGrid_.setVisible(true);
}
final private static int PAGER_HEIGHT = 32;
final private static int FILTER_HEIGHT = 32;
final private static int BORDER_HEIGHT = 2;
.gridContainer .filterContainer {
position: relative;
z-index: 1000;
top: 28px;
}
.gridContainer .filterContainer td {
padding: 0 13px 0 5px;
width: auto;
text-align: center;
}
.gridContainer .filterContainer .filterInput {
width: 100%;
}
addKeyUpHandler(new KeyUpHandler() {
@Override
public void onKeyUp(KeyUpEvent event) {
filterTimer.cancel();
filterTimer.schedule(FILTER_DELAY);
}
});
private FilterTimer filterTimer = new FilterTimer();
private class FilterTimer extends Timer {
@Override
public void run() {
updateDataList();
}
}
public void updateDataList() {
initParameters();
// required parameters controlled by datagrid
parameters_.put("limit", limit_ + "");
parameters_.put("offset", offset_ + "");
// sort parameters
if (sortField_.equals("") || sortOrder_.equals("")) {
parameters_.remove("sortField");
parameters_.remove("sortDir");
} else {
parameters_.put("sortField", sortField_);
parameters_.put("sortDir", sortOrder_);
}
// filter parameters
for (Filter filter : filters_) {
if (!filter.getValue().equals("")) {
CGlobal.LOG.info("filter: " + filter.getBoundColumn().getDataStoreName() + "=" + filter.getValue());
parameters_.put(filter.getBoundColumn().getDataStoreName(), filter.getValue());
}
}
RequestServiceAsync requestService = (RequestServiceAsync) GWT.create(RequestService.class);
requestService.getRequest("RPC", getParameters(), new ProviderAsyncCallback());
}
<b:if cond='data:blog.pageType == "static_page"'></b:if>