半透明信息显示浮动窗口的实现

实现目的

       在一些画图软件中,经常需要向用户展示鼠标移动到的位置的对象的一些参数信息。此时,完成一个交互性友好的信息显示界面就相当的重要了。因为一个软件的好坏,在用户的眼中,第一感觉甚至是第一重要的就是视觉效果和可操作性。当然,软件本身的稳定性和效率也很重要。特别对于产品性的软件,在用户展示时,一个优秀的界面效果可以大大加深软件在用户心里的印象分。

       功能简介

       本功能是作者根据自身软件在用户实际使用过程中对交互性的更高要求而开发的。浮动窗口其实是一个对话框,设置为无标题的风格,然后进行自绘制而成。能够根据需要显示的内容自动调整窗口的大小,保证正好能够容纳需要显示的内容。如以下效果:

 


       图中黄色条为栏目分隔,同时显示其下内容所属的信息域。如图中表示下方信息为台风即时预报信息的内容。下方信息分成两栏,栏间绘制线条进行分割。左侧为信息标题,右侧为信息内容。比如台风名称是奥麦斯。

       如果鼠标移动的位置,同时选中多项内容,那么,提示信息可以同时包括多个栏目,如下图:

 

       本图中包括两个栏目,即本公司船位置信息和美气导的等压线信息。从理论上讲,本功能可以支持任意多的栏目,前提是你的显示器能够容纳得下。

       整个界面的效果是半透明的。包括透明度,字体大小和信息内容的颜色都可以由用户自行定义,配置界面如下:

 

       透明度范围为0-255;背景色列表框是作者在博客中已提供的一个自定义的线条、填充和颜色选择列表控件。

       修改完成后,可以改变浮动窗口的显示效果,比如一种修改后的效果:

 

       这样,即使用户对浮动窗口内容的展示方式不满意,那么也完全可以由用户自行定义自己喜欢的风格。当然,在此基础上,可以进一步扩大自定义的范围。本例中,栏目分割条的背景色和信息内容标题文字的颜色是固定的,信息内容文字的颜色是背景色的反色,这些都可以考虑加入到自定义项中。


代码实现


以下是消息提示项的数据结构:

view plaincopy to clipboardprint?
typedef struct _MSG_TIP//消息提示数据项描述信息  
 
{  
 
       CString sMsgItemName;                  //信息标题  
 
       CString sMsgItemInfo;               //信息内容  
 
       COLORREF nInfoShowColor; //显示颜色(此项值目前暂时没有使用,原意是使每个栏目的文字颜色均可自定义;因为考虑到设定的颜色可能和背景色冲突,因此目前文字颜色使用背景色的反色)  
 
}MSG_TIP;  
 
typedef CArray CMsgTipArray;//消息提示内容 
typedef struct _MSG_TIP//消息提示数据项描述信息

{

       CString sMsgItemName;                  //信息标题

       CString sMsgItemInfo;               //信息内容

       COLORREF nInfoShowColor; //显示颜色(此项值目前暂时没有使用,原意是使每个栏目的文字颜色均可自定义;因为考虑到设定的颜色可能和背景色冲突,因此目前文字颜色使用背景色的反色)

}MSG_TIP;

typedef CArray CMsgTipArray;//消息提示内容
 

 

头文件,MsgTipDlg.h


view plaincopy to clipboardprint?
#if !defined(AFX_MSGTIPDLG_H__9759E9A8_93DE_4003_BCB2_87F390641270__INCLUDED_)  
#define AFX_MSGTIPDLG_H__9759E9A8_93DE_4003_BCB2_87F390641270__INCLUDED_  
 
#if _MSC_VER > 1000  
#pragma once  
#endif // _MSC_VER > 1000  
// MsgTipDlg.h : header file  
//  
 
/////////////////////////////////////////////////////////////////////////////  
// CMsgTipDlg dialog  
 
class CMsgTipDlg : public CDialog  
{  
// Construction  
public:  
    CMsgTipDlg(CWnd* pParent = NULL);   // standard constructor  
    CSize ShowMsgTip(CMsgTipArray &arMsgTip); //供外部函数传递需要显示的内容,并计算尺寸  
    void UpdateTrans();     //修改透明度等配置参数      
    void DrawMsgTip();      //绘制提示信息  
// Dialog Data  
    //{{AFX_DATA(CMsgTipDlg)  
    enum { IDD = IDD_MSGTIP_DLG };  
    //}}AFX_DATA  
 
// Overrides  
    // ClassWizard generated virtual function overrides  
    //{{AFX_VIRTUAL(CMsgTipDlg)  
    public:  
    virtual BOOL PreTranslateMessage(MSG* pMsg);  
    protected:  
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support  
    //}}AFX_VIRTUAL  
 
// Implementation  
protected:  
    CMsgTipArray m_arMsgTip;    //提示信息数组  
    CFont   m_MsgTipFont;       //用于消息提示的字体  
    int     m_nTipNameWidth;    //标题名最大宽度,决定竖线绘制位置  
    int     m_nRowHeight;       //行高,决定横线绘制位置  
private:  
    void DrawGrid(CDC *pDC,CRect &rc);                      //绘制网格  
    void DrawMsgTip(CDC *pDC,CPoint topPos,MSG_TIP &mt);    //绘制提示信息(某一条)  
    void DrawMsg(CDC *pDC);                                 //绘制信息  
      
