Click here to Skip to main content
Click here to Skip to main content
Go to top

CRegionButton - A multidirectional button

, 17 May 2004
Rate this:
Please Sign up or sign in to vote.
A class for making a button appear as though it has many regions.

Introduction

This article is a brief discussion on how you would go about creating a button class that acts as a multidirectional button. Most buttons perform a task when clicked. No matter where you click on the button, the task is still the same. If the task happened to be something like moving an object in the viewport in some direction (e.g., left), you'd need one button per direction. Do-able, but a bit awkward.

A slight improvement might be to use two spin button controls, one with the UDS_HORZ style and then the other with the UDS_VERT style. These two controls can be placed atop each other, producing something like:

Sample Image - RegionButton1.jpg

While not incorrect, there are several drawbacks to this approach. The first is that the controls do not overlap cleanly. It's plain to see that one control is actually obscuring the other. This might be considered a minor annoyance at best.

Second, each control requires its own CSpinButtonCtrl variable, which also means that two UDN_DELTAPOS handlers will be needed. These handlers might look like:

void CRegionButtonTestDlg::OnDeltaposHorz(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_UPDOWN *pNMUpDown = (NM_UPDOWN *) pNMHDR;

    if (0 < pNMUpDown->iDelta)
        ; // left
    else
        ; // right
 
    *pResult = 0;
}

void CRegionButtonTestDlg::OnDeltaposVert(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_UPDOWN *pNMUpDown = (NM_UPDOWN *) pNMHDR;

    if (0 < pNMUpDown->iDelta)
        ; // down
    else
        ; // up

    *pResult = 0;
}

If you needed a change in one handler, chances are that you'd also need it in the other. Duplicating code is rarely fun.

A better solution would be to use one control that acted differently depending on where it was clicked. A button fills this need pretty well.

The class I created, CRegionButton is derived from CBitmapButton and is very easy to use. It has two private member variables, and one public method. The two member variables are to keep track of the different regions on the button. It currently works with 4 or 9 regions, but other numbers will work as long as they are a perfect square (e.g., 16, 25).

The public method, CalculateRegions(), is really where all the "magic" takes place. It should be called sometime after LoadBitmaps(). This method will create an array of CRect objects that represent the different regions of the bitmap.

In the case of a 4-region button, the button would be equally divided into four regions numbered 0 through 3.

Sample Image - RegionButton3.jpg

So, if the bitmap used for the button was 80x80 pixels, region 0 of the button would be l=0, t=0, r=39, and b=39.

Once the regions have been calculated, now it's just a matter of detecting mouse clicks with a BN_CLICKED handler. The code for that looks like:

void CRegionButton::OnClicked() 
{
    CPoint  pt;
    DWORD   dwPos;
    
    // where was the mouse clicked
    dwPos = GetMessagePos();

    // get the X/Y screen coordinates
    pt.x = LOWORD(dwPos);
    pt.y = HIWORD(dwPos);

    // convert them to client coordinates
    ScreenToClient(&pt);

    // see if the mouse click is within any of the regions
    for (UINT x = 0; x < m_uRegionCount; x++)
    {
        // if so, send a message to the parent
        // including the region that was clicked
        if (m_pRegion[x].PtInRect(pt) != FALSE)
        {
            GetParent()->SendMessage(UDM_REGION_CLICKED, x);
            break;
        }
    }
}

The message that is sent to the parent is a registered message created by calling RegisterWindowMessage(). You can see the implementation of this message in the class' .h file. Notice that the region that was clicked is sent as the WPARAM parameter.

At this point, the only thing left to do is respond to the message. An ON_REGISTERED_MESSAGE() entry will need to be added to the dialog's message map. The code for that looks like:

LRESULT CRegionButtonTestDlg::OnRegionClicked( WPARAM wParam, LPARAM lParam )
{
    CString     str;

    str.Format("You clicked in region %u", wParam);

    return (0);
}

Now, we have but one method that gets called no matter where we click on the button, but also tells where upon the button we clicked. When in use, this button might look like:

Sample Image - RegionButton2.jpg

Enjoy!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

DavidCrow
Software Developer (Senior) Pinnacle Business Systems
United States United States

The page you are looking for might have been removed, had its name changed, or is temporarily unavailable.
 
HTTP 404 - File not found
Internet Information Services

Comments and Discussions

 
GeneralCool PinmemberChris Richardson18-May-04 21:37 
GeneralRe: Cool PinmemberDavidCrow19-May-04 2:55 
Generalgood idea Pinmember.dan.g.18-May-04 19:05 
GeneralRe: good idea PinmemberDavidCrow19-May-04 2:25 
General32 warnings !!! PinmemberWREY18-May-04 11:45 
GeneralRe: 32 warnings !!! PinstaffNishant S18-May-04 20:06 
GeneralRe: 32 warnings !!! PinmemberDavidCrow19-May-04 2:30 
Nishant S wrote:
David probably used the now obsolete VC6 compiler...
 
Correct, hence the VC6 in the upper-right corner!
 
Nishant S wrote:
...which is really bad at standards compliance.
 
The warnings have nothing to do with standards compliance. In this case, the warnings are produced because a double is being assigned to a long. No data is being lost so I did not bother with the cast.
 

"The pointy end goes in the other man." - Antonio Banderas (Zorro, 1998)


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
Web01 | 2.8.140926.1 | Last Updated 18 May 2004
Article Copyright 2004 by DavidCrow
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid