2010-06-09 112 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