?
Solved

Scroll a Panel Without Having Focus

Posted on 2010-01-10
8
Medium Priority
?
2,738 Views
Last Modified: 2013-12-03
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

0
Comment
Question by:käµfm³d   👽
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 3
  • 2
8 Comments
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 2000 total points
ID: 26278783
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
 
LVL 15

Expert Comment

by:x77
ID: 26278834
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
 
LVL 75

Author Comment

by:käµfm³d 👽
ID: 26279420
@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
The Orion Papers

Are you interested in becoming an AWS Certified Solutions Architect?

Discover a new interactive way of training for the exam.

 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26279539
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
 
LVL 75

Author Comment

by:käµfm³d 👽
ID: 26279933
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
 
LVL 75

Author Closing Comment

by:käµfm³d 👽
ID: 31675295
Always a pleasure working with you, sir!
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 26279988
Hehe...glad you figured it out!  =)
0
 
LVL 15

Expert Comment

by:x77
ID: 26282246
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

Featured Post

Veeam Disaster Recovery in Microsoft Azure

Veeam PN for Microsoft Azure is a FREE solution designed to simplify and automate the setup of a DR site in Microsoft Azure using lightweight software-defined networking. It reduces the complexity of VPN deployments and is designed for businesses of ALL sizes.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question