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

CCaptionButton(标题栏按钮)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (41投票s)

2004年6月3日

4分钟阅读

viewsIcon

248929

downloadIcon

10691

标题栏的位图按钮

Sample Image - CCaptionButton.gif

这里有一些具有不同按钮状态的图像

DeActive Image - DeActive.gif

鼠标悬停状态

Highlight Image - Highlight.gif

引言

此类会将可变数量的位图插入到对话框的标题栏中,并像按钮一样处理它们(紧邻关闭、最大化或最小化按钮)。这意味着无论只有一个按钮(用于关闭对话框)还是三个按钮(用于关闭/最大化/最小化),尺寸和位置都将被计算出来。该按钮还可以绘制到具有工具窗口标志或可调整大小标志的对话框上。如果鼠标悬停在按钮上方,按钮会显示高亮状态,并且当窗口非活动时会被禁用。我构建此类的原因是为了在不使用 DrawFrameControl 的情况下,在对话框标题栏中添加一个按钮,以此来获得位图和非客户区的使用经验。

顺便说一句:建设性的批评总是受欢迎的!:-)

使用代码

演示项目中的代码文档记录良好(至少在我看来 ;-)。看看吧!

  1. CaptionButton.hCaptionButton.cpp 文件添加到您的项目中并包含头文件。
    #include "CaptionButton.h"
  2. 创建一个 CCaptionButton 类的成员变量。
    i.e.   CCaptionButton *m_pCapBtn // a pointer to CCaptionButton
  3. 在对话框的 OnInitDialog() 处理程序中调用静态函数 CCaptionButton::InitCapBtn
    CCaptionButton::InitCapBtn(m_hWnd);
    • HWND m_hWnd 是应该放置按钮的窗口的句柄。
  4. 当我们在对话框源文件的 OnInitDialog() 部分时,我们向类提供一些细节。

    因此,我们使用成员函数 SetBmpID

    m_pCapBtn->SetBmpID(1, IDB_LAMPOFF, IDB_LAMPON, FALSE);
    • UINT n(在本例中为 1)是按钮的编号(例如:1 是最右边的按钮,然后是按钮 1 左边的按钮 2...)
    • UINT IDB_LAMPOFF按下按钮的位图
    • UINT IDB_LAMPON 是按钮按下状态下的位图。如果您希望将相同的位图用于两种按钮状态(按下/未按下),则可以将其留空。
    • BOOL FALSE 表示按钮的类型(复选框或否)。仅对悬停绘制重要。

    您可以在代码中的任何位置使用此函数来更改位图,只要第一个参数保持不变。

  5. 现在,我们需要响应 WMU_HITCAPBUTTON 消息

    当标题栏中的按钮被单击时,我们希望采取一些操作。每次单击我们的按钮时,都会向我们的窗口发送一条消息。这就是为什么我们必须为已注册的消息 WMU_HITCAPBUTTON 添加一个处理程序。请按照以下简单步骤完成任务:

    • 您可以在对话框类的头文件中的消息处理程序部分定义处理程序 OnWMU_Hitcapbutton。添加声明
      • afx_msg LRESULT OnWMU_Hitcapbutton(WPARAM wParam, LPARAM lParam);
    BEGIN_MESSAGE_MAP(CTitleBarButtonDlg, CDialog)
            //{{AFX_MSG(CTitleBarButtonDlg)
            virtual BOOL OnInitDialog();
            afx_msg void OnPaint();
            afx_msg HCURSOR OnQueryDragIcon();
            afx_msg void OnNcLButtonDown(UINT nHitTest, CPoint point);
            afx_msg void OnNcPaint();
            afx_msg void OnDestroy();
            afx_msg BOOL OnNcActivate(BOOL bActive);
            afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
            //}}AFX_MSG
            afx_msg LRESULT OnWMU_Hitcapbutton(WPARAM wParam, LPARAM lParam);
    DECLARE_MESSAGE_MAP()
    • 为这些消息创建一个条目以进行分派,因此您需要声明已注册的消息并在对话框类的源文件的消息映射中添加一个条目
      • 对于已注册的消息:DECLARE_USER_MESSAGE(WMU_HITCAPBUTTON)
      • 消息映射条目:ON_REGISTERED_MESSAGE(WMU_HITCAPBUTTON, OnWMU_Hitcapbutton)
    // announce the registered message:
    
    DECLARE_USER_MESSAGE(WMU_HITCAPBUTTON)
    
    BEGIN_MESSAGE_MAP(CTitleBarButtonDlg, CDialog)
            //{{AFX_MSG_MAP(CTitleBarButtonDlg)
            ON_WM_PAINT()
            ON_WM_QUERYDRAGICON()
            ON_WM_NCLBUTTONDOWN()
            ON_WM_NCPAINT()
            ON_WM_DESTROY()
            ON_WM_NCACTIVATE()
            ON_WM_NCMOUSEMOVE()
            //}}AFX_MSG_MAP
            ON_REGISTERED_MESSAGE(WMU_HITCAPBUTTON, OnWMU_Hitcapbutton)
    END_MESSAGE_MAP()

    请注意,消息映射中的条目写在 //}}AFX_MSG - MFC 标签之外!

    • 现在,当您的类收到 WMU_HITCAPBUTTON 消息时,它将调用此消息的处理程序,该处理程序应如下所示:
    /***********************************************************************
    *   Message Name:            WMU_HITCAPBUTTON
    *   Inputs:
    *     WPARAM: (UINT)wParam = Nomba of Button
    *     LPARAM: (BOOL)lParam = Button state (Pressed=TRUE/Released=FALSE)
    *
    *   Result: LRESULT
    *                       Logically void, 0, always
    *
    *   Effect: represents the # of the Button (if there is more than one)
    *               and the button state (pressed/released)
    ***********************************************************************/
    LRESULT CTitleBarButtonDlg::OnWMU_Hitcapbutton(WPARAM wParam,
                                                      LPARAM lParam)
    {
            // Button #1 has been hit:
            if((UINT)wParam == 1)
            {
                // button No.1 has been clicked, now do something
    
            }
    
    return 0; // Allways return 0(LRESULT->void)
    }