    // Generated message map functions  
    //{{AFX_MSG(CMsgTipDlg)  
    virtual BOOL OnInitDialog();  
    afx_msg void OnPaint();  
    //}}AFX_MSG  
    DECLARE_MESSAGE_MAP()  
};  
 
//{{AFX_INSERT_LOCATION}}  
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.  
 
#endif // !defined(AFX_MSGTIPDLG_H__9759E9A8_93DE_4003_BCB2_87F390641270__INCLUDED_) 
#if !defined(AFX_MSGTIPDLG_H__9759E9A8_93DE_4003_BCB2_87F390641270__INCLUDED_)
#define AFX_MSGTIPDLG_H__9759E9A8_93DE_4003_BCB2_87F390641270__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MsgTipDlg.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CMsgTipDlg dialog

class CMsgTipDlg : public CDialog
{
// Construction
public:
 CMsgTipDlg(CWnd* pParent = NULL);   // standard constructor
 CSize ShowMsgTip(CMsgTipArray &arMsgTip); //供外部函数传递需要显示的内容,并计算尺寸
 void UpdateTrans();  //修改透明度等配置参数 
 void DrawMsgTip();  //绘制提示信息
// Dialog Data
 //{{AFX_DATA(CMsgTipDlg)
 enum { IDD = IDD_MSGTIP_DLG };
 //}}AFX_DATA

// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CMsgTipDlg)
 public:
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 protected:
 virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
 //}}AFX_VIRTUAL

// Implementation
protected:
 CMsgTipArray m_arMsgTip; //提示信息数组
 CFont   m_MsgTipFont;  //用于消息提示的字体
 int  m_nTipNameWidth; //标题名最大宽度,决定竖线绘制位置
 int  m_nRowHeight;  //行高,决定横线绘制位置
private:
 void DrawGrid(CDC *pDC,CRect &rc);      //绘制网格
 void DrawMsgTip(CDC *pDC,CPoint topPos,MSG_TIP &mt); //绘制提示信息(某一条)
 void DrawMsg(CDC *pDC);         //绘制信息
 
 // Generated message map functions
 //{{AFX_MSG(CMsgTipDlg)
 virtual BOOL OnInitDialog();
 afx_msg void OnPaint();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_MSGTIPDLG_H__9759E9A8_93DE_4003_BCB2_87F390641270__INCLUDED_)
 

CPP文件,MsgTipDlg.cpp

view plaincopy to clipboardprint?
// MsgTipDlg.cpp : implementation file  
//  
 
#include "stdafx.h"  
#include "MsgTipDlg.h"  
 
#ifdef _DEBUG  
#define new DEBUG_NEW  
#undef THIS_FILE  
static char THIS_FILE[] = __FILE__;  
#endif  
 
/////////////////////////////////////////////////////////////////////////////  
// CMsgTipDlg dialog  
 
 
CMsgTipDlg::CMsgTipDlg(CWnd* pParent /*=NULL*/)  
    : CDialog(CMsgTipDlg::IDD, pParent)  
{  
    //{{AFX_DATA_INIT(CMsgTipDlg)  
    //}}AFX_DATA_INIT  
}  
 
 
void CMsgTipDlg::DoDataExchange(CDataExchange* pDX)  
{  
    CDialog::DoDataExchange(pDX);  
    //{{AFX_DATA_MAP(CMsgTipDlg)  
    //}}AFX_DATA_MAP  
}  
 
 
BEGIN_MESSAGE_MAP(CMsgTipDlg, CDialog)  
    //{{AFX_MSG_MAP(CMsgTipDlg)  
    ON_WM_PAINT()  
    //}}AFX_MSG_MAP  
END_MESSAGE_MAP()  
 
/////////////////////////////////////////////////////////////////////////////  
// CMsgTipDlg message handlers  
 
