65.9K
CodeProject 正在变化。 阅读更多。
Home

CRegionButton - 多向按钮

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.32/5 (20投票s)

2004 年 5 月 18 日

3分钟阅读

viewsIcon

120994

downloadIcon

1309

一个用于使按钮看起来好像具有多个区域的类。

引言

本文简要讨论了如何创建一个充当多向按钮的按钮类。大多数按钮在单击时执行一项任务。无论您单击按钮的哪个位置,任务仍然相同。如果任务恰好是在视口中沿某个方向(例如,向左)移动对象,则每个方向都需要一个按钮。可以做到,但有点笨拙。

一个小的改进可能是使用两个微调按钮控件,一个具有UDS_HORZ样式,另一个具有UDS_VERT样式。这两个控件可以放置在彼此的顶部,产生类似如下的效果:

Sample Image - RegionButton1.jpg

虽然没有错误,但这种方法存在几个缺点。首先,控件不能完全重叠。很明显,一个控件实际上遮挡了另一个控件。这最多可能被认为是一个小小的烦恼。

其次,每个控件都需要自己的CSpinButtonCtrl变量,这也意味着需要两个UDN_DELTAPOS处理程序。这些处理程序可能如下所示:

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

如果您需要在一个处理程序中进行更改,那么您很可能也需要在另一个处理程序中进行更改。复制代码很少有趣。

一个更好的解决方案是使用一个控件,该控件根据单击的位置以不同的方式工作。按钮很好地满足了这种需求。

我创建的类CRegionButton派生自CBitmapButton,并且非常易于使用。它有两个私有成员变量和一个公共方法。这两个成员变量用于跟踪按钮上的不同区域。它目前适用于 4 个或 9 个区域,但只要它们是完美的正方形(例如 16、25),其他数字也可以使用。

公共方法CalculateRegions()实际上是所有“魔法”发生的地方。它应该在LoadBitmaps()之后调用。此方法将创建一个CRect对象数组,表示位图的不同区域。

在 4 区域按钮的情况下,该按钮将被平均分为四个区域,编号为 0 到 3。

Sample Image - RegionButton3.jpg

因此,如果用于按钮的位图为 80x80 像素,则按钮的区域 0 将为 l=0, t=0, r=39, 和 b=39。

计算出区域后,现在只需使用BN_CLICKED处理程序检测鼠标点击即可。代码如下所示:

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

发送到父级的消息是通过调用RegisterWindowMessage()创建的已注册消息。您可以在该类的.h文件中看到此消息的实现。请注意,单击的区域作为WPARAM参数发送。

至此,剩下的唯一事情就是响应消息。需要将ON_REGISTERED_MESSAGE()条目添加到对话框的消息映射中。代码如下所示:

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

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

    return (0);
}

现在,我们只有一个方法,无论我们单击按钮的哪个位置都会调用该方法,而且还会告诉我们在按钮上的哪个位置单击。使用时,此按钮可能如下所示:

Sample Image - RegionButton2.jpg

尽情享用!

© . All rights reserved.