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!
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;
}

Open in new window

LVL 75
käµfm³d   👽Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mike TomlinsonMiddle School Assistant TeacherCommented:
It works for me...
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
    {
        public Form1()
        {
            InitializeComponent();

            Application.AddMessageFilter(new MyScroll(this.panel1));
        }
    }

    public class MyScroll : IMessageFilter
    {

        private Panel pnl;

        public MyScroll(Panel pnl)
        {
            this.pnl = pnl;
        }
        
        private const int WM_MOUSEWHEEL = 0x020A;

        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

        bool IMessageFilter.PreFilterMessage(ref Message m)
        {
            if (m.Msg == WM_MOUSEWHEEL)
            {
                if (pnl.RectangleToScreen(pnl.ClientRectangle).Contains(Cursor.Position))
                {
                    SendMessage(pnl.Handle, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
                    return true;
                }
            }

            return false;
        }

    }

}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
x77Commented:
on control, Create a Public Function MouseWeel(MouseEventArgs e) that calls base.OnMouseWeel(e)

Then on the Form manage the MouseWheel event:

Tested on Vb:

        If ActiveControl IsNot PrvCtl Then
            If New Rectangle(PrvCtl.Location, PrvCtl.Size).Contains(New Point(e.X, e.Y)) Then
                PrvCtl.MouseWeel(e)
            End If
        End If
0
käµfm³d 👽Author Commented:
@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.AddMessageFilter(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).

0
Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

Mike TomlinsonMiddle School Assistant TeacherCommented:
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:
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;
        }

    }

}

Open in new window

0
käµfm³d 👽Author Commented:
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).
0
käµfm³d 👽Author Commented:
Always a pleasure working with you, sir!
0
Mike TomlinsonMiddle School Assistant TeacherCommented:
Hehe...glad you figured it out!  =)
0
x77Commented:
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.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.