BOOL CMsgTipDlg::OnInitDialog()   
{  
    CDialog::OnInitDialog();  
    m_MsgTipFont.CreateFont(  
        theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipFontSize,// nHeight  
        0,                         // nWidth  
        0,                         // nEscapement  
        0,                         // nOrientation  
        FW_SEMIBOLD,                  // nWeight  
        FALSE,                     // bItalic  
        FALSE,                     // bUnderline  
        0,                         // cStrikeOut  
        DEFAULT_CHARSET,              // nCharSet  
        OUT_DEFAULT_PRECIS,        // nOutPrecision  
        CLIP_DEFAULT_PRECIS,       // nClipPrecision  
        DEFAULT_QUALITY,           // nQuality  
        DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily  
        "Times New Roman");//"MS Sans Serif");//Arial  
    m_nTipNameWidth = 0;  
    m_nRowHeight = 0;     
      
    SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,  
    GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);  
    //WS_EX_LAYERED  
    HINSTANCE hInst = LoadLibrary("User32.DLL");   
    if(hInst)   
    {   
        typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);   
        MYFUNC fun = NULL;  
        //取得SetLayeredWindowAttributes函数指针   
        fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");  
        if(fun)  
            //fun(this->GetSafeHwnd(),0,400,2);   
            fun(this->GetSafeHwnd(),0,theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipTrans,2);  
        FreeLibrary(hInst);   
    }  
 
    return TRUE;  // return TRUE unless you set the focus to a control  
                  // EXCEPTION: OCX Property Pages should return FALSE  
}  
 
