Tooltips for GWT tree: adding mouseovers to nodes

2019-04-11 01:38发布

问题:

I'm trying to add tooltips for the nodes of a Tree in GWT. As such, I'd like to add a mouseover listener for the nodes of a tree rather than on the tree itself.

The Treelistener interface seems to be what I want but this is now deprecated in lieu of the handler system. I don't quite understand how to get mouseover behaviour on the cell as I only seem to be able to add a MouseOverHandler to the tree itself.

Any help would be appreciated, thank you.

回答1:

A TreeItem can contains a Widget object. So add a MouseOverHandler and a MouseOutHandler on a widget (i.e. a Label) and put the widget inside the TreeItem to add :

Label myItemContent = new Label("My content");
myItemContent.addMouseOverHandler(new MouseOverHandler() {

  public void onMouseOver(MouseOverEvent event) {
    // construct and/or open your tooltip
  }
});

myItemContent.addMouseOutHandler(new MouseOutHandler() {

  public void onMouseOut(MouseOutEvent event) {
    // close your tooltip

  }
});
//put your Label inside a TreeItem
TreeItem myItem = new TreeItem(myItemContent);
// let's assume that parentNode is an ItemTree
parentNode.addItem(myItem);

An other solution can be to use GwtQuery. GwtQuery allows to bind event handler to any DOM element :

import static com.google.gwt.query.client.GQuery.$;

...

TreeItem myItem = new TreeItem("My content");
$(myItem.getElement()).hover(new Function() {

  //method called on mouse over
  public void f(Element e) {
      // construct and/or open your tooltip
  }

}, new Function() {

  //method called on mouse out
  public void f(Element e) {
      //close your tooltip
  }
});

parentNode.addItem(myItem);

Julien



回答2:

I'm going to stick my neck out a bit here since I haven't actually used a Tree in GWT yet, but I see that the TreeItem class is a subclass of UIObject. Any UIObject can have its setTitle() method called. Under the hood, this method sets the standard HTML title attribute to be whatever string you pass into setTitle().

This should give you the tooltip behavior you seek. As an added bonus, the browser does all of the mouse event handling for you:

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;

public class TreeTest extends Composite {

    public TreeTest() {
        Tree root = new Tree();
        initWidget(root);
        TreeItem dogs = new TreeItem("canines");
        dogs.addItem("Fido").setTitle("faithful");
        dogs.addItem("Lassie").setTitle("starlet");
        dogs.addItem("Touser").setTitle("ruthless killer");
        root.addItem(dogs);

        TreeItem cats = new TreeItem("felines");
        cats.addItem("Boots").setTitle("needy");
        cats.addItem("Fabio").setTitle("aloof");
        cats.addItem("Mandu").setTitle("bob seger");
        root.addItem(cats);
    }


}

Edit: Now let's imagine that you don't want to use the browser's built-in tool-tip mechanism described above, and that you would like to handle the mouse events yourself.

TreeItem might look, on the surface, as a non-starter. After all, it inherits directly from UIObject and not from Widget. (The key difference that a Widget adds to UIObject is, after all, the ability to handle events. So one would think that we cannot add handlers to the TreeItem!)

While this is strictly true, notice that TreeItem gives us the following constructor:

public TreeItem(Widget widget)

When we make each instance, then, we can pass a real Widget into it (such as a Label, perhaps, or maybe your own class MyWidget extends Composite) and we can add event handlers directly to that:

    import com.google.gwt.core.client.GWT;
    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.user.client.ui.Composite;
    import com.google.gwt.user.client.ui.Label;
    import com.google.gwt.user.client.ui.Tree;
    import com.google.gwt.user.client.ui.TreeItem;

    public class AnotherTreeTest extends Composite {

        public AnotherTreeTest() {
            Tree root = new Tree();
            initWidget(root);
            TreeItem dogs = new TreeItem("canines");
            makeItem(dogs,"Fido","faithful");
            makeItem(dogs,"Lassie","starlet");
            makeItem(dogs,"Touser","ruthless killer");
            root.addItem(dogs);

            TreeItem cats = new TreeItem("felines");
            makeItem(cats,"Boots","needy");
            makeItem(cats,"Fabio","aloof");
            makeItem(cats,"Mandu","bob seger");
            root.addItem(cats);
        }

        private void makeItem(TreeItem parent, String name, final String tip) {
            Label label = new Label(name);
            TreeItem animal = new TreeItem(label);
            label.addMouseOverHandler(new MouseOverHandler() {

                @Override
                public void onMouseOver(MouseOverEvent event) {
                    GWT.log("mouse over " + tip); // do something better here
                }

            });
            label.addMouseOutHandler(new MouseOutHandler() {

                @Override
                public void onMouseOut(MouseOutEvent event) {
                    GWT.log("mouse out " + tip); // do something better here
                }

            });
            parent.addItem(animal);
        }

}

Note that there may be other ways to accomplish this that are less expensive. If you have an enormous tree, then creating a Widget for each node can get expensive. Then you might want to explore a more sophisticated way of dealing with your mouse events, perhaps by having one handler that checks to see which element it is in.



回答3:

An alternative way that I settled upon is to make use of CSS.

/**
 * @return a label with a CSS controlled popup
 */
public static Widget labelWithHTMLPopup(String text, String description)
{
    FlowPanel p = new FlowPanel();
    p.addStyleName("tooltipLabel");
    p.add(new Label(text));

    HTML contents = new HTML(description);
    contents.setStyleName("tooltip");
    p.add(contents);

    return p;
}

With accompanying css:

/*************** Tooltip **************/

div.tooltip
{
    display: none;

    position: absolute; 
    border: 1px outset black;
    left: 90%;  
    top: -20px;

    background: white;
    padding: 5px;
    box-shadow: 3px 3px 2px 0px #555;       
    overflow-y: auto;
    max-height: 150px;
    font-size: 80%; 
    z-index: 99;
}

div.tooltipLabel
{
    position: relative;
}
div.tooltipLabel:hover div.tooltip
{
    display: block;
    position: absolute; 
}

Of course, you can change the style, add fades etc as you like.

Less javas/javascript and more css.