给CListBox增加个性化的ToolTip

转载请注明来源:http://www.cnblogs.com/xuesongshu/

【步骤】

  1、新建一个MFC应用程序项目,无项目设置要求

  2、添加一个对话框,添加一个ListBox,无属性设置要求,ListBox宽度最好设小点,以突出效果。

  3、添加CShellExcuteString类,ShellExcuteString.h代码如下:

#ifndef _HYPRILNK_H
#define _HYPRILNK_H

class CShellExcuteString:public CString
{
public:
    CShellExcuteString(LPCTSTR lpLink=NULL):CString(lpLink) {}
    ~CShellExcuteString() {}
    const CShellExcuteString& operator=(LPCTSTR lpsz)
    {
        CString::operator=(lpsz);
        return*this;
    }
    operator LPCTSTR()
    {
        return CString::operator LPCTSTR();
    }
    virtual HINSTANCE Navigate()
    {
        return IsEmpty()?NULL:ShellExecute(0,_T("open"),*this,0,0,SW_SHOWNORMAL);
    }
};
#endif

  4、添加CHookWindowObject类,HookWindowObject.h代码如下:

#ifndef _SUBCLASSW_H
#define _SUBCLASSW_H
class CHookWindowObject:public CObject
{
public:
    CHookWindowObject();
    ~CHookWindowObject();

    BOOL HookWindow(HWND hwnd);
    BOOL HookWindow(CWnd *pWnd)
    {
        return HookWindow(pWnd->GetSafeHwnd());
    }
    void Unhook()
    {
        HookWindow((HWND)NULL);
    }
    BOOL IsHooked()
    {
        return m_hWnd!=NULL;
    }
    friend LRESULT CALLBACK HookWndProc(HWND,UINT,WPARAM,LPARAM);
    friend class CHookWindowMap;
    virtual LRESULT WindowProc(UINT msg,WPARAM wp,LPARAM lp);
    LRESULT Default();//call this at the end of handler fns
#ifdef _DEBUG
    virtual void AssertValid()const;
    virtual void Dump(CDumpContext&dc)const;
#endif
protected:
    HWND m_hWnd;//the window hooked
    WNDPROC m_pOldWndProc;//..and original window proc
    CHookWindowObject *m_pNext;//next in chain of hooks for this window
    DECLARE_DYNAMIC(CHookWindowObject);
};
#endif//_SUBCLASSW_H

  HookWindowObject.cpp代码如下:

IMPLEMENT_DYNAMIC(CHookWindowObject,CWnd);
CHookWindowObject::CHookWindowObject()
{
    m_pNext=NULL;
    m_pOldWndProc=NULL;
    m_hWnd=NULL;
}
CHookWindowObject::~CHookWindowObject()
{
    if(m_hWnd)
        HookWindow((HWND)NULL);//unhook window
}

BOOL CHookWindowObject::HookWindow(HWND hwnd)
{
    ASSERT_VALID(this);
    if(hwnd)
    {
//Hook the window
        ASSERT(m_hWnd==NULL);
        ASSERT(::IsWindow(hwnd));
        theHookMap.Add(hwnd,this);//Add to map of hooks
    }
    else if(m_hWnd)
    {
//Unhook the window
        theHookMap.Remove(this);//Remove from map
        m_pOldWndProc=NULL;
    }
    m_hWnd=hwnd;
    return TRUE;
}

LRESULT CHookWindowObject::WindowProc(UINT msg,WPARAM wp,LPARAM lp)
{
//ASSERT_VALID(this);//removed for speed
    ASSERT(m_pOldWndProc);
    return m_pNext?m_pNext->WindowProc(msg,wp,lp):
           ::CallWindowProc(m_pOldWndProc,m_hWnd,msg,wp,lp);
}

