当前位置: 代码迷 >> Web前端 >> gwt 兑现界面模式之 "Extras on Demand"
  详细解决方案

gwt 兑现界面模式之 "Extras on Demand"

热度:388   发布时间:2012-11-23 00:03:43.0
gwt 实现界面模式之 "Extras on Demand"

GWT 是一个强大的工具, 一旦定义好html结构和css之后,使用gwt提供的组件模型,可以将任意结构的html+css封装成为组件 ,并在java 语言中以组件的方式操作.GWT 1.6 增加了新的事件系统(原有的事件api可能会在将来删除), 更使得在dom或者现有的组件之上扩展开发相当容易.下面将以一个例子说明如何使用新的事件模型扩展现有组件.

(使用最新的 gwt 1.6.4 )

?

目标:


如上, 在google 财经中有一个最近查询的股票列表,当鼠标在上面移动时,仅有当前行的操作(删除)出现,这有点类似界面模式中的"Extras on Demand ". 我们的目标就是要在gwt 中实现类似的特性..

解决方案

相比较自己完全从html结构开始做起,如果能够在一个现有的组件之上进行开发,会减轻不少工作量,gwt 中提供了很多灵活,强大的组件.FlexTable 就是其中之一.FlextTable 很适合数据量不大的少量表格数据显示.也适合作为灵活的布局容器,如果需要显示大量数据,可以考虑 gwt incubator 中的 PagingScrollTable.

实现以上特性的关键是要能捕获鼠标移动事件(MouserMoveEvent), 并处理. FlexTable 支持ClickEvent, 并且可以使用 getCellForEvent 方法获得事件发生时的单元格对象,进而获得所在行. 当并不支持MouseMoveEvent. 所以首先我们需要从FlexTable 继承,并增加MouseMoveEvent 的事件支持.

public class MouseMoveableFexTable extends FlexTable implements HasMouseMoveHandlers, HasMouseOverHandlers,
        HasMouseOutHandlers {

    public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
        return addDomHandler(handler, MouseMoveEvent.getType());
    }

    public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
        return addDomHandler(handler, MouseOverEvent.getType());
    }

    public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
        return addDomHandler(handler, MouseOutEvent.getType());
    }

?增加事件处理在新的事件模型下就是如此简单,基本上不再需要去处理 onBrowserEvent 了,增加一个 HasXXX handler 的接口,然后在实现方法中加上一句 addDomHandler即可.我们同时实现了HasMouseOverHandlers,HasMouseOutHandlers. 因为希望在鼠标进入或者离开表格区域时,客户端也能检测到,并做相应的处理.

?

接下来我们需要象FlexTable 处理ClickEvent 一样,从MouseEvent 中返回所在的单元格信息

public class TableCell {

        int rowIdx;
        int colIdx;

        public TableCell(int rowIdx, int colIdx) {
            this.rowIdx = rowIdx;
            this.colIdx = colIdx;
        }

        public int getColIdx() {
            return colIdx;
        }

        public void setColIdx(int colIdx) {
            this.colIdx = colIdx;
        }

        public int getRowIdx() {
            return rowIdx;
        }

        public void setRowIdx(int rowIdx) {
            this.rowIdx = rowIdx;
        }
    }

    public TableCell getTableCellForEvent(DomEvent event) {
        Element td = getEventTargetCell(Event.as(event.getNativeEvent()));
        if (td == null) {
            return null;
        }
        Element tr = DOM.getParent(td);
        Element body = DOM.getParent(tr);
        int row = DOM.getChildIndex(body, tr);
        int column = DOM.getChildIndex(tr, td);

        return new TableCell(row, column);
    }

?首先定义了一个TableCell 内部类,用于传递单元格信息,之后定义一个 getTableCellForEvent 用于将事件转换成为单元格信息. 实现了这个功能后, 客户端就能注册 MouseMoveHandler, MouseOutHandler, 接收事件,提取当前的单元格信息,进而实现相应的程序操作了.

?

完整的代码如下:

/**
 * This code is released under lgpl v3 license.
 * All rights reserved.
 */
package net.gwidgets.client;

import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
import com.google.gwt.event.dom.client.HasMouseOutHandlers;
import com.google.gwt.event.dom.client.HasMouseOverHandlers;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.FlexTable;

/**
 * 
 * @author yuan yunchang    dukerr@gmail.com
 */
public class MouseMoveableFexTable extends FlexTable implements HasMouseMoveHandlers, HasMouseOverHandlers,
        HasMouseOutHandlers {

    public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
        return addDomHandler(handler, MouseMoveEvent.getType());
    }

    public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
        return addDomHandler(handler, MouseOverEvent.getType());
    }

    public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
        return addDomHandler(handler, MouseOutEvent.getType());
    }

    public class TableCell {

        int rowIdx;
        int colIdx;

        public TableCell(int rowIdx, int colIdx) {
            this.rowIdx = rowIdx;
            this.colIdx = colIdx;
        }

        public int getColIdx() {
            return colIdx;
        }

        public void setColIdx(int colIdx) {
            this.colIdx = colIdx;
        }

        public int getRowIdx() {
            return rowIdx;
        }

        public void setRowIdx(int rowIdx) {
            this.rowIdx = rowIdx;
        }
    }

    public TableCell getTableCellForEvent(DomEvent event) {
        Element td = getEventTargetCell(Event.as(event.getNativeEvent()));
        if (td == null) {
            return null;
        }
        Element tr = DOM.getParent(td);
        Element body = DOM.getParent(tr);
        int row = DOM.getChildIndex(body, tr);
        int column = DOM.getChildIndex(tr, td);

        return new TableCell(row, column);
    }
}

