2015-10-14 65 views
2

我有Panel其中AutoScroll爲真。該面板包含許多較小的面板,可以填充所有可用空間,如瓷磚。當顯示太多子面板時,我會按預期得到垂直滾動條。
這些「圖塊」中的每一個都有一些綁定到它們的事件處理程序來處理MouseDown/MouseUp/MouseMove,因爲它們可以被拖動。將MouseWheel事件從子項傳遞給父項

我遇到的問題是鼠標滾輪不能在父面板上工作,因爲它不會有焦點。我無法專注,因爲很有可能我會在移動一個將重點關注焦點的子面板時進行滾動,即使如此,由於面板不喜歡焦點,因此即使這樣也需要解決方法。

我一直在嘗試(和失敗)找到一種方法來將鼠標滾輪事件從孩子傳播給父母。
我讀過WinFor的話,如果一個控件無法處理鼠標事件,它會將它吹到該控件的父級,然後到該控件的父級,等等,直到找到合適的處理程序。
考慮到這一點,我認爲最好的解決方案是使用WndProc覆蓋子面板上的所有滾動相關事件,並將它們傳遞給父項,同時保持所有其他事件不變但不可否認,這不是我的強項,而我迷失了。

我已經嘗試了一些其他的解決方案,比如讓所有鼠標事件都不可見的子面板,但正如你可能已經猜到這是不好的。我讀過關於實現一個消息過濾器,但不理解它。

這裏的,這將使你的面板和它的孩子們的一個很基本的例子代碼:

private void Form1_Load(object sender, EventArgs e) 
{ 
    Height = 600; 
    Width = 300; 

    Color[] colors = new Color[]{ Color.PowderBlue, Color.PeachPuff }; 

    Panel panel = new Panel() 
    { 
     Height = this.ClientSize.Height - 20, 
     Width = 200, 
     Top = 10, 
     Left = 10, 
     BackColor = Color.White, 
     BorderStyle = BorderStyle.FixedSingle, 
     AutoScroll = true 
    }; 

    for (int i = 0; i < 10; i++) 
    { 
     Panel subPanel = new Panel() 
     { 
      Name = @"SubPanel " + i.ToString(), 
      Height = 100, 
      Width = panel.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - 2, 
      BackColor = colors[i % 2], 
      Top = i * 100 
     }; 
     subPanel.MouseClick += subPanel_MouseClick; 
     panel.Controls.Add(subPanel); 
    } 

    Controls.Add(panel); 
} 

void subPanel_MouseClick(object sender, MouseEventArgs e) 
{ 
    Panel panel = sender as Panel; 
    Text = panel.Name; 
} 

這是我在一個自定義面板覆蓋的WndProc嘗試:

class NoScrollPanel : Panel 
{ 
    private const int WM_HSCROLL = 0x114; 
    private const int WM_VSCROLL = 0x115; 
    private const int MOUSEWHEEL = 0x020A; 
    private const int KEYDOWN = 0x0100; 

    protected override void WndProc(ref Message m) 
    { 
     if ((m.HWnd == Handle) && (m.Msg == MOUSEWHEEL || m.Msg == WM_VSCROLL || (m.Msg == KEYDOWN && (m.WParam == (IntPtr)40 || m.WParam == (IntPtr)35)))) 
     { 
      PostMessage(Parent.Handle, m.Msg, m.WParam, m.LParam); 
     } 
     else 
     { 
      base.WndProc(ref m); 
     } 
    } 

    [DllImport("User32.dll")] 
    private static extern IntPtr PostMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); 
} 

任何幫助或替代方法是最受歡迎的。謝謝!

+1

Windows將消息發送到焦點窗口。這不會是面板,並且不太可能是這種形式,當然不是NoScrollPanel。可能是某種形式的按鈕或工具條。你真的*做*需要[可以採取焦點的面板](http://stackoverflow.com/a/3562449/17034)。 –

+0

感謝漢斯。現在我感到有點愚蠢,因爲我看到了這個線索,並且無意中讀了你的答案。哎呀!我會在明天嘗試它,因爲我確信它會完美地工作。非常感激。 – Equalsk

回答

1

一切歸功於漢斯帕桑特(再次),從他建議螺紋採取:https://stackoverflow.com/a/3562449/17034

允許含有面板採取集中工作的罰款。對於上面的演示代碼,該類不需要更改,僅將其用於包含面板。我必須對我的項目進行一些調整,以便在必要時調用焦點,但這遠非火箭科學。

再次感謝。

0

我無法獲得任何這些解決方案的工作。我像你一樣覆蓋了WndProc fxn。終於找到解決方案!我注意到,如果持有我的TextBox的容器處於焦點狀態,則滾動工作,而不是在TextBox處於焦點時。

我不需要改變事件的透明度,我需要將事件發送到不同的控制柄! (現在看起來很簡單,但我想這出了天!)

internal class myTextBox : TextBox 
{ 
    const int WM_MOUSEWHEEL = 0x020A; 

    protected override void WndProc(ref Message m) 
    { 

     if (m.Msg == WM_MOUSEWHEEL) 
      m.HWnd = this.Parent.Handle; // Change the Handle of the message 

     base.WndProc(ref m); 
    } 
} 

我還沒有看到在我所有的谷歌搜索這個方法的任何提及,如果有一些理由不做這個我希望有人會回覆。

相關問題