LRESULT CHookWindowObject::Default()
{
//MFC stores current MSG in thread state
    MSG &curMsg=AfxGetThreadState()->m_lastSentMsg;
//Note:must explicitly call CHookWindowObject::WindowProc to avoid infinte
//recursion on virtual function
    return CHookWindowObject::WindowProc(curMsg.message,curMsg.wParam,curMsg.lParam);
}
#ifdef _DEBUG
void CHookWindowObject::AssertValid() const
{
    CObject::AssertValid();
    ASSERT(m_hWnd==NULL||::IsWindow(m_hWnd));
    if(m_hWnd)
    {
        for(CHookWindowObject *p=theHookMap.Lookup(m_hWnd); p; p=p->m_pNext)
        {
            if(p==this)
                break;
        }
        ASSERT(p);//should have found it!
    }
}
void CHookWindowObject::Dump(CDumpContext&dc)const
{
    CObject::Dump(dc);
}
#endif

/////////////////
//Find first hook associate with window
//
CHookWindowObject *CHookWindowMap::Lookup(HWND hwnd)
{
    CHookWindowObject *pFound=NULL;
    if(!CMapPtrToPtr::Lookup(hwnd,(void*&)pFound))
        return NULL;
    ASSERT_KINDOF(CHookWindowObject,pFound);
    return pFound;
}

  5、添加CHookWindowMap类,代码放在HookWindowObject.cpp头部,代码如下:

class CHookWindowMap:private CMapPtrToPtr
{
public:
    CHookWindowMap();
    ~CHookWindowMap();
    static CHookWindowMap &GetHookMap();
    void Add(HWND hwnd,CHookWindowObject *pNewHook);
    void Remove(CHookWindowObject *pOldHook);
    void RemoveAll(HWND hwnd);
    CHookWindowObject*Lookup(HWND hwnd);
};

#define theHookMap (CHookWindowMap::GetHookMap())

CHookWindowMap::CHookWindowMap()
{
}
CHookWindowMap::~CHookWindowMap()
{
//This assert bombs when posting WM_QUIT,so I've deleted it.
//ASSERT(IsEmpty());//all hooks should be removed!
}

CHookWindowMap &CHookWindowMap::GetHookMap()
{
//By creating theMap here,C++doesn't instantiate it until/unless
//it's ever used!This is a good trick to use in C++,to
//instantiate/initialize a static object the first time it's used.
//
    static CHookWindowMap theMap;
    return theMap;
}
/////////////////
//Add hook to map;i.e.,associate hook with window
//
void CHookWindowMap::Add(HWND hwnd,CHookWindowObject *pNewHook)
{
    ASSERT(hwnd&&::IsWindow(hwnd));
//Add to front of list
    pNewHook->m_pNext=Lookup(hwnd);
    SetAt(hwnd,pNewHook);
    if(pNewHook->m_pNext==NULL)
    {
//If this is the first hook added,subclass the window
        pNewHook->m_pOldWndProc=(WNDPROC)SetWindowLong(hwnd,GWL_WNDPROC,(DWORD)HookWndProc);
    }
    else
    {
//just copy wndproc from next hook
        pNewHook->m_pOldWndProc=pNewHook->m_pNext->m_pOldWndProc;
    }
    ASSERT(pNewHook->m_pOldWndProc);
}
//////////////////
//Remove hook from map
//
void CHookWindowMap::Remove(CHookWindowObject *pUnHook)
{
    HWND hwnd=pUnHook->m_hWnd;
    ASSERT(hwnd&&::IsWindow(hwnd));
    CHookWindowObject *pHook=Lookup(hwnd);
    ASSERT(pHook);
    if(pHook==pUnHook)
    {
//hook to remove is the one in the hash table:replace w/next
        if(pHook->m_pNext)
            SetAt(hwnd,pHook->m_pNext);
        else
        {
//This is the last hook for this window:restore wnd proc
            RemoveKey(hwnd);
            SetWindowLong(hwnd,GWL_WNDPROC,(DWORD)pHook->m_pOldWndProc);
        }
    }
    else
    {
//Hook to remove is in the middle:just remove from linked list
        while(pHook->m_pNext!=pUnHook)
            pHook=pHook->m_pNext;
        ASSERT(pHook&&pHook->m_pNext==pUnHook);
        pHook->m_pNext=pUnHook->m_pNext;
    }
}
//////////////////
//Remove all the hooks for a window
//
void CHookWindowMap::RemoveAll(HWND hwnd)
{
    CHookWindowObject*pSubclassWnd;
    while((pSubclassWnd=Lookup(hwnd))!=NULL)
        pSubclassWnd->HookWindow((HWND)NULL);//(unhook)
}

  6、添加全局函数HookWindowProc,代码如下:

