GWT Timer cancel not working

2019-05-27 11:09发布

问题:

I am trying to write a code to differentiate between simgle and double clicks using GWT and GWTQuery. I got the idea here. So I translated it into GWT like this: (my app can't have global variables, so I am doing that part with element attributes instead):

$("img").live("click", new Function() {
         public boolean f(Event event) {
            String clicksString = $(event).attr("clicks");
            int clicks = Integer.parseInt(clicksString);
            clicks++;
            $(event).attr("clicks",String.valueOf(clicks));
            Timer t = new Timer() {

                @Override
                public void run() {
                    Window.alert("Click");
                    $(event).attr("clicks","0");
                }
            };

            if (clicks == 1) {
              t.schedule(200);
            }

            else {
              t.cancel();
              $(event).attr("clicks","0");
              Window.alert("Double Click");
            }
            return true;
          }
});

Here, when the image is clicked, an alert should pop up showing Single Click, and if the user double clicks (within 200 ms), it should pop up Double Click. It works fine for the single click, but on double click, even though the Double Click alert pops up, on clicking Ok to get rid of it, I find the Single Click alert waiting to be get rid of.

Somehow, I think the t.cancel() is not firing on double-click. Can anyone tell me how to fix this?

Update:

The accepted solution works fine for alerting, but when I need the event parameter as well, it has to be slightly tweaked. After doing that, again, the problem comes back, the timer is not cleared, and now I get two alerts, Double Click and Click..:

          $("img").live("click", new Function() {
              int clicks = 0;

            public boolean f(Event event) {

                  Timer t = new Timer() {

                    @Override
                    public void run() {
                        clicks = 0;
//                            Here I need the event paramater

                    }
                };
                if (clicks++%2 == 0) {
                    t.schedule(5000);
                }
                else {
                    t.cancel();
                    clicks = 0;
 //                       Here also I need the event paramater
                }
                return true;
            }
          });

Updated by @Manolo: Based on my comment below last code should be:

      $("img").live("click", new Function() {
        int clicks = 0;
        Event event;
        Timer t = new Timer() {
           @Override
            public void run() {
               // Use the event
               event....
            }
        };
       public boolean f(Event event) {
            this.event = event;
            if (clicks++%2 == 0) {
                t.schedule(5000);
            } else {
                t.cancel();
                // Use the event
                event....
            }
            return true;
        }
      });

回答1:

The following code does exactly the same than in the jsfiddle example you say:

  $("img").click(new Function() {
    boolean b = false;
    Timer t = new Timer() {
      public void run() {
        Window.alert("Click");
      }
    };
    public void f() {
      if (b = !b) {
        t.schedule(200);
      } else  {
        t.cancel();
        Window.alert("Double Click");
      }
     }
  });

The prevent default fragment is not necessary unless you previously were sunk events to the element, but in the case, the code should be:

  $("img").dblclick(new Function() {
    public boolean f(Event e) {
      return false;
    }
  });

EDITED: If you want to have unique variables per matched element, the best way is to create as many functions as elements. Using GQuery.each() is the easier way:

  $("img").each(new Function() {
    public void f() {
      $(this).click(new Function() {
        boolean b = false;
        Timer t = new Timer() {
          public void run() {
            Window.alert("Click");
          }
        };
        public void f() {
          if (b = !b) {
            t.schedule(200);
          } else  {
            t.cancel();
            Window.alert("Double Click");
          }
         }
      });
  }});

You could even use only one function and store variables in the element, but you should store not only the counter like you pretend in your query but a timer per element as well:

  $("img").click(new Function() {
    public void f() {
      boolean b = $(this).prop("c", Boolean.class);
      Timer t = $(this).prop("f");
      if (t == null) {
        t = new Timer() {
          public void run() {
            Window.alert("Click");
          }
        };
        $(this).prop("f", t);
      }
      if (b = !b) {
        t.schedule(200);
      } else  {
        t.cancel();
        Window.alert("Double Click");
      }
      $(this).prop("c", b);
     }
  });


回答2:

Do you feel GWT's DoubleClickEvent is insufficient. Why not listen to Double Click event from Dom instead of Click Event even if you take GwtQuery? Using timer is horribly bad approach for distinguishing Double Clicks.

In plain GWT Double Click would be -

public void onModuleLoad() {
    final Image button = new Image("http://upload.wikimedia.org/wikipedia/commons/thumb/7/7b/Katrina_Kaif.jpg/220px-Katrina_Kaif.jpg");

    button.addDoubleClickHandler( new DoubleClickHandler() {
        @Override
        public void onDoubleClick(DoubleClickEvent event) {
            Window.alert("DoubleClick");
        }
    });
    button.addClickHandler(new ClickHandler() {
        @Override
        public void onClick(ClickEvent event) {
            Window.alert("Click");
        }
    });
    RootPanel.get("slot1").add(button);
}

In GwtQuery you might try using 'dblclick'

$("img").live("dblclick", new Function() {
// Your code....
}

Update

You might have to borrow solution from Jquery community.This seems to be a travelled ground by jquery community here @ Jquery bind double click and single click separately

Quote from .dblclick() at the jQuery site

It is inadvisable to bind handlers to both the click and dblclick events for the same element. The sequence of events triggered varies from browser to browser, with some receiving two click events before the dblclick and others only one. Double-click sensitivity (maximum time between clicks that is detected as a double click) can vary by operating system and browser, and is often user-configurable.