zoukankan      html  css  js  c++  java
  • VC中给树形控件的图标加上工具提示





    我从没有在任何一个应用程序中看到过图标的工具提示。有时候查遍了整个帮助
    文档也没有明白某个图标是什么意思。如果能在自己的程序中为图标加上工具提
    示,一定会使界面的友好性大大增加。本文中以树形控件为例,详细介绍了在VC
    中使用MFC提供的机制来实现图标工具提示的方法。

    ---- 第一步:使控件可以显示工具提示

    ---- 调用EnableToolTips(TRUE)使一个窗口可以显示工具提示。在什么地方插入
    这条代码最好呢?在类的PreSubclassWindow()中。因为不管一个控件如何被创建
    ,MFC都会调用此函数。而其他的函数则不一定会被调用。以OnCreate()为例,如
    果调用Create()或CreateEx()创建一个控件,OnCreate()会被调用,而如果一个
    控件是从对话框资源创建,OnCreate()就不会被调用。

    实现代码如下:
    void CTreeCtrlX::PreSubclassWindow()
    {
    CTreeCtrl::PreSubclassWindow();

    EnableToolTips(TRUE);
    }

    ---- 第二步:重载虚函数OnToolHitTest()
    ---- MFC调用函数来确定在某个点是否应该显示工具提示。MSDN建议如果鼠标落
    在应该显示工具提示的点上,返回值1。这并不完全正确。这个函数应该返回不同
    的值来区分窗口中不同的应该显示提示的区域。

    ---- 在这个函数中,本文只处理鼠标落在节点图标或节点状态图标上的情况。读
    者可以按照自己的情况向树的其他元素上添加工具提示。在两种情况下,都要计
    算图标的区域,并且把TOOLINFO的uID设为鼠标所在点的树节点的句柄。注意,尽
    管对于节点图标和节点状态图标,使用了相同的id,但返回值并不相同。不同的
    返回值迫使MFC更新工具提示。

    ---- 虽然我们可以在此函数中给出工具提示,但因为鼠标的每次移动都会调用此
    函数,太多的处理并不是一个好注意,所以我们在其他的函数中处理应该显示什
    么提示的问题。

    类声明中的代码如下所示:
    // Overrides
    // ClassWizard generated
    virtual function overrides
    //{{AFX_VIRTUAL(CTreeCtrlX)
    protected:

    virtual int OnToolHitTest
    ( CPoint point, TOOLINFO* pTI ) const;
    //}}AFX_VIRTUAL

    实现代码如下所示:
    int CTreeCtrlX::OnToolHitTest
    (CPoint point, TOOLINFO * pTI) const
    {
    RECT rect;

    UINT nFlags;
    HTREEITEM hitem = HitTest( point, &nFlags );
    if( nFlags & TVHT_ONITEMICON )
    {
    CImageList *pImg = GetImageList( TVSIL_NORMAL );
    IMAGEINFO imageinfo;
    pImg- >GetImageInfo( 0, &imageinfo );

    GetItemRect( hitem, &rect, TRUE );
    rect.right = rect.left - 2;
    rect.left -= (imageinfo.rcImage.right + 2);

    pTI- >hwnd = m_hWnd;
    pTI- >uId = (UINT)hitem;
    pTI- >lpszText = LPSTR_TEXTCALLBACK;
    pTI- >rect = rect;
    return pTI- >uId;
    }
    else if( nFlags & TVHT_ONITEMSTATEICON )
    {
    CImageList *pImg = GetImageList( TVSIL_NORMAL );
    IMAGEINFO imageinfo;
    pImg- >GetImageInfo( 0, &imageinfo );

    GetItemRect( hitem, &rect, TRUE );
    rect.right = rect.left -
    (imageinfo.rcImage.right + 2);

    pImg = GetImageList( TVSIL_STATE );
    rect.left = rect.right - imageinfo.rcImage.right ;

    pTI- >hwnd = m_hWnd;
    pTI- >uId = (UINT)hitem;
    pTI- >lpszText = LPSTR_TEXTCALLBACK;
    pTI- >rect = rect;

    // 返回与节点图标不同的值
    return pTI- >uId*2;
    }
    return -1;
    }

    ---- 第三步:处理TTN_NEEDTEXT消息;
    ---- 加入一个函数处理TTN_NEEDTEXT消息通知。当工具处理控制需要知道应该显
    示什么信息时,这条消息被发出。由于上一步中我们给TOOLINFO的lpszText赋值
    为LPSTR_TEXTCALLBACK,所以我们要处理这个消息VC的ClassWizard并不支持这条
    消息被映射,所以只有我们自己加入这条消息的映射机制加入到MESSAGE_MAP中去
    。我们不得不处理这个消息的两个版本,TTN_NEEDTEXTA和TTN_NEEDTEXTA。消息
    映射的代码如下所示:

    BEGIN_MESSAGE_MAP(CTreeCtrlX, CTreeCtrl)
    //{{AFX_MSG_MAP(CTreeCtrlX)

    //}}AFX_MSG_MAP
    ON_NOTIFY_EX_RANGE
    (TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
    ON_NOTIFY_EX_RANGE
    (TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
    END_MESSAGE_MAP()

    下面的代码是加到类声明中:
    protected:
    //{{AFX_MSG(CTreeCtrlX)

    //}}AFX_MSG
    afx_msg BOOL OnToolTipText
    ( UINT id, NMHDR * pNMHDR, LRESULT * pResult );
    DECLARE_MESSAGE_MAP()

    ---- 现在讨论这个函数本身的实现。为了适应不同的语言字符集,ANSI字符集和
    UNICODE字符集都必须被处理,处理过程会有些不同。此处对树形控件的本身产生
    的ToolTip消息不予处理,过滤掉上述消息的原则是树形控件本身产生的消息的ID
    是树形控件窗口的句柄,并且有TTF_IDISHWND标志。根据鼠标位置可以确定应该
    给出节点图标还是状态图标的工具提示。本文根据笔者画的图显示了一些无关紧
    要的提示,读者做这一步时应该加入一些有意义的提示。当然,本文假定控件包
    含节点图标和状态图标。如不包含,计算鼠标位置时要注意 不要计算错误。

    BOOL CTreeCtrlX::OnToolTipText
    ( UINT id, NMHDR * pNMHDR, LRESULT * pResult )
    {
    // 需要处理ANSI和UNICODE两种格式
    TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
    TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
    CString strTipText;
    UINT nID = pNMHDR- >idFrom;

    // 不必处理树自己发出的ToolTip消息
    if( nID == (UINT)m_hWnd &&
    (( pNMHDR- >code == TTN_NEEDTEXTA &&
    pTTTA- >uFlags & TTF_IDISHWND ) ||
    ( pNMHDR- >code == TTN_NEEDTEXTW &&
    pTTTW- >uFlags & TTF_IDISHWND ) ) )
    return FALSE;

    // 得到鼠标位置
    const MSG* pMessage;
    CPoint pt;
    pMessage = GetCurrentMessage();
    ASSERT ( pMessage );
    pt = pMessage- >pt;
    ScreenToClient( &pt );

    UINT nFlags;
    HTREEITEM hitem = HitTest( pt, &nFlags );
    if( nFlags & TVHT_ONITEMICON )
    {
    int nImage, nSelImage;
    GetItemImage( (HTREEITEM ) nID, nImage, nSelImage );
    switch(nImage)
    {
    case 0:
    strTipText = "叉";
    break;
    case 1:
    strTipText = "加号";
    break;
    case 2:
    strTipText = "菱形";
    break;
    }
    }
    else
    {
    if( (GetItemState( (HTREEITEM ) nID,
    TVIS_STATEIMAGEMASK ) > >12 ) == 2 )
    strTipText.Format( "此节点被选中" );
    else
    strTipText.Format( "此节点未被选中" );
    }

    #ifndef _UNICODE
    if (pNMHDR- >code == TTN_NEEDTEXTA)
    lstrcpyn(pTTTA- >szText, strTipText, 80);
    else
    _mbstowcsz(pTTTW- >szText, strTipText, 80);
    #else
    if (pNMHDR- >code == TTN_NEEDTEXTA)
    _wcstombsz(pTTTA- >szText, strTipText, 80);
    else
    lstrcpyn(pTTTW- >szText, strTipText, 80);
    #endif
    *pResult = 0;

    return TRUE; // 消息处理完毕
    }

    ---- 本文程序在Win9x,VC6.0下调试通过。

  • 相关阅读:
    JDBC数据更新
    ResultSet 的Type属性
    iis7 和iis10 对json处理的不同,导致的JavaScript的不兼容
    噪音分贝DB,FFT. 振动加速度关系
    各个版本的版本sqlserver
    实战多线程交互
    OSS 真香,比FTP速度快多了。
    How to print a fast report in ZPL format
    新项目要用斑马打印机打标签
    蓝屏故障诊断工具Windows Debugger
  • 原文地址:https://www.cnblogs.com/zhiweiyouzhishenghuo/p/5005503.html
Copyright © 2011-2022 走看看