当用户将鼠标悬停在 TreeView 控件的特定 TreeNode 控件上时显示不同的光标

Posted

技术标签:

【中文标题】当用户将鼠标悬停在 TreeView 控件的特定 TreeNode 控件上时显示不同的光标【英文标题】:Displaying a different cursor when the user hovers the mouse over a particular TreeNode control of a TreeView control 【发布时间】:2020-06-04 14:51:11 【问题描述】:

当用户将指针悬停在具有特定命名父节点的节点上时,我需要表单的光标更改为光标Cursors.Hand

我在实现这一点时遇到的问题是,当用户将指针从关注的TreeNode 移开时,将光标更改回默认值。

我已经处理了TreeView 控件的NodeMouseHover 事件(如最后的sn-p 代码)以将指针更改为备用光标并在指针移动到另一个光标时返回默认光标节点,但这不处理当用户将指针从节点移到TreeView 控件的空白区域时的情况。

关于这个问题的解决方案,我最初的也是唯一的直觉是获取位置并计算 TreeNodes 的区域,这需要更改光标并检查指针是否仍在其中一个TreeView 控件的 MouseMove 事件的事件处理程序,但是,我相信这不是一个优雅的解决方案,因为有很多 TreeNodes 需要这种行为,这需要循环其中很多检查,这反过来可能会导致应用程序在极少数情况下有点无响应。

提前致谢。

PS 有问题的代码 sn-p:

this.treeView.NodeMouseHover += delegate (object sender, TreeNodeMouseHoverEventArgs e)

   bool isNewCursorAssigned = false;
   if (e.Node.Parent != null)
   
      if (e.Node.Parent.Text == "someTxt")
      
         this.Cursor = Cursors.Hand;
         isNewCursorAssigned = true;
      
   
   if (isNewCursorAssigned == false && this.Cursor != this.DefaultCursor)
      this.Cursor = this.DefaultCursor;
;

【问题讨论】:

【参考方案1】:

改为处理MouseMove,从当前鼠标位置获取Node,向后迭代以获取当前NodeParent(以及父级的父级,如果有),然后更改@ 987654325@相应:

private void treeView1_MouseMove(object sender, MouseEventArgs e)

    var node = treeView1.GetNodeAt(e.Location);

    if (node != null)
    
        var parent = node.Parent;

        while (parent != null)
        
            if (parent.Text == "someTxt")
            
                if (Cursor != Cursors.Hand)
                            Cursor = Cursors.Hand;
                        return;
            
            parent = parent.Parent;
        
        Cursor = Cursors.Default;
    

同时处理MouseLeave 事件以检查是否需要默认 Cursor

private void treeView1_MouseLeave(object sender, EventArgs e)

    if (Cursor != Cursors.Default)
        Cursor = Cursors.Default;

或者如果您更喜欢 Lambda 方式:

//In the constructor:

treeView1.MouseMove += (s, e) =>

    var node = treeView1.GetNodeAt(e.Location);

    if (node != null)
    
        var parent = node.Parent;
        while (parent != null)
        
            if (parent.Text == "someTxt")
            
                if (Cursor != Cursors.Hand)
                    Cursor = Cursors.Hand;
                return;
            
            parent = parent.Parent;
        
        Cursor = Cursors.Default;
    
;

treeView1.MouseLeave += (s, e) =>

    if (Cursor != Cursors.Default)
        Cursor = Cursors.Default;
;

【讨论】:

【参考方案2】:

我认为当光标横向移动到节点文本边界之外时,必须这样做以合并光标更改。

this.treeView.MouseMove += delegate (object sender, MouseEventArgs e)

     TreeNode concernedNode = this.treeViewOfAvailableMachines.GetNodeAt(e.Location);
     if (concernedNode != null)
        if (!(concernedNode.Parent != null && concernedNode.Parent.Text == "someTxt"))
               concernedNode = null;
     if (concernedNode != null)
     
          if ((e.Location.X >= concernedNode.Bounds.Location.X &&
                    e.Location.X <= concernedNode.Bounds.Location.X + concernedNode.Bounds.Width) &&
                    (e.Location.Y >= concernedNode.Bounds.Location.Y &&
                    e.Location.Y <= concernedNode.Bounds.Location.Y + concernedNode.Bounds.Height))
          
               this.Cursor = Cursors.Hand;
          
          else
          
               this.Cursor = this.DefaultCursor;
          
     
     else
     
          this.Cursor = this.DefaultCursor;
     
;

【讨论】:

我认为这个答案有两个缺陷:1. this.treeViewOfAvailableMachines 应该是 ((TreeView)sender)。当您拥有超过 1 个树视图时,可能会发生奇怪的事情。并且 2. MouseLeave 应该按照另一个答案中的描述来实现。

以上是关于当用户将鼠标悬停在 TreeView 控件的特定 TreeNode 控件上时显示不同的光标的主要内容,如果未能解决你的问题,请参考以下文章

仅当鼠标悬停在元素上至少特定时间时,如何触发 MouseMove 事件?

当鼠标悬停在 MFC C++ 中列表控件的列标题上时显示工具提示

隐藏视频控件,直到用户将鼠标悬停在视频上

在使用拖放时,我可以让 Treeview 展开用户悬停的节点吗?

当鼠标悬停在 DIV 上时,如何使某些控件可见并与 DIV 重叠? [关闭]

当鼠标悬停在控件的指定区域时如何更改鼠标光标?使用 c#