LRESULT CALLBACK HookWndProc(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp)
{
#ifdef _USRDLL
//If this is a DLL,need to set up MFC state
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
//Set up MFC message state just in case anyone wants it
//This is just like AfxCallWindowProc,but we can't use that because
//a CHookWindowObject is not a CWnd.
//
    MSG &curMsg=AfxGetThreadState()->m_lastSentMsg;
    MSG oldMsg=curMsg;//save for nesting
    curMsg.hwnd=hwnd;
    curMsg.message=msg;
    curMsg.wParam=wp;
    curMsg.lParam=lp;
//Get hook object for this window.Get from hook map
    CHookWindowObject *pSubclassWnd=theHookMap.Lookup(hwnd);
    ASSERT(pSubclassWnd);
    LRESULT lr;
    if(msg==WM_NCDESTROY)
    {
//Window is being destroyed:unhook all hooks(for this window)
//and pass msg to orginal window proc
//
        WNDPROC wndproc=pSubclassWnd->m_pOldWndProc;
        theHookMap.RemoveAll(hwnd);
        lr=::CallWindowProc(wndproc,hwnd,msg,wp,lp);
    }
    else
    {
//pass to msg hook
        lr=pSubclassWnd->WindowProc(msg,wp,lp);
    }
    curMsg=oldMsg;//pop state
    return lr;
}

  7、添加CHookWindowTipHandler类,HookWindowTipHandler.h代码如下:

#pragma once

#include "HookWindowObject.h"
#include "ToolTipWnd.H"
class CHookWindowTipHandler:public CHookWindowObject
{
protected:
    UINT m_idMyControl;//id of list box control
    UINT m_nCurItem;//index of current item
    BOOL m_bCapture;//whether mouse is captured
    static CToolTipWnd g_wndTip;//THE tip window
//subclass window proc
    virtual LRESULT WindowProc(UINT msg,WPARAM wp,LPARAM lp);
//virtual fns you can override
    virtual void OnMouseMove(CPoint p);
    virtual BOOL IsRectCompletelyVisible(const CRect&rc);
    virtual UINT OnGetItemInfo(CPoint p,CRect&rc,CString&s);
public:
    CHookWindowTipHandler();
    ~CHookWindowTipHandler();
    static UINT g_nTipTimeMsec;//global:msec wait before showing tip
    void Init(CWnd*pListBox);//initialize
};

  HookWindowTipHandler.cpp代码如下:

#include "stdafx.h"
#include "ToolTipWnd.H"
#include "HookWindowTipHandler.h"
#include <afxcoll.h>
#include <windowsx.h>
//THE popup tip window
CToolTipWnd CHookWindowTipHandler::g_wndTip;
//Timeout before showing long listbox tip--you can change
UINT CHookWindowTipHandler::g_nTipTimeMsec=100;//.1 sec

CHookWindowTipHandler::CHookWindowTipHandler()
{
    m_nCurItem=-1;
    m_bCapture=FALSE;
}

CHookWindowTipHandler::~CHookWindowTipHandler()
{
}

//////////////////
//Install hook.Initialize control ID from list box and create
//(invisible)tip window.
//
void CHookWindowTipHandler::Init(CWnd *pListBox)
{
    CHookWindowObject::HookWindow(pListBox);
    m_idMyControl=pListBox->GetDlgCtrlID();
    if(!g_wndTip)
    {
//create scroll tip window
        g_wndTip.Create(CPoint(0,0),pListBox,PTS_TRANSPARENT);
    }
}

