Java 自定义标题包含搜索框和焦点问题的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,该标题在正常列文本下方显示一个搜索框(简单文本框)。
搜索框应允许用户过滤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代码如下所示:

  • 确保你的gri
    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>