Google

Saturday, December 9, 2006

GWT sample code... customizing widgets...

Here is an example, A flexTable or a Grid which now includes double clicks, mulitple select and right click events...

There are four classes, for FlexTable, Grid, TableListener collection, and Table listener interface...
We need to extend all this classes and overridde some methods...

Here's what i've come up so far...

GridWithDoubleClick.java

import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.SourcesTableEvents;
import com.google.gwt.user.client.ui.MouseListener;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Window;

import java.util.ArrayList;

public class GridWithDoubleClick extends Grid {
private TableListenerCollectionWithDoubleClick tableListeners;
private boolean isShiftKeyDown = false;
private ArrayList selectedRows = new ArrayList();

public GridWithDoubleClick() {
super();
disableContextMenu(getElement());
setselectedhighlight(getElement());
sinkEvents(Event.ONMOUSEUP| Event.ONDBLCLICK | Event.BUTTON_RIGHT | Event.ONKEYDOWN | Event.ONKEYUP );
}

public void onBrowserEvent(Event event) {
// Find out which cell was actually clicked.
Element td = getEventTargetCell(event);
if (td == null) {
return;
}
Element tr = DOM.getParent(td);
Element body = DOM.getParent(tr);
int row = DOM.getChildIndex(body, tr);
int column = DOM.getChildIndex(tr, td);
switch (DOM.eventGetType(event)) {
case Event.ONMOUSEUP: {
switch(DOM.eventGetButton(event)){
case Event.BUTTON_LEFT:
if (this.tableListeners != null)
{
// Fire the event.
if (DOM.eventGetShiftKey(event))
{
selectedRows.add(new String().valueOf(row));
tableListeners.fireMultipleCellClicked(this, row, column);
}
else
{
tableListeners.fireCellClicked(this, row, column);
selectedRows = null;
selectedRows = new ArrayList();
}
}

break;

case Event.BUTTON_RIGHT:
if (this.tableListeners != null)
{
// Fire the event.
tableListeners.fireRightClicked(this, row, column, DOM.eventGetClientX(event), DOM.eventGetClientY(event));
//tableListeners.fireRightClicked(this, row, column);
}
break;
default:{
//do nothing
}
break;
}
break;
}
case Event.ONDBLCLICK: {
if (this.tableListeners != null && !DOM.eventGetShiftKey(event)) {
// Fire the event.
tableListeners.fireCellDblClicked(this, row, column);

}
break;
}

default: {
// Do nothing
}
break;
}
}

public ArrayList getSelectedRows()
{
return selectedRows;
}

//overide this methods pra maka fire sa atong ghimo na interface ug listener collections
public void addTableListener(TableListenerWithDoubleClick listener) {
if (tableListeners == null) {
tableListeners = new TableListenerCollectionWithDoubleClick();
}
tableListeners.add(listener);
}
public void removeTableListener(TableListenerWithDoubleClick listener)
{
if (tableListeners != null)
{
tableListeners.remove(listener);
}
}

private native void disableContextMenu(Element elem) /*-{
elem.oncontextmenu=function(a,b) {return false};
}-*/;

private native void setselectedhighlight(Element elem ) /*-{
elem.onselectstart=function(a,b) {return false};


}-*/;
}


Do the same for flexTable... you can also sink other events that you like and just add the condition in the switch...

In the code, we override the onbrowser event and sink the events needed.

TableListenerCollectionWithDoubleClick.java


import com.google.gwt.user.client.ui.SourcesTableEvents;
import java.util.Vector;
import java.util.Iterator;

public class TableListenerCollectionWithDoubleClick extends Vector {

public void fireCellClicked(SourcesTableEvents sender, int row, int cell) {
for (Iterator it = iterator(); it.hasNext();) {
TableListenerWithDoubleClick listener = (TableListenerWithDoubleClick) it.next();
listener.onCellClicked(sender, row, cell);
}
}

public void fireCellDblClicked(SourcesTableEvents sender, int row, int cell) {
for (Iterator it = iterator(); it.hasNext();) {
TableListenerWithDoubleClick listener = (TableListenerWithDoubleClick) it.next();
listener.onCellDblClicked(sender, row, cell);
}
}

public void fireMultipleCellClicked(SourcesTableEvents sender, int row, int cell) {
for (Iterator it = iterator(); it.hasNext();) {
TableListenerWithDoubleClick listener = (TableListenerWithDoubleClick) it.next();
listener.onMultipleCellClicked(sender, row, cell);
}
}
public void fireRightClicked(SourcesTableEvents sender, int row, int cell, int mouseX, int mouseY) {
for (Iterator it = iterator(); it.hasNext();) {
TableListenerWithDoubleClick listener = (TableListenerWithDoubleClick) it.next();
listener.onCellRightClicked(sender, row, cell, mouseX, mouseY);
}
}/*
public void fireRightClicked(SourcesTableEvents sender, int row, int cell) {
for (Iterator it = iterator(); it.hasNext();) {
TableListenerWithDoubleClick listener = (TableListenerWithDoubleClick) it.next();
listener.onCellRightClicked(sender, row, cell);
}
}*/
}


As you can see above, i've added fireRightClicked and . These are the methods that fire the onCellRightClicked and onMultipleCellClicked in the new TableListenerWithDoubleClick interface.

Here's the code for TableListenerWithDoubleClick interface

TableListenerWithDoubleClick.java

import com.google.gwt.user.client.ui.TableListener;
import com.google.gwt.user.client.ui.SourcesTableEvents;

public interface TableListenerWithDoubleClick extends TableListener{

public void onCellClicked(SourcesTableEvents sender, int row, int cell);
public void onCellDblClicked(SourcesTableEvents sender, int row, int cell);
public void onMultipleCellClicked(SourcesTableEvents sender, int row, int cell);
public void onCellRightClicked(SourcesTableEvents sender, int row, int cell, int mouseX, int mouseY);
//public void onCellRightClicked(SourcesTableEvents sender, int row, int cell);
}

These works the same way as the currently included implementation...
Just include all the include all the files in you class (you can name them to anything you want).
Sample:

import MyPackage.GridWithDoubleClick
import MyPackage.FlexTableWithDoubleClick
import MyPackage.TableListenerWithDoubleClick

GridWithDoubleClick mygrid = new GridWithDoubleClick();

myGrid.addTableListener(new TableListenerWithDoubleClick()
{
//implement all the methods in the tableListener with click methods...
});


this works with the latest version of GWT.



3 comments:

Unknown said...

How do I adapt this for the RootPanel, so I can listen to mouse events for the project as a whole... So far I've changed everything for TableListener to EventListener. I think that should be fine, but I'm not sure how to override the onBrowserEvent routine in the RootPanel, like you did for the GridWithDoubleClick class.

Thanx alot,
-- BSW

Vivien said...

If you're looking for a way to fire a click event on a widget, try this :

myElement.fireEvent(new ClickEvent(){});

I looked for a solution for an hour on google and found nothing. I think Eclipse hides the option of building an inner anonymous class since the clickEvent constructor is protected / private.

It works for me. I hope it will for you.

Unknown said...

Re: vivien

Thanks for the tip about how to use fireEvent... I used it exactly as you stated, and it works great!