LRESULT CHookWindowTipHandler::WindowProc(UINT msg,WPARAM wp,LPARAM lp)
{
    switch(msg)
    {
    case WM_MOUSEMOVE:
        OnMouseMove(CPoint(GET_X_LPARAM(lp),GET_Y_LPARAM(lp)));
        break;
    case WM_LBUTTONDOWN:
        g_wndTip.Cancel();//cancel popup text if any
        break;
    }
    return CHookWindowObject::WindowProc(msg,wp,lp);
}

void CHookWindowTipHandler::OnMouseMove(CPoint pt)
{
    CListBox *pListBox=(CListBox*)CWnd::FromHandle(m_hWnd);
    if(!m_bCapture)
    {
        ::SetCapture(m_hWnd);
        m_bCapture=TRUE;
    }
//Get text and text rectangle for item under mouse
    CString sText;//item text
    CRect rcText;//item text rect
    UINT nItem=OnGetItemInfo(pt,rcText,sText);
    if(nItem==-1||nItem!=m_nCurItem)
    {
        g_wndTip.Cancel();//new item,or no item:cancel popup text
        if(nItem>=0&&!IsRectCompletelyVisible(rcText))
        {
//new item,and not wholly visible:prepare popup tip
            CRect rc=rcText;
            pListBox->ClientToScreen(&rc);//text rect in screen coords
            g_wndTip.SetWindowText(sText);//set tip text to that of item
//move tip window over list text
            g_wndTip.SetWindowPos(NULL,rc.left-3,rc.top,rc.Width()*2,rc.Height()*2,SWP_NOZORDER|SWP_NOACTIVATE);
            g_wndTip.ShowDelayed(g_nTipTimeMsec);//show popup text delayed
        }
    }
    m_nCurItem=nItem;
    if(nItem==-1)
    {
        ::ReleaseCapture();
        m_bCapture=FALSE;
    }
}

BOOL CHookWindowTipHandler::IsRectCompletelyVisible(const CRect&rc)
{
    CListBox *pListBox=(CListBox*)CWnd::FromHandle(m_hWnd);
    CRect rcClient;
    pListBox->GetClientRect(&rcClient);
    return rcClient.Width()>rc.Width();
}

UINT CHookWindowTipHandler::OnGetItemInfo(CPoint p,CRect&rc,CString&s)
{
    CListBox *pListBox=(CListBox*)CWnd::FromHandle(m_hWnd);
    ASSERT_VALID(pListBox);
    BOOL bOutside;
    UINT nItem=pListBox->ItemFromPoint(p,bOutside);
    s.Empty();
    if(!bOutside)
    {
        pListBox->GetText(nItem,s);
        pListBox->GetItemRect(nItem,&rc);
        CFont *pFont=pListBox->GetFont();
        CClientDC dc(pListBox);
        CFont *pOldFont=dc.SelectObject(pFont);
        dc.DrawText(s,&rc,DT_CALCRECT);
        dc.SelectObject(pOldFont);
        return nItem;
    }
    return -1;
}

  8、添加CLinkStatic类,LinkStatic.h代码如下:

#ifndef _STATLINK_H
#define _STATLINK_H

#include "ShellExcuteString.H"
class CLinkStatic:public CStatic
{
public:
    DECLARE_DYNAMIC(CLinkStatic)
    CLinkStatic(LPCTSTR lpText=NULL,BOOL bDeleteOnDestroy=FALSE);
    ~CLinkStatic() {}
    CShellExcuteString m_link;
    COLORREF m_color;

    static COLORREF g_colorUnvisited;
    static COLORREF g_colorVisited;

