Click here to Skip to main content
Click here to Skip to main content

CWindowScroller

, 20 Mar 2003
Rate this:
Please Sign up or sign in to vote.
An MFC control for adding middle mouse button scrolling to any CWnd derived window

Sample Image - WindowScroller.jpg

Introduction

CWindowScroller is a small MFC class that is used to add middle mouse button scrolling functionality (aka. panning) to any CWnd derived window. The control is similar to the one that is found in Internet Explorer and Visual Studio .NET. All that is needed is a single line of code to get the window scroller up and running. All the resources (icon and cursors) that the window scroller uses are created dynamically at run time. They do not have to be added to your resource file.

Using the code

The first (and most obvious) step to using the CWindowScroller class is to add the class files (WindowScroller.h and WindowScroller.cpp ) to your project.

In the .cpp file for the window that you want to add the scroller to, be sure to include the WindowScroller.h file

#include "WindowScroller.h"

Then, using class wizard, add the OnMButtonDown function to your window class. ( Just a small note, the message filter has to be set to "Window" )

Now, in the OnMButtonDown function, all you have to do is create an instance of the CWindowScroller class on the heap.

void CChildView::OnMButtonDown (UINT, CPoint point)
{
    CWindowScroller *ws = new CWindowScroller (this, point);
}

Notes :

  • If you create the CWindowScroller on the stack, it will briefly flash on the screen and then be destroyed when your variable goes out of scope.
  • There is no use saving the pointer for later use, as the CWindowScroller will be destroyed, and the memory deleted as soon as your user is finished using it.
  • If you are compiling under warning level 4, this construct will give your warning number C4189 "local variable is initialized but not referenced". The warning can safely be ignored.

When the CWindowScroller is destroyed, it posts a registered windows message to the window that it scrolled. If you want to handle the message you must define the window message using the RegisterWindowMessage() function passing in the RWM_OnDestroyWindowScrollerString string that is defined in the WindowScroller.h file. See ON_REGISTERED_MESSAGE in MSDN for more information on handling registered messages.

Member Functions

The class constructor is the only public member function.

CWindowScroller::CWindowScroller (CWnd *pParent,
                                  CPoint Point,
                                  int Pixels,        // = 15
                                  UINT Elapse,       // = 30
                                  int Direction,     // = Both
                                  BOOL bUseThumbPos) // = TRUE

Parameters

pParent A pointer to the window that needs to be scrolled
Point The point, in parent window client coordinates, that will be the center of the CWindowScroller window
Pixels The distance interval, in pixels, that the mouse pointer has to be away from the center of the CWindowScroller window before the scrolling speed increases.
Elapse The time, in milliseconds, between scrolling messages. This value is passed on to the SetTimer() function
Direction The direction of the scroll. Allowable values are CWindowScroller::Vertical, CWindowScroller::Horizontal or CWindowScroller::Both
bUseThumbPos Sets the message flag to be used with WM_HSCROLL and WM_VSCROLL messages.
TRUE sets the flag to SB_THUMBPOSITION.
FALSE sets the flag to SB_THUMBTRACK.

Scrolling Speed

The scrolling speed is calculated by taking the distance, in pixels, that the mouse pointer is away from the center of the CWindowScroller window and dividing it by the value of the Pixels parameter. This will give the distance that the parent window will be scrolled every Elapse milliseconds.

Preparing your window to use the CWindowScroller

The majority of windows should work with the CWindowScroller without any problems, but some may need a little special attention, either with the CWindowScroller settings or with the way the window handles scrolling messages.

The CWindowScroller currently handles any regular CWnd derived classes by setting the scrollbar position with a call to CWnd::SetScrollPos(), and then sending either a WM_HSCROLL or WM_VSCROLL message to the window. It also has built in code for handling CScrollViews, CTreeViews, and CListViews.

How to add more supported window types to the CWindowScroller

If you get a window that the CWindowScroller does not handle because it uses some non-standard method for scrolling ( such as a list view, which uses the LVM_SCROLL message instead of WM_HSCROLL/WM_VSCROLL ) and you want the CWindowScroller to handle it, then you will have to add some code in the following places in the WindowScroller.cpp file.

First, add a new window type identifier to the WindowTypes enumeration found at the top of the file

enum WindowTypes
{
    Type_CWnd = 0,
    Type_CScrollView,
    Type_CTreeView,
    Type_CListView_Report,
    Type_CListView_List,
    Type_CListView_Icon
    // Add more types here
};

Second, add the code to the GetParentWndType() function that can use the pointer passed into the CWindowScroller constructor to identify the window type. Have that code return the identifier that you added to the WindowTypes enumeration.

UINT CWindowScroller::GetParentWndType()
{
    TCHAR szClassName[256] = {0};
    ::GetClassName(*m_pParentWnd, szClassName, sizeof szClassName);
    
    if (!_tcscmp(szClassName, _T("SysTreeView32")))
        return Type_CTreeView;

    if (!_tcscmp(szClassName, _T("SysListView32")))
    {
        if ((m_pParentWnd->GetStyle() & 0x3) == LVS_REPORT)
            return Type_CListView_Report;
        
        if ((m_pParentWnd->GetStyle() & 0x3) == LVS_LIST)
            return Type_CListView_List;
        
        return Type_CListView_Icon;
    }

    if (m_pParentWnd->IsKindOf(RUNTIME_CLASS(CScrollView)))
        return Type_CScrollView;

    // Add additional window identifier code here

    return Type_CWnd;
}

The third step is to add the actual scrolling code to the OnTimer() function. Add the code as a case within the switch (m_ParentWndType) block, using the identifier you added to the WindowTypes enumeration and returned from the GetParentWndType() function as the case to be handled.

