kaufmed
asked on
Scroll a Panel Without Having Focus
I have created a panel that has several objects on it. Autoscroll is set to true, so when the number of objects exceeds the visible bounds, the panel automatically adds scrollbars. I want to be able to use the mouse wheel to scroll the panel; however, I would like not to be forced to give the panel focus in order to do so.
I have been experimenting with IMessageFilter to pre-process the mouse wheel event (actually the WM_MOUSEWHEEL message). The code I have been working with is below, and yes, I have added the message filter to the form, even though that line of code is not below. Some code snippets online suggested using SendMessage() to relay the message to the Panel without it needing focus. Would I be correct in my assumption that the panel will process the WM_MOUSEWHEEL message even though it does not have focus?
To summarize, my overall intent is to have the panel be scrollable with the mouse wheel, and only when the mouse is over the panel, not always. My preference is to not give the panel focus and still be able to scroll with the mouse wheel.
Thanks in advance!
I have been experimenting with IMessageFilter to pre-process the mouse wheel event (actually the WM_MOUSEWHEEL message). The code I have been working with is below, and yes, I have added the message filter to the form, even though that line of code is not below. Some code snippets online suggested using SendMessage() to relay the message to the Panel without it needing focus. Would I be correct in my assumption that the panel will process the WM_MOUSEWHEEL message even though it does not have focus?
To summarize, my overall intent is to have the panel be scrollable with the mouse wheel, and only when the mouse is over the panel, not always. My preference is to not give the panel focus and still be able to scroll with the mouse wheel.
Thanks in advance!
const int WM_MOUSEWHEEL = 0x020A;
public bool PreFilterMessage(ref Message m)
{
if (m.HWnd == this.taskPanel1.Handle && m.Msg == WM_MOUSEWHEEL)
{
SendMessage(this.taskPanel1.Handle, m.Msg, m.WParam, m.LParam);
m.Result = IntPtr.Zero;
return true;
}
return false;
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
@Idle_Mind
I swear you have an affinity for this GUI stuff ;)
So you implemented the message filter on the control itself. Right now I implemented it at the form level. Should I implement it only for the panel, or does it even matter? To me, it seems as though implementing at the form level as I have means that there will be more messages passing through the filter, but the end result is the same. Am I correct?
BTW: By "at the form level," I mean
Application.AddMessageFilt er(this);
on my form.
@x77
I assume the code you provided above is to be placed in the MouseWheel handler of the form. Calling OnMouseWheel as you have it implemented above will result in an endless loop (to the point of stack overflow).
I swear you have an affinity for this GUI stuff ;)
So you implemented the message filter on the control itself. Right now I implemented it at the form level. Should I implement it only for the panel, or does it even matter? To me, it seems as though implementing at the form level as I have means that there will be more messages passing through the filter, but the end result is the same. Am I correct?
BTW: By "at the form level," I mean
Application.AddMessageFilt
on my form.
@x77
I assume the code you provided above is to be placed in the MouseWheel handler of the form. Calling OnMouseWheel as you have it implemented above will result in an endless loop (to the point of stack overflow).
It doesn't matter where you implement it...ALL messages intended for your app still go thru the Filter... =)
I passed in a reference to the Panel since that was all that I was interested in. You could pass in whatever you want really!.
You could also NOT pass in anything at all and instead make the filter raise an event that the Form subscribes to. Then, in the form itself, you could do the check to see if the cursor is over the panel and scroll from there accordingly.
That might look like:
I passed in a reference to the Panel since that was all that I was interested in. You could pass in whatever you want really!.
You could also NOT pass in anything at all and instead make the filter raise an event that the Form subscribes to. Then, in the form itself, you could do the check to see if the cursor is over the panel and scroll from there accordingly.
That might look like:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
public Form1()
{
InitializeComponent();
MyScroll ms = new MyScroll();
ms.MouseWheelScrolled += new MyScroll.MouseWheel(ms_MouseWheelScrolled);
Application.AddMessageFilter(ms);
}
private void ms_MouseWheelScrolled(Message m)
{
if (this.panel1.RectangleToScreen(this.panel1.ClientRectangle).Contains(Cursor.Position))
{
SendMessage(this.panel1.Handle, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
}
}
}
public class MyScroll : IMessageFilter
{
public delegate void MouseWheel(Message m);
public event MouseWheel MouseWheelScrolled;
private const int WM_MOUSEWHEEL = 0x020A;
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEWHEEL)
{
MouseWheelScrolled(m);
}
return false;
}
}
}
ASKER
LOL. This is hilarious. I made a boo boo.
I was investigating why I could not get the panel to scroll using SendMessage(). The issue was that I had a panel, but the panel was part of a user control. The Handle I was passing in to SendMessage() was that of the user control and not the panel that was a part of the user control (lol).
Sorry about taking so long, but I was determined to figure that one out (and I didn't wan to respond back with more questions without understanding the problem).
I was investigating why I could not get the panel to scroll using SendMessage(). The issue was that I had a panel, but the panel was part of a user control. The Handle I was passing in to SendMessage() was that of the user control and not the panel that was a part of the user control (lol).
Sorry about taking so long, but I was determined to figure that one out (and I didn't wan to respond back with more questions without understanding the problem).
ASKER
Always a pleasure working with you, sir!
Hehe...glad you figured it out! =)
Re - I assume the code you provided above is to be placed in the MouseWheel handler of the form. Calling OnMouseWheel as you have it implemented above will result in an endless loop (to the point of stack overflow).
No, I define a new Function on the control.
Public void NewFunction(MouseEventArgs e)
{
base.OnMouseWeel(e);
}
I call it MouseWeell, then I can call it from MouseWeell event on Form.
I can't call Control.OnMouseWeel(e) from Form methods, it is Protected.
No, I define a new Function on the control.
Public void NewFunction(MouseEventArgs
{
base.OnMouseWeel(e);
}
I call it MouseWeell, then I can call it from MouseWeell event on Form.
I can't call Control.OnMouseWeel(e) from Form methods, it is Protected.
Then on the Form manage the MouseWheel event:
Tested on Vb:
If ActiveControl IsNot PrvCtl Then
If New Rectangle(PrvCtl.Location,
PrvCtl.MouseWeel(e)
End If
End If