    static HCURSOR g_hCursorLink;
protected:
    CFont m_font;//underline font for text control
    BOOL m_bDeleteOnDestroy;//delete object when window destroyed?
    virtual void PostNcDestroy();
//message handlers
    DECLARE_MESSAGE_MAP()
    afx_msg UINT OnNcHitTest(CPoint point);
    afx_msg HBRUSH CtlColor(CDC*pDC,UINT nCtlColor);
    afx_msg void OnLButtonDown(UINT nFlags,CPoint point);
    afx_msg BOOL OnSetCursor(CWnd*pWnd,UINT nHitTest,UINT message);
};

#endif _STATLINK_H

  LinkStatic.cpp代码如下:

#include "StdAfx.h"
#include "LinkStatic.H"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

COLORREF CLinkStatic::g_colorUnvisited=RGB(0,0,255);//blue
COLORREF CLinkStatic::g_colorVisited=RGB(128,0,128);//purple
HCURSOR CLinkStatic::g_hCursorLink=NULL;
IMPLEMENT_DYNAMIC(CLinkStatic,CStatic)
BEGIN_MESSAGE_MAP(CLinkStatic,CStatic)
    ON_WM_NCHITTEST()
    ON_WM_CTLCOLOR_REFLECT()
    ON_WM_LBUTTONDOWN()
    ON_WM_SETCURSOR()
END_MESSAGE_MAP()

CLinkStatic::CLinkStatic(LPCTSTR lpText,BOOL bDeleteOnDestroy)
{
    m_link=lpText;//link text(NULL==>window text)
    m_color=g_colorUnvisited;//not visited yet
    m_bDeleteOnDestroy=bDeleteOnDestroy;//delete object with window?
}

UINT CLinkStatic::OnNcHitTest(CPoint point)
{
    return HTCLIENT;
}

HBRUSH CLinkStatic::CtlColor(CDC *pDC,UINT nCtlColor)
{
    ASSERT(nCtlColor==CTLCOLOR_STATIC);
    DWORD dwStyle=GetStyle();
    HBRUSH hbr=NULL;
    if((dwStyle&0xFF)<=SS_RIGHT)
    {
//this is a text control:set up font and colors
        if(!(HFONT)m_font)
        {
//first time init:create font
            LOGFONT lf;
            GetFont()->GetObject(sizeof(lf),&lf);
            lf.lfUnderline=TRUE;
            m_font.CreateFontIndirect(&lf);
        }
//use underline font and visited/unvisited colors
        pDC->SelectObject(&m_font);
        pDC->SetTextColor(m_color);
        pDC->SetBkMode(TRANSPARENT);
//return hollow brush to preserve parent background color
        hbr=(HBRUSH)::GetStockObject(HOLLOW_BRUSH);
    }
    return hbr;
}

void CLinkStatic::OnLButtonDown(UINT nFlags,CPoint point)
{
    if(m_link.IsEmpty())
    {
//no link:try to load from resource string or window text
        m_link.LoadString(GetDlgCtrlID())||(GetWindowText(m_link),1);
        if(m_link.IsEmpty())
            return;
    }

    HINSTANCE h=m_link.Navigate();
    if((UINT)h>32) //success!
    {
        m_color=g_colorVisited;//change color
        Invalidate();//repaint
    }
    else
    {
        MessageBeep(0);//unable to execute file!
        TRACE(_T("***WARNING:CLinkStatic:unable to navigate link%sn"),(LPCTSTR)m_link);
    }
}

BOOL CLinkStatic::OnSetCursor(CWnd *pWnd,UINT nHitTest,UINT message)
{
    if(g_hCursorLink==NULL)
    {
        static bTriedOnce=FALSE;
        if(!bTriedOnce)
        {
            CString windir;
            GetWindowsDirectory(windir.GetBuffer(MAX_PATH),MAX_PATH);
            windir.ReleaseBuffer();
            windir+=_T("\winhlp32.exe");
            HMODULE hModule=LoadLibrary(windir);
            if(hModule)
            {
                g_hCursorLink=CopyCursor(::LoadCursor(hModule,MAKEINTRESOURCE(106)));
            }
            FreeLibrary(hModule);
            bTriedOnce=TRUE;
        }
    }
    if(g_hCursorLink)
    {
        ::SetCursor(g_hCursorLink);
        return TRUE;
    }
    return FALSE;
}