就是这样!现在您的按钮应该可以工作了。


附加成员函数

  • 一个用于启用/禁用按钮的函数(此例程已实现,但在我的 NT4 上不起作用,尽管它在我的 XP-Home 上起作用)
    BOOL CCaptionButton::EnableButton(BOOL bEnable)

计划中但尚未实现

  • 一个用于显示/隐藏按钮的函数
  • 一个用于获取/设置按钮状态的函数
  • ..... ..... ..... .....
  • 欢迎提出更多建议!

    以下是 CCaptionButton 类中处理的消息

    • WM_NCPAINT:在这里,按钮将被绘制到标题栏。
    • WM_NCACTIVATE:对话框的活动/非活动状态将在此处“更改”。
    • WM_NCLBUTTONDOWN:鼠标单击将在此处处理。
    • WM_NCMOUSEMOVE:在这里,按钮将被告知鼠标何时悬停在其上方。
    • WM_SETTEXT:必须处理此消息,否则标题栏将以我不喜欢的方式更改;-)

    致谢

    • 如果您想了解更多关于消息传递的信息,您应该阅读 Joseph M. Newcomer 的精彩文章 Joseph M. Newcomer
    • Paul Di Lascia。我在 isWindowActive(...) 中重用了他的代码。
    • 有关 Win32 实现,请在此处查看:here

    更新

    • 04.06.2004
      • 已添加 TRACKMOUSEEVENT 结构
      • 已添加 TrackMouseEvent(TRACKMOUSEEVENT lpEventTrack) 函数
      • 已添加 WM_NCMOUSELEAVE 的消息处理
      • 更改了 COLORADJUSTMENT 结构中的一些值
    • 11.06.2004
      • 解决了在 NC 区域右键单击时按钮消失的问题
      • 解决了在 NC 区域左键单击重新激活对话框时按钮绘制延迟的问题
    © . All rights reserved.