2010-06-09 111 views
8

只要鼠标悬停在特定控件上,我们就会显示某种形式。当鼠标离开控制器时,我们会在稍微超时后隐藏控制器。这是标准的悬停行为。.NET控件上的C#鼠标输入监听器滚动条

然而,当控制(例如树视图)有一个滚动条,并且鼠标上或通过滚动条,该事件不火......

如果我们能找到的一个参考滚动条控件,这将解决我们的问题,因为我们将相同的侦听器事件添加到滚动条。然而,据我所知滚动条不可访问...

我们该如何解决这个问题?

回答

3

滚动条在树视图中的非客户区。当鼠标移动到那里时,它开始生成非客户端消息,如WM_NCMOUSEMOVE和WM_NCMOUSELEAVE。您必须对TreeView进行子类别重写并覆盖WndProc()来检测这些消息。

虽然这并不能真正解决您的问题,但在边缘情况下您仍然很难。一个带有计时器的低技术的方法总是工作:

private Form frmPopup; 

    private void treeView1_MouseEnter(object sender, EventArgs e) { 
     timer1.Enabled = true; 
     if (frmPopup == null) { 
      frmPopup = new Form2(); 
      frmPopup.StartPosition = FormStartPosition.Manual; 
      frmPopup.Location = PointToScreen(new Point(treeView1.Right + 20, treeView1.Top)); 
      frmPopup.FormClosed += (o, ea) => frmPopup = null; 
      frmPopup.Show(); 
     } 
    } 

    private void timer1_Tick(object sender, EventArgs e) { 
     Rectangle rc = treeView1.RectangleToScreen(new Rectangle(0, 0, treeView1.Width, treeView1.Height)); 
     if (!rc.Contains(Control.MousePosition)) { 
      timer1.Enabled = false; 
      if (frmPopup != null) frmPopup.Close(); 
     } 
    } 
2

我认为有几种不同的方法可以做到这一点,但关键是您希望暂停操作。我认为两种技术的组合可能有效:

将控件放在面板上,停靠填充并使用面板的MouseEnter打开您的行为 - 这将包含控件的滚动条。您也可以使用面板的MouseLeave事件,但您必须检查光标的位置以确保它未移入包含的控件。此方法大多可靠,但快速移动鼠标可能会使其混淆。

如果将此功能与计时器结合起来,该计时器会在显示/隐藏控件显示时启动,并定期检查光标位置。这会起作用,但是在隐藏控件之前你的超时不一定是一致的(因为定时器在他们进入控件时开始)。您可以停止/启动控制器中的mousemove计时器,以稍微缓解这一点。

我放在一起的不同的方法我试过这里的项目:http://lovethedot.s3.amazonaws.com/100609StackoverflowScrollbarQuestion.zip

通过对接要在面板跟踪控制,它本质上包裹它,你会在的最边缘得到的MouseEnter跟踪控件:

private void panel1_MouseEnter(object sender, EventArgs e) 
    { 
     this.Text = "in"; 
    } 

    private void panel1_MouseLeave(object sender, EventArgs e) 
    { 
     if (!new Rectangle(new Point(0, 0), panel1.Size).Contains(panel1.PointToClient(Control.MousePosition))) 
      this.Text = "out"; 
    } 

您正在跟踪围绕控件的面板的入口,如果光标不在跟踪控件的内部,则退出该面板。

为了更好地“离开”的经验,它结合检查,看看光标所在以及定时器:

 private void listBox3_MouseEnter(object sender, EventArgs e) 
    { 
     button1.Visible = true; 
     visibleTimer.Stop(); 
     visibleTimer.Start(); 
    } 

    void visibleTimer_Tick(object sender, EventArgs e) 
    { 
     if (!new Rectangle(new Point(0, 0), listBox3.Size).Contains(listBox3.PointToClient(Control.MousePosition))) 
     { 
      visibleTimer.Stop(); 
      button1.Visible = false; 
     } 
    } 
+0

面板容器是一个好主意,但是,这并不工作,因为事件不AR鼓泡,父控件...这将是相同的加入mouseenter事件到整个表单。 超时和定时器不是问题,那些工作很好。虽然谢谢! – 2010-06-09 13:34:15