void CWindowScroller::OnTimer(UINT nIDEvent) 
{
    < snip >
    if (nIDEvent == 0x1FEB && rc.PtInRect(pt) && (m_HorzScroll || m_VertScroll))
    {
        < snip >
        if (NewPoint != OriginalPoint)
        {
            switch (m_ParentWndType)
            {
            case Type_CListView_Report:
                < snip >
                break;

            case Type_CListView_List:
                < snip >
                break;

            case Type_CListView_Icon:
                < snip >
                break;

            case Type_CTreeView:
                < snip >
                break;

            case Type_CScrollView:
                < snip >
                break;

            case Type_CWnd:
                < snip >
                break;

            // Add additional cases here

            default:
                TRACE (_T("CWindowScroller::OnTimer - Unknown window type"));
                break;
            } // switch (m_ParentWndType)
        } // if (NewPoint != OriginalPoint)
    } // if (nIDEvent == 0x1FEB && rc.PtInRect(pt) && (m_HorzScroll || m_VertScroll))
}

The final step is to write up what you did in the forum below, and I will update the article with the new code.

Even if you do all this, there may still be some windows that the CWindowScroller may still not work properly with. One such window that I had a problem with was Chris Maunder's MFC Grid control 2.24. The horizontal scrolling worked great, but the vertical scrolling had a small problem. It turned out that the fixed columns along the left hand side of the control would not scroll along with the rest of the control. The problem (for me, not for Chris) was that the SB_THUMBTRACK and SB_THUMBPOSITION flags were being handled the same, but they have to be handled seperately. So a small change was required in the CGridCtrl::OnVScroll() function to get the CWindowScroller to function properly.

// Handle vert scrollbar notifications
void CGridCtrl::OnVScroll(UINT nSBCode,
                          UINT /*nPos*/,
                          CScrollBar* /*pScrollBar*/)
{

< snip >
        
    // pja - 9/1/2003 - changed case SB_THUMBPOSITION:
    // so it properly handles the CWindowScroller
    case SB_THUMBPOSITION:
        m_idTopLeftCell.row = -1;
        rect.top = GetFixedRowHeight();
        InvalidateRect(rect);
        break;

    case SB_THUMBTRACK:
        {
    
< snip >

If any of you find other windows that the CWindowScroller has problems with, and you manage to find a fix, let me know and I can post the fix here. Thanks

History

January 10, 2003 Initial release
January 20, 2003 Added code for scrolling list views - Thanks to Jean-Michel LE FOL
January 23, 2003 Fixed middle button click'n hold bug
February 16, 2003 Added mouse button up handlers
February 16, 2003 Cleaned up the demo app's drawing code in order to reduce flicker when using the window scroller
March 8, 2003 Fixed bug that crashed program if window creation fails
March 10, 2003 Total rewrite of scrolling code, now supports tree views and list views in all modes.
Added GetParentWndType function

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

PJ Arends
President
Canada Canada
No Biography provided

Comments and Discussions

 
GeneralGreat work, although it's already implemented in CScrollView... Pinmemberpiotrmb15-Dec-05 3:48 
GeneralRe: Great work, although it's already implemented in CScrollView... PinmemberPJ Arends15-Dec-05 9:13 
GeneralRe: Great work, although it's already implemented in CScrollView... Pinmemberpiotrmb18-Dec-05 3:20 
GeneralEcellent work, PinmemberErgin Salih28-Nov-05 2:53 
GeneralAdded support for CListBox PinmemberPJ Arends12-Jul-03 17:51 
GeneralProblems with certain rodents PinmemberPJ Arends8-Mar-03 8:24 
GeneralRe: Problems with certain rodents PinmemberWREY10-Mar-03 11:58 
GeneralYou did not disappoint !! PinmemberWREY7-Mar-03 14:07 
GeneralRe: You did not disappoint !! PinmemberPJ Arends7-Mar-03 18:34 
GeneralBroken download links PinmemberNeville Franks24-Feb-03 10:06 
GeneralRe: Broken download links - Fixed PinmemberPJ Arends24-Feb-03 15:01 
GeneralUsing it in ED PinmemberNeville Franks27-Feb-03 16:42 
GeneralRe: Using it in ED PinmemberPJ Arends27-Feb-03 17:40 
GeneralRe: Using it in ED PinmemberNeville Franks27-Feb-03 19:20 
GeneralCompile error under VC7 PinmemberGerard Nicol28-Jan-03 9:40 
GeneralRe: Compile error under VC7 PinmemberPJ Arends28-Jan-03 10:20 
GeneralPB: Doesn't work with ListView PinmemberJean-Michel LE FOL20-Jan-03 1:59 
GeneralRe: PB: Doesn't work with ListView PinmemberPJ Arends20-Jan-03 9:27 
GeneralRe: PB: Doesn't work with ListView PinmemberDieter Hammer25-Feb-03 21:22 
GeneralRe: PB: Doesn't work with ListView PinmemberLasthero25-Feb-03 23:10 
GeneralRe: PB: Doesn't work with ListView PinmemberDieter Hammer26-Feb-03 0:29 
GeneralJust another proposal PinmemberDieter Hammer26-Feb-03 1:21 
GeneralUpdated PinmemberPJ Arends21-Mar-03 12:16 
GeneralOne suggestion PinmemberGregor S.12-Jan-03 3:42 
GeneralRe: One suggestion PinmemberPJ Arends12-Jan-03 8:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140821.2 | Last Updated 21 Mar 2003
Article Copyright 2003 by PJ Arends
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid