Search code examples
c#while-looptooltiptreenodemouse-position

C# Show TreeNode ToolTip as long as TreeNode is hovered


When a TreeNodein my TreeViewis hovered, a ToolTip is supposed to show. And when the mouse leave the TreeNode the ToolTip should dissapear. I tried doing this by getting the MousePosition of PontToClient() and Show() the ToolTip as long as the MousePosition did not change. It works but it doesn't look good. The ToolTip dissapear or doesn't show if the mouse is moved just the slightest.

This gave a somewhat working result

private void treeView_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
{
    ToolTip tip = new ToolTip();
    tip.ToolTipTitle = e.Node.Name;
    Point client = PointToClient(MousePosition);
    while (client == PointToClient(MousePosition))
    {
        tip.Show(e.Node.Nodes.Count.ToString(), this, PointToClient(MousePosition));
    }
    tip.Dispose();
}

Instead I'm trying to show the ToolTip as long as the TreeNode at the MousePosition is the same as the TreeNode that triggered the event. But now the ToolTip never shows?

private void treeView_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
{
    ToolTip tip = new ToolTip();
    tip.ToolTipTitle = e.Node.Name;
    while (e.Node == treeView.GetNodeAt(MousePosition))
    {
        tip.Show(e.Node.Nodes.Count.ToString(), this, PointToClient(MousePosition));
    }
    tip.Dispose();
}

UPDATE

I just realized that the this result in following exception?

treeView.GetNodeAt(MousePosition).Name

Object reference not set to an instance of an object


Solution

  • treeView.GetNodeAt(MousePosition) returns null, so you can not access property Name from it.

    MousePosition is position of mouse pointer on your screen, not on your control. So, lets assume your pointer in in the middle of screen, so coordinates would be like x: 1000, y: 500. But, GetNodeAt() expects coordinates in treeview, where, in example, first node is at x: 20 and Y: 50 coordinates.

    You have to transform those coordinates to be relative to your treeview, something like this:

    var point = treeView.PointToClient(MousePosition);
    var node = treeView.GetNodeAt(point);
    

    UPDATE: In your second example, correct use would be:

    private void treeView1_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
    {
        ToolTip tip = new ToolTip();
        tip.ToolTipTitle = e.Node.Name;
        while (e.Node == treeView.GetNodeAt(treeView.PointToClient(MousePosition)))
        {
            tip.Show(e.Node.Nodes.Count.ToString(), this, PointToClient(MousePosition));
        }
        tip.Dispose();
    }
    

    but, to simplify things (and avoid flickering, constant initialization of tooltip etc), I would move ToolTip declaration out of the method and put it into the form's scope, then show ToolTip on hover and hide it on mouse move. Like this:

    ToolTip tip = new ToolTip();
    
    private void treeView_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
    {
    
        tip.ToolTipTitle = e.Node.Name;
        tip.Show(e.Node.Nodes.Count.ToString(), this, PointToClient(MousePosition));
    
    }
    
    private void treeView_MouseMove(object sender, MouseEventArgs e)
    {
        if (treeView.GetNodeAt(treeView.PointToClient(MousePosition)) == null)
            tip.Hide(this);
    }