?

这是一个基于以上基础的demo:


完整的代码如下:

java module file:

/**
 * This code is released under lgpl v3 license.
 * All rights reserved.
 */
package net.gwidgets.demo.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Widget;
import net.gwidgets.client.MouseMoveableFexTable;

/**
 *
 * @author yuan yunchang    dukerr@gmail.com
 */
public class MouseMoveControl implements EntryPoint {

    int currentRow = -1;
    MouseMoveableFexTable tb;

    public void onModuleLoad() {
        createTest();
    }

    private void createTest() {
        tb = new MouseMoveableFexTable();
        tb.setStylePrimaryName("testTable");
        
        tb.setText(0, 0, "名称");
        tb.setText(0, 1, "价格");
        tb.setText(0, 2, "涨跌");
        tb.getRowFormatter().addStyleName(0, "title");


        tb.setText(1, 0, "中国银行");
        tb.setText(1, 1, "3.53");
        tb.setText(1, 2, "-0.03 (-0.84%)");
        DelControl del = new DelControl("x");
        del.addClickHandler(new ClickHandler() {

            public void onClick(ClickEvent event) {
                delRow(currentRow);
            }
        });
        tb.setWidget(1, 3, del);
        tb.getRowFormatter().addStyleName(1, "data");

        tb.setText(2, 0, "中国石油");
        tb.setText(2, 1, "11.83");
        tb.setText(2, 2, "-0.10 (-0.84%)");
        del = new DelControl("x");
        del.addClickHandler(new ClickHandler() {

            public void onClick(ClickEvent event) {
                delRow(currentRow);
            }
        });
        tb.setWidget(2, 3, del);
        tb.getRowFormatter().addStyleName(2, "data");

        tb.setText(3, 0, "宝钢股份");
        tb.setText(3, 1, "6.00");
        tb.setText(3, 2, "-0.01 (-0.17%)");
        del = new DelControl("x");
        del.addClickHandler(new ClickHandler() {

            public void onClick(ClickEvent event) {
                delRow(currentRow);
            }
        });
        tb.setWidget(3, 3, del);
        tb.getRowFormatter().addStyleName(3, "data");

        tb.addMouseMoveHandler(new MouseMoveHandler() {

            public void onMouseMove(MouseMoveEvent event) {
                MouseMoveableFexTable.TableCell cell = tb.getTableCellForEvent(event);
                if (cell != null) {
                    int row = cell.getRowIdx();
                    if(row>0){
                        setCurrent(row);
                    }
                }
            }
        });
        tb.addMouseOutHandler(new MouseOutHandler() {
            public void onMouseOut(MouseOutEvent event) {
                hideCurrenDel();
            }
        });

        tb.getColumnFormatter().addStyleName(0, "name");
        tb.getColumnFormatter().addStyleName(1, "price");
        tb.getColumnFormatter().addStyleName(2, "updown");

        RootPanel.get("mouse_move").add(tb);

    }

    void setCurrent(int row) {
        hideCurrenDel();
        Widget w = tb.getWidget(row, 3);
        w.setVisible(true);
        currentRow = row;
        tb.getRowFormatter().addStyleName(row, "current");

    }
    void hideCurrenDel(){
        if (currentRow > 0) {
            Widget prew = tb.getWidget(currentRow, 3);
            prew.setVisible(false);
            tb.getRowFormatter().removeStyleName(currentRow, "current");
        }
    }
    void delRow(int row) {
        tb.removeRow(row);
        currentRow = -1;
    }

    class DelControl extends Label {

        public DelControl(String text, boolean wordWrap) {
            super(text, wordWrap);
            setStylePrimaryName("delControl");
            setVisible(false);
            setTitle("删除");
        }

        public DelControl(String text) {
            super(text);
            setStylePrimaryName("delControl");
            setVisible(false);
        }

        public DelControl() {
            setStylePrimaryName("delControl");
            setVisible(false);
        }
    }
}
?

html:

<!--

-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script type="text/javascript" language="javascript" src="mousemove_control/mousemove_control.nocache.js"></script>
        <style>
           
        </style>
    </head>
    <body>
        <div class="main">
            <h3>mouse move controls demo</h3>
            <div id="mouse_move" ></div>
        </div>
    </body>
</html>

?css:

.main{
    margin-left:5em;
    margin-right:5em;
}
#mouse_move{
    margin-top:1em;
}
.delControl{
    padding:1px 5px;
    border:1px solid #aaaaaa;
    cursor:pointer;
}
.testTable{
    cursor:default;
}
.testTable .current{
    background-color:#eeeeee;
}
.testTable .title{
    background-color:#E5ECF9;
}
.testTable .data{
    height:30px;
}
.testTable .name{
    width:100px;
}
.testTable .price{
    width:80px;
}
.testTable .updown{
    width:150px;
}
?

?

?

?

?

?

?

?

1 楼 edokeh 2009-05-25  
gwt官方博客里面最近有篇文章讲到自定义控件的最佳实践,它不建议继承gwt自带的UI类,而建议用聚合的方式来做
2 楼 duker 2009-05-29  
哦, 给个链接,看看..
  相关解决方案