void CLinkStatic::PostNcDestroy()
{
    if(m_bDeleteOnDestroy)
        delete this;
}

  9、添加CToolTipWnd类,ToolTipWnd.h代码如下:

class CToolTipWnd:public CWnd
{
public:
    CSize m_szMargins;//extra space around text:change if you like
	CFont m_font;
    CToolTipWnd();
    virtual ~CToolTipWnd();
    BOOL Create(CPoint pt,CWnd *pParentWnd,UINT nStyle=0,UINT nID=0);
    void ShowDelayed(UINT msec);
    void Cancel();
protected:
    UINT m_nStyle;//style(see below)
    virtual void PostNcDestroy();
    virtual BOOL PreCreateWindow(CREATESTRUCT &cs);
    void DrawText(CDC &dc,LPCTSTR lpText,CRect &rc,UINT flags);
    afx_msg UINT OnNcHitTest(CPoint pt);
    afx_msg void OnPaint();
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg LRESULT OnSetText(WPARAM wp,LPARAM lp);
    DECLARE_DYNAMIC(CToolTipWnd);
    DECLARE_MESSAGE_MAP();
};
#define PTS_JUSTIFYLEFT 0x0000
#define PTS_JUSTIFYRIGHT 0x0001
#define PTS_TRANSPARENT 0x0002

  ToolTipWnd.cpp代码如下:

#include "stdafx.h"
#include "ToolTipWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
IMPLEMENT_DYNAMIC(CToolTipWnd,CWnd)
BEGIN_MESSAGE_MAP(CToolTipWnd,CWnd)
    ON_WM_NCHITTEST()
    ON_WM_PAINT()
    ON_MESSAGE(WM_SETTEXT,OnSetText)
    ON_WM_TIMER()
END_MESSAGE_MAP()
CToolTipWnd::CToolTipWnd()
{
    m_szMargins=CSize(4,4);
	m_font.CreateFont(24,0,0,0,FW_NORMAL,0,0,0,1,0,0,0,0,"微软雅黑");
}
CToolTipWnd::~CToolTipWnd()
{
}

int CToolTipWnd::Create(CPoint pt,CWnd *pParentWnd,UINT nStyle,UINT nID)
{
    m_nStyle=nStyle;
    return CreateEx(0,
                    NULL,
                    NULL,
                    WS_POPUP|WS_VISIBLE,
                    CRect(pt,CSize(0,0)),
                    pParentWnd,
                    nID);
}
UINT CToolTipWnd::OnNcHitTest(CPoint pt)
{
    if(m_nStyle&PTS_TRANSPARENT)//transparent?
        return HTTRANSPARENT;//..make it so
    return CWnd::OnNcHitTest(pt);//otherwise return default
}

LRESULT CToolTipWnd::OnSetText(WPARAM wp,LPARAM lp)
{
    CRect rc;
    GetWindowRect(&rc);
    int x=(m_nStyle&PTS_JUSTIFYRIGHT)?rc.right:rc.left;
    int y=rc.top;
    CClientDC dc=this;
    DrawText(dc,CString((LPCTSTR)lp),rc,DT_CALCRECT);
    rc.InflateRect(m_szMargins);
    //if(m_nStyle&PTS_JUSTIFYRIGHT)
    //{
    //    x-=rc.Width();
    //}
    //SetWindowPos(NULL,x,y,rc.Width(),rc.Height(),SWP_NOZORDER|SWP_NOACTIVATE);
    return Default();
}

