I`m trying to add a event for left and right click on a MenuItem.
Left click goes to an URL, right - call a context menu with option to delete this item from list.
However, addEventHandler as implemented has no effect.
FileUtils.getFileContentsAsArrayList(FileUtils.getBookMarksFile());
for (int i = 0; i < FileUtils.getBookmarksContents().size(); i++) {
String item = FileUtils.getBookmarksContents().get(i);
MenuItem miNewItem = new MenuItem(item);
miNewItem.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
if (e.getButton() == MouseButton.PRIMARY)
{System.out.println("LEFT");}
else if (e.getButton() == MouseButton.SECONDARY)
{System.out.println("RIGTH");}
}
});
In a final code it should work as
miNewItem.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
#Override public void handle(MouseEvent e) {
if (e.getButton() == MouseButton.PRIMARY)
{MyJavaFXBrowser.getWebEngine().load(miNewItem.getText());}
else if (e.getButton() == MouseButton.SECONDARY)
{removeBookmark().show(miNewItem, e.getScreenX(), e.getScreenY());}
}
});
But it gives an error -
The method show(Node, double, double) in the type ContextMenu is not applicable for the arguments (MenuItem, double, double)
Thanks
Can be solved by using CustomMenuItem insted of MenuItem.
and
CustomMenuItem cmi = new CustomMenuItem();
cmi.getContent().setOnMouseClicked(new EventHandler<MouseEvent>()...
Related
In a Xamarin.Forms and Xamarin.Android project I create a Custom Render and Adapter for a ListView.
The adapter implements BaseAdapter and ISectionIndexer. The custom render of this control is using FastScroll feature, in Android when you tap this scroll a bubble with a index letter appears. This works fine, but my idea is to have a way to catch the selected index after releasing scroll and that scroll "bubble" disappears.
I thought with the following class (in the GetSectionForPosition method) could achieve that:
public class ListViewconIndexAdapter : BaseAdapter<string>, ISectionIndexer
{
string[] items;
Activity context;
string[] sections;
Java.Lang.Object[] sectionsObjects;
Dictionary<string, int> alphaIndex;
public ListViewconIndexAdapter(Activity context, string[] items) : base()
{
this.context = context;
this.items = items;
alphaIndex = new Dictionary<string, int>();
for (int i = 0; i < items.Length; i++)
{
var key = items[i][0].ToString();
if (!alphaIndex.ContainsKey(key))
alphaIndex.Add(key, i);
}
sections = new string[alphaIndex.Keys.Count];
alphaIndex.Keys.CopyTo(sections, 0);
sectionsObjects = new Java.Lang.Object[sections.Length];
for (int i = 0; i < sections.Length; i++)
{
sectionsObjects[i] = new Java.Lang.String(sections[i]);
}
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public override long GetItemId(int position)
{
return position;
}
public override string this[int position]
{
get { return items[position]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView;
if (view == null)
view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);
view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = items[position];
return view;
}
//Fill in cound here, currently 0
public override int Count
{
get { return items.Length; }
}
// -- ISectionIndexer --
public int GetPositionForSection(int section)
{
return alphaIndex[sections[section]];
}
public int GetSectionForPosition(int position)
{ // this method isn't called in this example, but code is provided for completeness
int prevSection = 0;
for (int i = 0; i < sections.Length; i++)
{
if (GetPositionForSection(i) > position)
{
break;
}
prevSection = i;
}
Console.WriteLine(prevSection);
Console.WriteLine(sections[prevSection]);
//Toast.MakeText(context, sections[prevSection], ToastLength.Short).Show();
Xamarin.Forms.MessagingCenter.Send<object,string>(this, "CambioSeccion", sections[prevSection]);
return prevSection;
}
}
I put those Console.writeline for checking the index letter and that Message send is a way to send it back to PCL/NET Standard code (to show an DisplayAlert or something).
But the problem is that method firing is not consistent, for example, sometimes you fast scroll down to 'C' but Console doesn't print anything after releasing it there, but after touching it again where you leave it, it fires up. But sometimes it works like i want, it prints after release the scroll at selected index.
ListView has two different scroll listeners, AbsListView.IOnScrollListener and AbsListView.IOnScrollChangeListener (this one was added in API 23) and a touch listener (AbsListView.IOnTouchListener)
I think based upon your use-case, you are looking for the OnScrollStateChanged and when it goes into idle state and you are not touching the listview, do something (or vice versa).
Example (adjust to your needs of course):
public class MyScrollListener : Java.Lang.Object, AbsListView.IOnTouchListener, AbsListView.IOnScrollListener, AbsListView.IOnScrollChangeListener //(API23)
{
bool touching;
bool scrolling;
public void OnScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
{
}
public void OnScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)
{
}
public void OnScrollStateChanged(AbsListView view, [GeneratedEnum] ScrollState scrollState)
{
switch(scrollState)
{
case ScrollState.Idle:
if (!touching)
{
scrolling = false;
GetSelection();
}
break;
default:
scrolling = true;
break;
}
}
public bool OnTouch(View v, MotionEvent e)
{
switch (e.Action)
{
case MotionEventActions.Up:
touching = false;
if (!scrolling)
GetSelection();
break;
default:
touching = true;
break;
}
return true;
}
void GetSelection()
{
// touch and srolling is done, do something
}
}
Usage:
var scrollListener = new MyScrollListener();
listView.SetOnTouchListener(scrollListener);
listView.SetOnScrollListener(scrollListener);
listView.SetOnScrollChangeListener(scrollListener); // API23
I' have some navigation page and I want to override the color for the back button and my next button ( ToolbarItem )
I Already tried BarTextColor property but it change color for all navigation header text.
It's done in IOS, but I' not able to find a solution for android.
It works perfectly for the title but not for the Icons.
Here my code :
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var page = this.Element as NavigationPage;
if (page != null && toolbar != null)
{
toolbar.SetTitleTextColor(Color.Black.ToAndroid());
if (toolbar.NavigationIcon != null)
toolbar.NavigationIcon.SetColorFilter(Color.Green.ToAndroid(), Android.Graphics.PorterDuff.Mode.Multiply);
if (toolbar.OverflowIcon != null)
toolbar.OverflowIcon.SetColorFilter(Color.Green.ToAndroid(), Android.Graphics.PorterDuff.Mode.Multiply);
}
}
I' have some navigation page and I want to override the color for the back button and my next button ( ToolbarItem )
Your next button is a ToolbarItem, which is defined by yourself. So it won't be a problem for you to customize it. The difficult part lies in the back button, because it is offered by Xamarin.Forms. You need to override the NavigationPageRenderer to change the color:
public class MyNavigationPageRenderer : NavigationPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var navController = (INavigationPageController)e.NewElement;
navController.PushRequested += NavController_PushRequested;
navController.PopRequested += NavController_PopRequested;
}
}
private void NavController_PopRequested(object sender, Xamarin.Forms.Internals.NavigationRequestedEventArgs e)
{
Device.StartTimer(TimeSpan.FromMilliseconds(220), () =>
{
ChangeIconColor();
return false;
});
}
private void NavController_PushRequested(object sender, Xamarin.Forms.Internals.NavigationRequestedEventArgs e)
{
ChangeIconColor();
}
private void ChangeIconColor()
{
int count = this.ViewGroup.ChildCount;
var toolbar = GetToolbar();
if (toolbar.NavigationIcon != null)
{
var drawable = (toolbar.NavigationIcon as DrawerArrowDrawable);
drawable.Color = Resource.Color.material_grey_850;//set the navigation icon color here
}
}
private AToolbar GetToolbar()
{
for (int i = 0; i < this.ViewGroup.ChildCount; i++)
{
var child = this.ViewGroup.GetChildAt(i);
if (child is AToolbar)
{
return (AToolbar)child;
}
}
return null;
}
}
A little explanation to the codes above: PushRequest and PopRequest fires when you push and pop a new page to the navigation page and it is the perfect time for you to customize the existing Toolbar's NavigationIcon. So first find the Toolbar using GetToolbar then change the icon color by ChangeIconColor.
I would like to be able to use a modal window to present the contents of a column to the user for editing. I am not able to make this work, and I am not sure where I am going wrong.
I have provided a button in the table which will indicate if there are additional details (in this case comments). When the user selects the button, I want to open a modal dialog to enter the data and when it closes, update the field.
I have gotten the majority of this wired up, but the data is not making it back to my model. I have tried several things, and all without results. It appears that the commit edit call I am making is not seeing the field as in "edit mode" and just skips.
This is my code for my custom table cell:
public class CommentTableCell<T> extends TableCell<T, String> {
private Button actionBtn;
private TextArea textArea;
public CommentTableCell(TableColumn<T, String> column) {
super();
actionBtn = new Button("my action");
actionBtn.setTooltip(new Tooltip("Select to add/edit comments..."));
actionBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
startEdit();
System.out.println("Action: "+getItem());
Stage commentStage = new Stage();
AnchorPane ap = new AnchorPane();
textArea = new TextArea();
AnchorPane.setTopAnchor(textArea, 5.0);
AnchorPane.setBottomAnchor(textArea, 5.0);
AnchorPane.setLeftAnchor(textArea, 5.0);
AnchorPane.setRightAnchor(textArea, 5.0);
ap.getChildren().add(textArea);
Scene commentScene = new Scene (ap, 200, 200);
commentStage.setScene(commentScene);
commentStage.show();
commentStage.setOnCloseRequest(a -> {
commitEdit(textArea.getText());
});
// I have tried with an column.setOnEditCommit() as well as what is noted below which I found here, passing in the column.
final TableView<T> tableView = getTableView();
tableView.getSelectionModel().select(getTableRow().getIndex());
tableView.edit(tableView.getSelectionModel().getSelectedIndex(), column);
}
});
setText(null);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
actionBtn.getStyleClass().clear();
setEditable(false);
if (item != null && item.length() > 0) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_EDIT_COMMNET);
setGraphic(actionBtn);
} else if (!empty) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_ADD_COMMNET);
setGraphic(actionBtn);
} else {
setGraphic(null);
}
}
}
During the execution it hits the commitEdit() call and the following has isEditing in the TableCell as null:
#Override public void commitEdit(T newValue) {
if (! isEditing()) return;
My table looks basically like this:
TableView<SomeDTO> addressTableView = new TableView()
addressTableView.setItems(sortedItems);
addressTableView.setEditable(true);
commentsColumn.setCellValueFactory(cellValue -> cellValue.getValue().commentsProperty());
commentsColumn.setCellFactory(tc -> new CommentTableCell<SomeDTO>(commentsColumn));
I have found a solution to my issue - though I am not sure it is the best way or not.
I have changed my CommentTableCell as follows and it seems to work like a charm..
public class CommentTableCell<T> extends TableCell<T, String> {
private Button actionBtn;
public CommentTableCell() {
super();
actionBtn = new Button("my action");
actionBtn.setTooltip(new Tooltip("Select to add/edit comments..."));
actionBtn.setOnAction(event ->
{
Stage commentStage = new Stage();
AnchorPane ap = new AnchorPane();
TextArea textArea = new TextArea();
AnchorPane.setTopAnchor(textArea, 5.0);
AnchorPane.setBottomAnchor(textArea, 5.0);
AnchorPane.setLeftAnchor(textArea, 5.0);
AnchorPane.setRightAnchor(textArea, 5.0);
ap.getChildren().add(textArea);
Scene commentScene = new Scene (ap, 200, 200);
commentStage.setScene(commentScene);
if(getItem() != null) {
String myValue = getItem();
textArea.setText(myValue);
textArea.selectAll();
}
commentStage.show();
commentStage.setOnCloseRequest(a -> {
commitEdit(textArea.getText());
});
});
}
#Override
#SuppressWarnings({"unchecked", "rawtypes"})
public void commitEdit(String item) {
if (isEditing()) {
super.commitEdit(item);
} else {
final TableView table = getTableView();
if (table != null) {
TablePosition position = new TablePosition(getTableView(),
getTableRow().getIndex(), getTableColumn());
CellEditEvent editEvent = new CellEditEvent(table, position,
TableColumn.editCommitEvent(), item);
Event.fireEvent(getTableColumn(), editEvent);
}
updateItem(item, false);
if (table != null) {
table.edit(-1, null);
}
}
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
actionBtn.getStyleClass().clear();
setEditable(false);
if (item != null && item.length() > 0) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_EDIT_COMMNET);
setGraphic(actionBtn);
} else if (!empty) {
actionBtn.getStyleClass().add(CSSConstants.GRID_BUTTON_ADD_COMMNET);
setGraphic(actionBtn);
} else {
setGraphic(null);
}
}
}
I have programmed an Android App with fragments. A ListView fragment and a detail fragment.
What I wanna do is, if someone clicks inside the detail activity, a layout which is "View.Gone" should be "View.Visible". The code works without errors but nothing changed on the screen.
You can see it in Detail fragment code where a clik event on the ImageButton btn is.
What do i wrong?
What is the best way to update the detail screen? If someone has a small example or could write me where in my code I have to change what, it makes me happy :-)
Thanks a lot
Tom
The FragmentActivity:
public class CacheFragment extends SherlockFragmentActivity {
CacheListFragment f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_cachelist);
f = new CacheListFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
f.setArguments(args);
}
Here's the Detail Fragment, where you can see whatt should happen if someone clicks on the Imagebutton:
public class CacheDetailsFragment extends SherlockFragment implements OnClickListener {
private CacheDetailsLoading cdLoad= new CacheDetailsLoading();
private static GeocacheDetails _cacheDetails = new GeocacheDetails();
private static GCRatingTyp _cacheVote = new GCRatingTyp();
private CacheDetailsUsing cdUsing = new CacheDetailsUsing();
private Activity _context;
private static CacheDetailsFragment f;
private View view;
/**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
public static CacheDetailsFragment newInstance(int index ) {
f = new CacheDetailsFragment();
// Supply index input as an argument.
Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args);
return f;
}
public int getShownIndex() {
return getArguments().getInt("index", 0);
}
public void setCacheDetail(GeocacheDetails cacheDetails)
{
_cacheDetails = cacheDetails;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
return null;
}
Bundle bundle=getArguments();
_cacheVote= bundle.getParcelable("cacheVote");
int index = bundle.getInt("index");
_cacheDetails=StaticCacheListByGroup.getCacheList().get(index);
_context = getActivity();
_context.setTheme(R.style.Theme_Sherlock_Light_DarkActionBar);
view = inflater.inflate(R.layout.list_cachedetails, container,false);
((RelativeLayout) view.findViewById(R.id.relativeLoggingInfo)).setVisibility(View.GONE);
((RelativeLayout) view.findViewById(R.id.relativeKategorienInfo)).setVisibility(View.GONE);
ImageButton btn = (ImageButton) view.findViewById(R.id.description_expand);
btn.setOnClickListener(new OnClickListener() {
public void onClick(View v)
{
if(((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).getVisibility() == View.GONE)
{
((ImageButton) getActivity().findViewById(R.id.description_expand)).setBackgroundResource(R.drawable.navigation_collapse_dark);
((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).setVisibility(View.VISIBLE);
}
else
{
((ImageButton) getActivity().findViewById(R.id.description_expand)).setBackgroundResource(R.drawable.navigation_expand_dark);
((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).setVisibility(View.GONE);
}
});
return view;
}
}
Now the Listfragment:
public class CacheListFragment extends SherlockListFragment {
boolean isDualPane;
int mCurCheckPosition = 0;
private CacheListArrayAdapter _adapter;
private SharedPrefs _sp= new SharedPrefs();
private double latitude=0;
private double longitude=0;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
latitude =Double.parseDouble(_sp.getSharedPrefs(getActivity(), LibraryDefaults.PROGRAMMNAME, "Latitude", "0"));
longitude =Double.parseDouble(_sp.getSharedPrefs(getActivity(), LibraryDefaults.PROGRAMMNAME, "Longitude", "0"));
// Check to see if we have a frame in which to embed the details
// fragment directly in the containing UI.
View detailsFrame = getActivity().findViewById(R.id.details);
isDualPane = detailsFrame != null && detailsFrame.getVisibility() == View.VISIBLE;
if(!isDualPane)
{
Bundle bundle = getActivity().getIntent().getExtras();
if(bundle != null && bundle.containsKey("Titel"))
((TextView) getActivity().findViewById(R.id.listtitle)).setText(bundle.getString("Titel"));
else
((TextView) getActivity().findViewById(R.id.listtitle)).setText(this.getResources().getString(R.string.caches_listtitle));
}
if (StaticCacheListByGroup.getCacheList() != null)
{
GeocachingCompass gc = new GeocachingCompass(getActivity());
_adapter = new CacheListArrayAdapter(getActivity(), StaticCacheListByGroup.getCacheList(), longitude,latitude);
_adapter.setActualCoordinates(new LatLng(latitude,longitude));
_adapter.setActualHeading(gc.getBearing(latitude,longitude));
if (_adapter != null)
setListAdapter(_adapter);
if (savedInstanceState != null) {
// Restore last state for checked position.
mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
}
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
getListView().setSoundEffectsEnabled(true);
getListView().setSmoothScrollbarEnabled(true);
getListView().setDrawSelectorOnTop(false);
getListView().setCacheColorHint(R.color.transparentBlack);
getListView().setDivider(getResources().getDrawable( R.color.divider));
getListView().setDividerHeight(5);
if (isDualPane) {
// In dual-pane mode, the list view highlights the selected item.
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
showDetails(mCurCheckPosition);
}
}
}
#Override
public void onResume() {
super.onResume();
GeocachingCompass gc = new GeocachingCompass(getActivity());
_adapter = new CacheListArrayAdapter(getActivity(), StaticCacheListByGroup.getCacheList(), longitude,latitude);
_adapter.setActualCoordinates(new LatLng(latitude,longitude));
_adapter.setActualHeading(gc.getBearing(latitude,longitude));
if (_adapter != null)
setListAdapter(_adapter);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("curChoice", mCurCheckPosition);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
showDetails(position);
}
/**
* Helper function to show the details of a selected item, either by
* displaying a fragment in-place in the current UI, or starting a
* whole new activity in which it is displayed.
*/
void showDetails(int index) {
mCurCheckPosition = index;
ReadGCVote getVote = new ReadGCVote();
GeocacheDetails cacheDetails = new GeocacheDetails();
cacheDetails=StaticCacheListByGroup.getCacheList().get(index);
if (isDualPane) {
// We can display everything in-place with fragments, so update
// the list to highlight the selected item and show the data.
getListView().setItemChecked(index, true);
// Check what fragment is currently shown, replace if needed.
CacheDetailsFragment details = (CacheDetailsFragment)
getActivity().getSupportFragmentManager().findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
// Make new fragment to show this selection.
details = CacheDetailsFragment.newInstance(index);
// Execute a transaction, replacing any existing fragment
// with this one inside the frame.
FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
} else {
// Otherwise we need to launch a new activity to display
Intent intent = new Intent();
intent.setClass(getActivity(), CacheDetailsActivity.class);
intent.putExtra("index", index);
intent.putExtra("cacheDetails",cacheDetails);
intent.putExtra("cacheVote",getVote.getGCVoteByCacheGuid( StaticGCVoteList.getCacheList(), cacheDetails.GetGUID()));
startActivity(intent);
}
}
}
I found the bug :-)
In the code snippet of the Detail Fragment ...
public void onClick(View v)
{
if(((RelativeLayout) getActivity().findViewById(R.id.relativeDescriptionInfo)).getVisibility() == View.GONE)
}
...you shouldn't use "getActivity()" use "view" from "view = inflater.inflate(R.layout.list_cachedetails, container,false);"
Then it will work
I am unable to figure out how could I add a double click event to the cell of the CellTable.
Is it possible with GWT CellTable or not?
Is there any workaround
thank you..
al
BTW, i saw this post but there is no reply...
http://www.devcomments.com/Adding-DoubleClicks-and-OnContextMenu-to-CellTable-at1066168.htm
I crafted something different that just fit my needs:
cellTable.addCellPreviewHandler(new Handler<TitoloProxy>() {
long lastClick=-1000;
#Override
public void onCellPreview(CellPreviewEvent<TitoloProxy> event) {
long clictAt = System.currentTimeMillis();
GWT.log("clickAt: "+(clictAt));
GWT.log("lastClick: "+(lastClick));
if(event.getNativeEvent().getType().contains("click")){
GWT.log(""+(clictAt-lastClick));
if(clictAt-lastClick < 300) { // dblclick on 2 clicks detected within 300 ms
Window.alert("I am a double click crafted event!");
}
lastClick = System.currentTimeMillis();
}
}
});
cellTable.addDomHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(DoubleClickEvent event) {
Window.alert("That's it!");
}
}, DoubleClickEvent.getType());
Integer row=0;// to hold row index
Integer column=0;// to hold column index
_Grid.addCellPreviewHandler(new CellPreviewEvent.Handler<Model>() {
// this is to handle row id
#Override
public void onCellPreview(final CellPreviewEvent<Model> event) {
if (BrowserEvents.CLICK.equalsIgnoreCase(event.getNativeEvent().getType())) {
row = event.getIndex();
column=event.getColumn();
}
}
});
// because Doubleclick handler doesn't give row index or column index we will use addCellPreviewHandler to return row index or column index.
_Grid.addDomHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(final DoubleClickEvent event) {
System.out.println(" You clicked row = " + row);
System.out.println(" You clicked column = " + column);
}
}, DoubleClickEvent.getType());
For cell lists, this code works ok:
cellList.addDomHandler(new DoubleClickHandler() {
#Override
public void onDoubleClick(DoubleClickEvent event) {
// do the stuff
}
}, DoubleClickEvent.getType());
I'm not sure about table cells
Because the CellPreview interface does not natively capture double click events you will need add event logic into the Overriden onCellPreview method. First you would think the best way would be to check the click time differences. However it is much more efficient and elegant to use a state machine and count clicks. This is more robust and allows you to deal with multiple event cases - Such as mouse hover, single, and double clicks. The code is pretty straightforward. So enjoy!
public class CellHoverHandler implements Handler<T> {
Timer singleClickTimer;
int clickCount = 0;
int clickDelay = 300;
#Override
public void onCellPreview(final CellPreviewEvent<T> event) {
if (Event.getTypeInt(event.getNativeEvent().getType()) == Event.ONMOUSEOVER) {
handleOnMouseOver(event);
} else if (Event.getTypeInt(event.getNativeEvent().getType()) == Event.ONCLICK) {
clickCount++;
if (clickCount == 1) {
singleClickTimer = new Timer() {
#Override
public void run() {
clickCount = 0;
handleOnClick(event);
}
};
singleClickTimer.schedule(clickDelay);
} else if (clickCount == 2) {
singleClickTimer.cancel();
clickCount = 0;
handleOnDblClick(event);
}
}
}
private void handleOnMouseOver(CellPreviewEvent<T> event) {
Element cell = event.getNativeEvent().getEventTarget().cast();
GWT.log("mouse over event");
}
private void handleOnClick(CellPreviewEvent<T> event) {
Element cell = event.getNativeEvent().getEventTarget().cast();
GWT.log("click event");
}
private void handleOnDblClick(CellPreviewEvent<T> event) {
Element cell = event.getNativeEvent().getEventTarget().cast();
GWT.log("double click event");
}
OPTIMIZATION: feel free to stick the count, timer, and delay as static class members or global members to reuse. Also check to see if the timer is null before making a new instance. I had omitted this for simplicity. Unlike a lot of other techniques this way still provides you with easy and direct access to the cell event. The technique with overloading the AbstractCell works well too, however sometimes you really don't have custom cells or want to make a custom cell to just handle events on the cell.
Leaving this here for future reference
private Set<GenericEventHandler<T>> dblClickHandlers = new HashSet<>(4);
dblClickHandlers simply maps interface implementations of my choice
table.addCellPreviewHandler(event -> {
if (BrowserEvents.DBLCLICK.equalsIgnoreCase(event.getNativeEvent().getType())) {
LOGGER.info("dblclick (native) " + event.getIndex() + " " + event.getColumn() + "; " + event.getValue());
dblClickHandlers.forEach(handler -> {
handler.onEvent(event.getValue());
});
}
});
table.sinkBitlessEvent(BrowserEvents.DBLCLICK);
The trick is to sink the 'dblclick' event.
If you wanted a text cell that allows you to support your own chosen list of events, you can use this:
public class EventfulTextCell extends AbstractSafeHtmlCell`<String`> {
private static final String[] NO_CONSUMED_EVENTS = null;
public EventfulTextCell() {
this(NO_CONSUMED_EVENTS);
}
public EventfulTextCell(String... consumedEvents) {
super(SimpleSafeHtmlRenderer.getInstance(), consumedEvents);
}
#Override
public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
if (value != null) {
sb.append(value);
}
}
}
Then you instantiate it:
new EventfulTextCell("click", "dblclick")
Then override the onBrowserEvent() method to process your events.