//供外部函数传递需要显示的内容,同时获得需要显示的内容的尺寸,以决定本界面的大小  
CSize CMsgTipDlg::ShowMsgTip(CMsgTipArray &arMsgTip)  
{  
    CSize size(0,0);  
    //////////////////////////////////////  
    m_arMsgTip.Copy(arMsgTip);  
 
    int nSize = m_arMsgTip.GetSize();  
    if(nSize == 0)  
        return size;  
 
    CDC *pDC = GetDC();  
    pDC->SelectObject(&m_MsgTipFont);  
    int nMaxNameLen = 0;  
    int nMaxInfoLen = 0;  
    int nMaxTitleLen = 0;  
    CSize sz;  
    for(int i=0; i    {  
        MSG_TIP mt = m_arMsgTip.GetAt(i);  
        if(mt.nInfoShowColor == -1)  
        {  
            ::GetTextExtentPoint32(pDC->m_hDC, mt.sMsgItemName,mt.sMsgItemName.GetLength(),&sz);  
            if(sz.cx > nMaxTitleLen)  
                nMaxTitleLen = sz.cx;  
            continue;  
        }  
        ::GetTextExtentPoint32(pDC->m_hDC, mt.sMsgItemName,mt.sMsgItemName.GetLength(),&sz);  
        if(sz.cx > nMaxNameLen)  
            nMaxNameLen = sz.cx;  
        if(mt.sMsgItemInfo.GetLength() == 0)  
            continue;  
        else 
        {  
            ::GetTextExtentPoint32(pDC->m_hDC, mt.sMsgItemInfo,mt.sMsgItemInfo.GetLength(),&sz);  
            if(sz.cx > nMaxInfoLen)  
                nMaxInfoLen = sz.cx;  
        }  
 
    }  
    m_nTipNameWidth = nMaxNameLen + 8;  
    m_nRowHeight = sz.cy + 4;  
    //  
    int nTitleWidth = nMaxTitleLen;  
    size.cx = m_nTipNameWidth + nMaxInfoLen+5;  
    if(size.cx < nTitleWidth)  
        size.cx = nTitleWidth;  
    size.cx += 5;  
    size.cy = m_nRowHeight * nSize;  
    ReleaseDC(pDC);  
    return size;  
}  
 
void CMsgTipDlg::OnPaint()   
{  
    CPaintDC dc(this); // device context for painting  
      
    DrawMsg(&dc);  
      
    // Do not call CDialog::OnPaint() for painting messages  
}  
 
void CMsgTipDlg::DrawMsg(CDC *pDC)  
{  
    CRect rc;  
    GetClientRect(&rc);  
    CDC memDC;  
    memDC.CreateCompatibleDC(pDC);  
    CBitmap bmp;  
    bmp.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());  
    CBitmap *pOldBmp = memDC.SelectObject(&bmp);  
    memDC.FillSolidRect(rc,theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipBkColor);  
    CFont *pOldFont = memDC.SelectObject(&m_MsgTipFont);  
      
    DrawGrid(&memDC,rc);  
    //  
    int nSize = m_arMsgTip.GetSize();  
    CPoint topPos(0,0);  
    for(int i=0; i    {  
        MSG_TIP mt = m_arMsgTip.GetAt(i);  
        DrawMsgTip(&memDC,topPos,mt);  
        topPos.y += m_nRowHeight;  
    }  
    pDC->BitBlt(0, 0, rc.Width(),rc.Height(), &memDC, 0, 0, SRCCOPY) ;  
    pDC->SelectObject(pOldBmp);  
    pDC->SelectObject(pOldFont);  
    bmp.DeleteObject();  
    memDC.DeleteDC();  
}  
 
void CMsgTipDlg::DrawMsgTip(CDC *pDC, CPoint topPos, MSG_TIP &mt)  
{  
    int nBkMode = pDC->SetBkMode(TRANSPARENT);  
    if(mt.nInfoShowColor == -1)  
    {  
        CRect rc;  
        GetClientRect(&rc);  
        CRect rowRc(topPos,CSize(rc.Width(),m_nRowHeight+2));  
        pDC->FillSolidRect(rowRc,COLOR_BUFF);  
        COLORREF nTC = pDC->SetTextColor(COLOR_MAGENTA);  
        pDC->TextOut(topPos.x+4,topPos.y+4,mt.sMsgItemName);  
        pDC->SetTextColor(nTC);  
    }  
    else 
    {  
        COLORREF nTC = pDC->SetTextColor(COLOR_MAGENTA);  
        pDC->TextOut(topPos.x+4,topPos.y+4,mt.sMsgItemName);  
        nTC = pDC->SetTextColor(COLOR_WHITE-theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipBkColor);//mt.nInfoShowColor);//  
        pDC->TextOut(topPos.x+m_nTipNameWidth+8,topPos.y+4,mt.sMsgItemInfo);  
        pDC->SetTextColor(nTC);  
    }  
    pDC->SetBkMode(nBkMode);  
}  
 
void CMsgTipDlg::DrawGrid(CDC *pDC,CRect &rc)  
{  
    CPen pen(PS_SOLID,1,COLOR_BUFF);  
    CPen *pOldPen = pDC->SelectObject(&pen);  
    CPoint ptTop(m_nTipNameWidth,0);  
    CPoint ptBottom(m_nTipNameWidth,rc.bottom);  
    pDC->MoveTo(ptTop);  
    pDC->LineTo(ptBottom);  
    //  
    int nSize = m_arMsgTip.GetSize();  
    for(int i=0; i    {  
        CPoint ptLeft(0,(m_nRowHeight)*(i+1)+2);  
        CPoint ptRight(rc.right,(m_nRowHeight)*(i+1)+2);  
        pDC->MoveTo(ptLeft);  
        pDC->LineTo(ptRight);  
    }  
    pDC->SelectObject(pOldPen);  
}  
 
void CMsgTipDlg::UpdateTrans()  
{  
    HINSTANCE hInst = LoadLibrary("User32.DLL");   
    if(hInst)   
    {   
        typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);   
        MYFUNC fun = NULL;  
        //取得SetLayeredWindowAttributes函数指针   
        fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");  
        if(fun)  
            //fun(this->GetSafeHwnd(),0,400,2);   
            fun(this->GetSafeHwnd(),0,theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipTrans,2);  
        FreeLibrary(hInst);   
    }  
    if(m_MsgTipFont.m_hObject != NULL)  
    {  
        m_MsgTipFont.DeleteObject();  
        m_MsgTipFont.CreateFont(  
            theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipFontSize,// nHeight  
            0,                         // nWidth  
            0,                         // nEscapement  
            0,                         // nOrientation  
            FW_SEMIBOLD,                  // nWeight  
            FALSE,                     // bItalic  
            FALSE,                     // bUnderline  
            0,                         // cStrikeOut  
            DEFAULT_CHARSET,              // nCharSet  
            OUT_DEFAULT_PRECIS,        // nOutPrecision  
            CLIP_DEFAULT_PRECIS,       // nClipPrecision  
            DEFAULT_QUALITY,           // nQuality  
            DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily  
            "Times New Roman");//Arial  }  
    }  
}  
 
void CMsgTipDlg::DrawMsgTip()  
{  
    CDC *pDC = GetDC();  
    DrawMsg(pDC);  
    ReleaseDC(pDC);  
}  
 
//鼠标不能移动到本界面,一旦移动到本界面,立即隐藏  
BOOL CMsgTipDlg::PreTranslateMessage(MSG* pMsg)   
{  
    if(pMsg->message == WM_MOUSEMOVE)  
    {  
        ShowWindow(SW_HIDE);  
    }  
    return CDialog::PreTranslateMessage(pMsg);  

// MsgTipDlg.cpp : implementation file
//

#include "stdafx.h"
#include "MsgTipDlg.h"

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

/////////////////////////////////////////////////////////////////////////////
// CMsgTipDlg dialog


CMsgTipDlg::CMsgTipDlg(CWnd* pParent /*=NULL*/)
 : CDialog(CMsgTipDlg::IDD, pParent)
{
 //{{AFX_DATA_INIT(CMsgTipDlg)
 //}}AFX_DATA_INIT
}


void CMsgTipDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CMsgTipDlg)
 //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CMsgTipDlg, CDialog)
 //{{AFX_MSG_MAP(CMsgTipDlg)
 ON_WM_PAINT()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMsgTipDlg message handlers

BOOL CMsgTipDlg::OnInitDialog()
{
 CDialog::OnInitDialog();
 m_MsgTipFont.CreateFont(
  theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipFontSize,// nHeight
  0,                         // nWidth
  0,                         // nEscapement
  0,                         // nOrientation
  FW_SEMIBOLD,                  // nWeight
  FALSE,                     // bItalic
  FALSE,                     // bUnderline
  0,                         // cStrikeOut
  DEFAULT_CHARSET,              // nCharSet
  OUT_DEFAULT_PRECIS,        // nOutPrecision
  CLIP_DEFAULT_PRECIS,       // nClipPrecision
  DEFAULT_QUALITY,           // nQuality
  DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
  "Times New Roman");//"MS Sans Serif");//Arial
 m_nTipNameWidth = 0;
 m_nRowHeight = 0; 
 
 SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,
 GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
 //WS_EX_LAYERED
 HINSTANCE hInst = LoadLibrary("User32.DLL");
 if(hInst)
 {
  typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
  MYFUNC fun = NULL;
  //取得SetLayeredWindowAttributes函数指针
  fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
  if(fun)
   //fun(this->GetSafeHwnd(),0,400,2);
   fun(this->GetSafeHwnd(),0,theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipTrans,2);
  FreeLibrary(hInst);
 }

 return TRUE;  // return TRUE unless you set the focus to a control
               // EXCEPTION: OCX Property Pages should return FALSE
}

//供外部函数传递需要显示的内容,同时获得需要显示的内容的尺寸,以决定本界面的大小
CSize CMsgTipDlg::ShowMsgTip(CMsgTipArray &arMsgTip)
{
 CSize size(0,0);
 //////////////////////////////////////
 m_arMsgTip.Copy(arMsgTip);

 int nSize = m_arMsgTip.GetSize();
 if(nSize == 0)
  return size;

 CDC *pDC = GetDC();
 pDC->SelectObject(&m_MsgTipFont);
 int nMaxNameLen = 0;
 int nMaxInfoLen = 0;
 int nMaxTitleLen = 0;
 CSize sz;
 for(int i=0; i {
  MSG_TIP mt = m_arMsgTip.GetAt(i);
  if(mt.nInfoShowColor == -1)
  {
   ::GetTextExtentPoint32(pDC->m_hDC, mt.sMsgItemName,mt.sMsgItemName.GetLength(),&sz);
   if(sz.cx > nMaxTitleLen)
    nMaxTitleLen = sz.cx;
   continue;
  }
  ::GetTextExtentPoint32(pDC->m_hDC, mt.sMsgItemName,mt.sMsgItemName.GetLength(),&sz);
  if(sz.cx > nMaxNameLen)
   nMaxNameLen = sz.cx;
  if(mt.sMsgItemInfo.GetLength() == 0)
   continue;
  else
  {
   ::GetTextExtentPoint32(pDC->m_hDC, mt.sMsgItemInfo,mt.sMsgItemInfo.GetLength(),&sz);
   if(sz.cx > nMaxInfoLen)
    nMaxInfoLen = sz.cx;
  }

 }
 m_nTipNameWidth = nMaxNameLen + 8;
 m_nRowHeight = sz.cy + 4;
 //
 int nTitleWidth = nMaxTitleLen;
 size.cx = m_nTipNameWidth + nMaxInfoLen+5;
 if(size.cx < nTitleWidth)
  size.cx = nTitleWidth;
 size.cx += 5;
 size.cy = m_nRowHeight * nSize;
 ReleaseDC(pDC);
 return size;
}

void CMsgTipDlg::OnPaint()
{
 CPaintDC dc(this); // device context for painting
 
 DrawMsg(&dc);
 
 // Do not call CDialog::OnPaint() for painting messages
}

void CMsgTipDlg::DrawMsg(CDC *pDC)
{
 CRect rc;
 GetClientRect(&rc);
 CDC memDC;
 memDC.CreateCompatibleDC(pDC);
 CBitmap bmp;
 bmp.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height());
 CBitmap *pOldBmp = memDC.SelectObject(&bmp);
 memDC.FillSolidRect(rc,theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipBkColor);
 CFont *pOldFont = memDC.SelectObject(&m_MsgTipFont);
 
 DrawGrid(&memDC,rc);
 //
 int nSize = m_arMsgTip.GetSize();
 CPoint topPos(0,0);
 for(int i=0; i {
  MSG_TIP mt = m_arMsgTip.GetAt(i);
  DrawMsgTip(&memDC,topPos,mt);
  topPos.y += m_nRowHeight;
 }
 pDC->BitBlt(0, 0, rc.Width(),rc.Height(), &memDC, 0, 0, SRCCOPY) ;
 pDC->SelectObject(pOldBmp);
 pDC->SelectObject(pOldFont);
 bmp.DeleteObject();
 memDC.DeleteDC();
}

void CMsgTipDlg::DrawMsgTip(CDC *pDC, CPoint topPos, MSG_TIP &mt)
{
 int nBkMode = pDC->SetBkMode(TRANSPARENT);
 if(mt.nInfoShowColor == -1)
 {
  CRect rc;
  GetClientRect(&rc);
  CRect rowRc(topPos,CSize(rc.Width(),m_nRowHeight+2));
  pDC->FillSolidRect(rowRc,COLOR_BUFF);
  COLORREF nTC = pDC->SetTextColor(COLOR_MAGENTA);
  pDC->TextOut(topPos.x+4,topPos.y+4,mt.sMsgItemName);
  pDC->SetTextColor(nTC);
 }
 else
 {
  COLORREF nTC = pDC->SetTextColor(COLOR_MAGENTA);
  pDC->TextOut(topPos.x+4,topPos.y+4,mt.sMsgItemName);
  nTC = pDC->SetTextColor(COLOR_WHITE-theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipBkColor);//mt.nInfoShowColor);//
  pDC->TextOut(topPos.x+m_nTipNameWidth+8,topPos.y+4,mt.sMsgItemInfo);
  pDC->SetTextColor(nTC);
 }
 pDC->SetBkMode(nBkMode);
}

void CMsgTipDlg::DrawGrid(CDC *pDC,CRect &rc)
{
 CPen pen(PS_SOLID,1,COLOR_BUFF);
 CPen *pOldPen = pDC->SelectObject(&pen);
 CPoint ptTop(m_nTipNameWidth,0);
 CPoint ptBottom(m_nTipNameWidth,rc.bottom);
 pDC->MoveTo(ptTop);
 pDC->LineTo(ptBottom);
 //
 int nSize = m_arMsgTip.GetSize();
 for(int i=0; i {
  CPoint ptLeft(0,(m_nRowHeight)*(i+1)+2);
  CPoint ptRight(rc.right,(m_nRowHeight)*(i+1)+2);
  pDC->MoveTo(ptLeft);
  pDC->LineTo(ptRight);
 }
 pDC->SelectObject(pOldPen);
}

void CMsgTipDlg::UpdateTrans()
{
 HINSTANCE hInst = LoadLibrary("User32.DLL");
 if(hInst)
 {
  typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);
  MYFUNC fun = NULL;
  //取得SetLayeredWindowAttributes函数指针
  fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");
  if(fun)
   //fun(this->GetSafeHwnd(),0,400,2);
   fun(this->GetSafeHwnd(),0,theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipTrans,2);
  FreeLibrary(hInst);
 }
 if(m_MsgTipFont.m_hObject != NULL)
 {
  m_MsgTipFont.DeleteObject();
  m_MsgTipFont.CreateFont(
   theApp.m_sysINIFile.GetMsgTipConfig().nMsgTipFontSize,// nHeight
   0,                         // nWidth
   0,                         // nEscapement
   0,                         // nOrientation
   FW_SEMIBOLD,                  // nWeight
   FALSE,                     // bItalic
   FALSE,                     // bUnderline
   0,                         // cStrikeOut
   DEFAULT_CHARSET,              // nCharSet
   OUT_DEFAULT_PRECIS,        // nOutPrecision
   CLIP_DEFAULT_PRECIS,       // nClipPrecision
   DEFAULT_QUALITY,           // nQuality
   DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
   "Times New Roman");//Arial }
 }
}

void CMsgTipDlg::DrawMsgTip()
{
 CDC *pDC = GetDC();
 DrawMsg(pDC);
 ReleaseDC(pDC);
}

//鼠标不能移动到本界面,一旦移动到本界面,立即隐藏
BOOL CMsgTipDlg::PreTranslateMessage(MSG* pMsg)
{
 if(pMsg->message == WM_MOUSEMOVE)
 {
  ShowWindow(SW_HIDE);
 }
 return CDialog::PreTranslateMessage(pMsg);
}
 

外部调用:

view plaincopy to clipboardprint?
//显示提示信息  
void CPetrelProView::ShowMsgTip(BOOL bShow,CMsgTipArray &arMsgTip)  
{  
    if(m_pMsgTipDlg == NULL)  
    {  
        m_pMsgTipDlg = new CMsgTipDlg();  
        m_pMsgTipDlg->Create(IDD_MSGTIP_DLG,this);  
    }  
    if(!bShow)  
    {  
        m_pMsgTipDlg->ShowWindow(SW_HIDE);  
    }  
    else 
    {  
        CSize size = m_pMsgTipDlg->ShowMsgTip(arMsgTip);  
        if(size.cx == 0)  
            return;  
        CPoint pt;  
        GetCursorPos(&pt);  
        CRect rc(pt,size);  
        rc.OffsetRect(15,20);  
        CRect mRc;  
        GetWindowRect(&mRc);  
        if(rc.bottom > mRc.bottom)  
            rc.OffsetRect(0,mRc.bottom-rc.bottom-5);  
        if(rc.right > mRc.right)  
        {  
            rc.OffsetRect(-rc.Width()-30,0);  
        }  
        m_pMsgTipDlg->SetWindowPos(&wndTop,rc.left,rc.top,rc.Width(),rc.Height(),SWP_SHOWWINDOW|SWP_NOACTIVATE);  
        m_pMsgTipDlg->DrawMsgTip();  
    }  

//显示提示信息
void CPetrelProView::ShowMsgTip(BOOL bShow,CMsgTipArray &arMsgTip)
{
 if(m_pMsgTipDlg == NULL)
 {
  m_pMsgTipDlg = new CMsgTipDlg();
  m_pMsgTipDlg->Create(IDD_MSGTIP_DLG,this);
 }
 if(!bShow)
 {
  m_pMsgTipDlg->ShowWindow(SW_HIDE);
 }
 else
 {
  CSize size = m_pMsgTipDlg->ShowMsgTip(arMsgTip);
  if(size.cx == 0)
   return;
  CPoint pt;
  GetCursorPos(&pt);
  CRect rc(pt,size);
  rc.OffsetRect(15,20);
  CRect mRc;
  GetWindowRect(&mRc);
  if(rc.bottom > mRc.bottom)
   rc.OffsetRect(0,mRc.bottom-rc.bottom-5);
  if(rc.right > mRc.right)
  {
   rc.OffsetRect(-rc.Width()-30,0);
  }
  m_pMsgTipDlg->SetWindowPos(&wndTop,rc.left,rc.top,rc.Width(),rc.Height(),SWP_SHOWWINDOW|SWP_NOACTIVATE);
  m_pMsgTipDlg->DrawMsgTip();
 }
}

那么,剩下的工作,就是需要在每个实体类中增加类似这样的函数:

    CMsgTipArray arMsgTip;
    pDoc->m_pShipMan->GetMsgTipInfo(arMsgTip);
在OnMouseMove事件中,从各个实体类中获取对象选中的情况。

如下是一个例子:

view plaincopy to clipboardprint?
void CShip::GetMsgTipInfo(CMsgTipArray &arMsgTip)  
{  
    MSG_TIP mt;  
    mt.nInfoShowColor = -1;  
    mt.sMsgItemName = "它船位置信息";  
    mt.sMsgItemInfo = "";  
    arMsgTip.Add(mt);  
    mt.sMsgItemInfo = m_ShipBaseInfo.sEngName;  
    mt.sMsgItemName = "船舶名称";  
    mt.nInfoShowColor = COLOR_GRASS;  
    arMsgTip.Add(mt);  
    mt.sMsgItemInfo = m_ShipBaseInfo.sMMSIID;  
    mt.sMsgItemName = "MMSI";  
    arMsgTip.Add(mt);  
    CString sDate = m_ShipBaseInfo.tNowReptTime.Format("%Y-%m-%d %H:%M:%S");  
    mt.sMsgItemInfo = sDate;  
    mt.sMsgItemName = "报告时间";  
    arMsgTip.Add(mt);  
    CString sLat = CoordFormatDouble2Str(m_ShipBaseInfo.nowPos.dLatitude,true,theApp.m_sysINIFile.GetLatLongConfig().eLatLongFmt);  
    CString sLong = CoordFormatDouble2Str(m_ShipBaseInfo.nowPos.dLongitude,false,theApp.m_sysINIFile.GetLatLongConfig().eLatLongFmt);  
    mt.sMsgItemInfo = sLat;  
    mt.sMsgItemName = "纬度";  
    arMsgTip.Add(mt);  
    mt.sMsgItemInfo = sLong;  
    mt.sMsgItemName = "经度";  
    arMsgTip.Add(mt);  
    if(m_ShipBaseInfo.fNowCOG > 359.9)  
        mt.sMsgItemInfo = "NA";  
    else 
        mt.sMsgItemInfo.Format("%.1f°",m_ShipBaseInfo.fNowCOG);  
    mt.sMsgItemName = "航向";  
    arMsgTip.Add(mt);  
    if(m_ShipBaseInfo.fNowSOG > 102)  
        mt.sMsgItemInfo = "NA";  
    else 
        mt.sMsgItemInfo.Format("%.1f",m_ShipBaseInfo.fNowSOG);  
    mt.sMsgItemName = "航速";  
    arMsgTip.Add(mt);  
    if(m_ShipBaseInfo.wTrueHeading == 511)  
        mt.sMsgItemInfo = "NA";  
    else 
        mt.sMsgItemInfo.Format("%d°",m_ShipBaseInfo.wTrueHeading);  
    mt.sMsgItemName = "船首向";  
    arMsgTip.Add(mt);  
    if(abs(m_ShipBaseInfo.lROT) >= 720)  
        mt.sMsgItemInfo = "NA";  
    else 
        mt.sMsgItemInfo.Format("%d°/分",m_ShipBaseInfo.lROT);  
    mt.sMsgItemName = "转向率";  
    arMsgTip.Add(mt);  
    mt.sMsgItemName = "船位来源";  
    mt.sMsgItemInfo = m_ShipBaseInfo.sPosFromName;  
    if(mt.sMsgItemInfo.GetLength() == 0)  
        mt.sMsgItemInfo = m_ShipBaseInfo.sPosFromCode;  
    arMsgTip.Add(mt);  

void CShip::GetMsgTipInfo(CMsgTipArray &arMsgTip)
{
 MSG_TIP mt;
 mt.nInfoShowColor = -1;
 mt.sMsgItemName = "它船位置信息";
 mt.sMsgItemInfo = "";
 arMsgTip.Add(mt);
 mt.sMsgItemInfo = m_ShipBaseInfo.sEngName;
 mt.sMsgItemName = "船舶名称";
 mt.nInfoShowColor = COLOR_GRASS;
 arMsgTip.Add(mt);
 mt.sMsgItemInfo = m_ShipBaseInfo.sMMSIID;
 mt.sMsgItemName = "MMSI";
 arMsgTip.Add(mt);
 CString sDate = m_ShipBaseInfo.tNowReptTime.Format("%Y-%m-%d %H:%M:%S");
 mt.sMsgItemInfo = sDate;
 mt.sMsgItemName = "报告时间";
 arMsgTip.Add(mt);
 CString sLat = CoordFormatDouble2Str(m_ShipBaseInfo.nowPos.dLatitude,true,theApp.m_sysINIFile.GetLatLongConfig().eLatLongFmt);
 CString sLong = CoordFormatDouble2Str(m_ShipBaseInfo.nowPos.dLongitude,false,theApp.m_sysINIFile.GetLatLongConfig().eLatLongFmt);
 mt.sMsgItemInfo = sLat;
 mt.sMsgItemName = "纬度";
 arMsgTip.Add(mt);
 mt.sMsgItemInfo = sLong;
 mt.sMsgItemName = "经度";
 arMsgTip.Add(mt);
 if(m_ShipBaseInfo.fNowCOG > 359.9)
  mt.sMsgItemInfo = "NA";
 else
  mt.sMsgItemInfo.Format("%.1f°",m_ShipBaseInfo.fNowCOG);
 mt.sMsgItemName = "航向";
 arMsgTip.Add(mt);
 if(m_ShipBaseInfo.fNowSOG > 102)
  mt.sMsgItemInfo = "NA";
 else
  mt.sMsgItemInfo.Format("%.1f",m_ShipBaseInfo.fNowSOG);
 mt.sMsgItemName = "航速";
 arMsgTip.Add(mt);
 if(m_ShipBaseInfo.wTrueHeading == 511)
  mt.sMsgItemInfo = "NA";
 else
  mt.sMsgItemInfo.Format("%d°",m_ShipBaseInfo.wTrueHeading);
 mt.sMsgItemName = "船首向";
 arMsgTip.Add(mt);
 if(abs(m_ShipBaseInfo.lROT) >= 720)
  mt.sMsgItemInfo = "NA";
 else
  mt.sMsgItemInfo.Format("%d°/分",m_ShipBaseInfo.lROT);
 mt.sMsgItemName = "转向率";
 arMsgTip.Add(mt);
 mt.sMsgItemName = "船位来源";
 mt.sMsgItemInfo = m_ShipBaseInfo.sPosFromName;
 if(mt.sMsgItemInfo.GetLength() == 0)
  mt.sMsgItemInfo = m_ShipBaseInfo.sPosFromCode;
 arMsgTip.Add(mt);
}

     以上工作即可实现一个浮动的鼠标移动选中的对象的半透明的提示窗。当鼠标移开或者移动到提示窗上时,提示窗将立刻隐藏。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/happyparrot/archive/2010/05/14/5589418.aspx

你可能感兴趣的:(zhuan)