void CToolTipWnd::DrawText(CDC &dc,LPCTSTR lpText,CRect &rc,UINT flags)
{
	CBitmap bmp;
	bmp.LoadBitmap(IDB_BITMAP1);
    //CBrush b(GetSysColor(COLOR_INFOBK));//use tooltip bg color
	CBrush br;
	br.CreatePatternBrush(&bmp);
    dc.FillRect(&rc,&br);
    dc.SetBkMode(TRANSPARENT);
    //dc.SetTextColor(GetSysColor(COLOR_INFOTEXT));//tooltip text color
	dc.SetTextColor(RGB(0xFF,0,0));
    //CFont *pOldFont=dc.SelectObject(GetParent()->GetFont());
	CFont *pOldFont=dc.SelectObject(&m_font);
    dc.DrawText(lpText,&rc,flags);
    dc.SelectObject(pOldFont);
}

void CToolTipWnd::OnPaint()
{
    CRect rc;
    GetClientRect(&rc);
    CString s;
    GetWindowText(s);
    CPaintDC dc(this);
    DrawText(dc,s,rc,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
}

BOOL CToolTipWnd::PreCreateWindow(CREATESTRUCT&cs)
{
    static CString sClassName;
    if(sClassName.IsEmpty())
        sClassName=AfxRegisterWndClass(0);
    cs.lpszClass=sClassName;
    cs.style=WS_POPUP|WS_BORDER;
    cs.dwExStyle|=WS_EX_TOOLWINDOW;
    return CWnd::PreCreateWindow(cs);
}

void CToolTipWnd::PostNcDestroy()
{
//don't delete this
}

void CToolTipWnd::ShowDelayed(UINT msec)
{
    if(msec==0)
    {
//no delay:show it now
        OnTimer(1);
    }
    else
    {
//delay:set time
        SetTimer(1,msec,NULL);
    }
}

void CToolTipWnd::Cancel()
{
    KillTimer(1);
    ShowWindow(SW_HIDE);
}

void CToolTipWnd::OnTimer(UINT nIDEvent)
{
    ShowWindow(SW_SHOWNA);
    Invalidate();
    UpdateWindow();
    KillTimer(1);
}

  10、添加CNonClientMetrics,代码写在ToolTipWnd.h头部,代码如下:

class CNonClientMetrics:public NONCLIENTMETRICS
{
public:
    CNonClientMetrics()
    {
        cbSize=sizeof(NONCLIENTMETRICS);
        SystemParametersInfo(SPI_GETNONCLIENTMETRICS,0,this,0);
    }
};

  11、添加一张位图,资源代号是:IDB_BITMAP1。

  12、在对话框的InitDialog里添加初始化ListBox的代码:

static LPCTSTR STRINGS[] = 
	{
		"来是空言去绝踪,",
		"月斜楼上五更钟。梦为远别啼难唤,",
		"书被催成墨未浓。蜡照半笼金翡翠,麝熏微度绣芙蓉。",
		"刘郎已恨蓬山远,",
		"更隔蓬山一万重。昨夜星辰昨夜风,",
		"画楼西畔桂堂东。身无彩凤双飞翼,心有灵犀一点通。",
		"隔座送钩春酒暖,"
		"分曹射覆蜡灯红。嗟余听鼓应官去,走马兰台类转蓬。",
		NULL
	};
	for (int i=0; STRINGS[i]; i++) 
	{
		m_wndListBox.AddString(STRINGS[i]);
	}
	m_tipHandler.Init(&m_wndListBox);
	m_wndListBox.SetFocus();
	m_wndLink1.m_link = _T("http://www.vckbase.com");
	m_wndLink2.m_link = _T("mailto:jiayuxiaosheng@yeah.net");
	m_wndLink1.SubclassDlgItem(IDC_VCKBASE, this);
	m_wndLink2.SubclassDlgItem(IDC_MAIL, this);

【效果】

  好了,大功告成,运行效果截图:

给CListBox增加个性化的ToolTip

原文链接: https://www.cnblogs.com/xuesongshu/archive/2013/04/24/tooltip.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    给CListBox增加个性化的ToolTip

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/85843

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月9日 下午10:16
下一篇 2023年2月9日 下午10:17

相关推荐