Duilib 实现右下角弹出像QQ新闻窗口,3秒后自动关闭(一)

转载:https://blog.twofei.com/667/

自绘或子类化控件时,有时需要处理鼠标进入(MouseEnter)/鼠标离开(MouseLeave)/鼠标停留(MouseHover)消息,虽然有定义这两个消息常量(WM_MOUSEHOVER 与 WM_MOUSELEAVE),但默认情况下 Windows 的窗口消息是不会产生这三个消息的。但提供了一个 API 函数_TrackMouseEvent 可以使用,这个函数可以使 Windows 产生 鼠标停留(WM_MOUSEHOVER)与 鼠标离开(WM_MOUSELEAVE)消息,至于鼠标进入消息(Windows 没有定义 WM_MOUSEENTER 宏),直接手动在第一次鼠标移动的时候模拟产生就行了。不过不爽的是 鼠标离开消息 Windows 没有传递离开时的坐标过来,所以这个也得手动模拟:每次鼠标移动的时候记录下坐标,在收到鼠标离开消息时,采用此值即可。下面的代码没有作此处理,如有需要可手动加上。

效果:

.h文件

#ifndef _POPUPWND_H_
#define _POPUPWND_H_

#include "WndShadow.h"

#define WIN_VISITWIDTH    280
#define WIN_VISITHEIGHT    186

#define ID_VISITPOP_WINDOW 20
#define ID_TIMER_DISPLAY_DELAY 30
#define ID_TIMER_CLOSE_WINDOW 40

class CPopUpWnd :public WindowImplBase
{
public:
    CPopUpWnd();

    ~CPopUpWnd();

public:
    virtual LPCTSTR GetWindowClassName() const;

    virtual void OnFinalMessage(HWND hWnd);

    virtual CDuiString GetSkinFile();

    virtual CDuiString GetSkinFolder();

    virtual UILIB_RESOURCETYPE GetResourceType() const;

    virtual CControlUI* CreateControl(LPCTSTR pstrClassName);

    virtual LRESULT ResponseDefaultKeyEvent(WPARAM wParam);

    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); 

    virtual void Notify(TNotifyUI& msg);

    virtual void OnClick(TNotifyUI& msg);

    virtual void InitWindow();

    void OnPrepare();

public:

    void InitControl();

    void StartTrack();

    void MoveSelfWindow();

    LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,BOOL& bHandled);

    LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

    LRESULT OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

    LRESULT OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);

    LRESULT OnMouseEnter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);


public:
    CWndShadow m_WndShadow;

    CLabelUI* m_pMousePos;

    UINT m_uTime;//移动窗口时器

protected:
    bool m_bMouseTracking;   // 是否正在跟踪鼠标
    bool m_bMouseWithin;     // 鼠标是否在窗口内
};

#endif//_POPUPWND_H

.cpp文件

#include "....stdafx.h"
#include "PopUpWnd.h"
#pragma comment(lib, "comctl32.lib")

CPopUpWnd::CPopUpWnd()
    :m_uTime(0)
    ,m_bMouseTracking(false)
    ,m_bMouseWithin(false)
    ,m_pMousePos(NULL)
{

}

CPopUpWnd::~CPopUpWnd()
{
    if (m_uTime)
    {
        KillTimer(this->GetHWND(),ID_VISITPOP_WINDOW);
        m_uTime = 0;
    }
}

LPCTSTR CPopUpWnd::GetWindowClassName() const
{
    return _T("PopUpWnd");
}

void CPopUpWnd::OnFinalMessage(HWND hWnd)
{
    CWindowWnd::OnFinalMessage(hWnd);
}

CDuiString CPopUpWnd::GetSkinFile()
{
    return _T("xml//PopUpDlg.xml");
}

CDuiString CPopUpWnd::GetSkinFolder()
{
    return _T("");
}

UILIB_RESOURCETYPE CPopUpWnd::GetResourceType() const
{
    return UILIB_FILE;
}

LRESULT CPopUpWnd::ResponseDefaultKeyEvent(WPARAM wParam)
{
    if (wParam == VK_RETURN)
    {
        return FALSE;
    }
    else if (wParam == VK_ESCAPE)
    {
        Close();
        return TRUE;
    }
    return FALSE;
}

CControlUI* CPopUpWnd::CreateControl(LPCTSTR pstrClassName)
{
    

    return NULL;
}

void CPopUpWnd::InitWindow()
{
    //窗体增加阴影
    CWndShadow::Initialize(m_PaintManager.GetInstance());
    m_WndShadow.Create(m_hWnd , true);
    m_WndShadow.SetSize(2);
    m_WndShadow.SetPosition(1, 1);

    //修改窗口风格
    //SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE) & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME );

    //加入WS_EX_LAYERED扩展属性
    LONG styleValue = ::GetWindowLong(m_hWnd, GWL_EXSTYLE); 

    styleValue &= ~(WS_EX_APPWINDOW);//当窗口可见时将一个顶层窗口放置在任务栏上
    styleValue |= WS_EX_TOOLWINDOW; //工具条窗口样式

    SetWindowLong(m_hWnd,GWL_EXSTYLE,styleValue);

    InitControl();

    //右下角慢慢弹出
    //m_uTime = SetTimer(m_hWnd,ID_VISITPOP_WINDOW,20,NULL);

   //在此调用MoveSelfWindow()方法  窗口不会显示在右下角,因为InitWindow在WM_CREATE 消息响应函数里调用,窗口还没创建出来
}

void CPopUpWnd::InitControl()
{
    m_pMousePos = static_cast<CLabelUI*>(m_PaintManager.FindControl(TEXT("mouse")));
}

void CPopUpWnd::OnPrepare()
{
    //直接显示在右下角
    MoveSelfWindow();

    //3秒后窗口自动关闭
    SetTimer(m_hWnd,ID_TIMER_DISPLAY_DELAY,3000,NULL);
}

void CPopUpWnd::Notify(TNotifyUI& msg)
{
    if( msg.sType == _T("windowinit") ) OnPrepare();

    if ( msg.sType == _T("click") )
    {
        
    }
    WindowImplBase::Notify(msg);
}

void CPopUpWnd::OnClick(TNotifyUI& msg)
{
    __super::OnClick(msg);
}

void CPopUpWnd::MoveSelfWindow()
{
    RECT rect;
    SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
    int y=rect.bottom-rect.top;
    int x=rect.right-rect.left;
    x=x-WIN_VISITWIDTH;
    y=y-WIN_VISITHEIGHT;

    MoveWindow(m_hWnd,x,y,WIN_VISITWIDTH,WIN_VISITHEIGHT,TRUE);
}

LRESULT CPopUpWnd::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam,BOOL& bHandled)
{
    static int nHeight=0;
    int cy=GetSystemMetrics(SM_CYSCREEN);
    int cx=GetSystemMetrics(SM_CXSCREEN);
    RECT rect;
    SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
    int y=rect.bottom-rect.top;
    int x=rect.right-rect.left;
    x=x-WIN_VISITWIDTH;

    switch(wParam)
    {//多个定时器
    case ID_VISITPOP_WINDOW:
        if(nHeight<=WIN_VISITHEIGHT)
        {
            ++nHeight;        
            MoveWindow(m_hWnd,x,y-WIN_VISITHEIGHT,WIN_VISITWIDTH,WIN_VISITHEIGHT,TRUE);
        }
        else
        {
            //nHeight = 0;
            KillTimer(m_hWnd,ID_VISITPOP_WINDOW);

            SetTimer(m_hWnd,ID_TIMER_DISPLAY_DELAY,3000,NULL);
        }
        break;
    case ID_TIMER_DISPLAY_DELAY:
        KillTimer(m_hWnd,ID_TIMER_DISPLAY_DELAY);
        Close(IDCLOSE);
        break;
    }
    return 0;
}


//LRESULT CPopUpWnd::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
//{
//    POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
//    //::ScreenToClient(m_hWnd,&pt);//转换成屏幕坐标
//    //POINT pt1 ;/*= { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };*/
//    //GetCursorPos(&pt1);
//    RECT rect;
//    ::GetWindowRect (m_hWnd,&rect);
//    //::ClientToScreen(m_hWnd,&pt);//转换成屏幕坐标
//    if (PtInRect(&rect,pt))//判断point是否在rect内部
//    {
//        KillTimer(m_hWnd,ID_TIMER_DISPLAY_DELAY);
//    }
//
//    return 0;
//}


void CPopUpWnd::StartTrack()
{
    TRACKMOUSEEVENT tme = {0};
    tme.cbSize = sizeof(tme);
    tme.hwndTrack = m_hWnd;
    tme.dwFlags = TME_HOVER | TME_LEAVE;
    tme.dwHoverTime = HOVER_DEFAULT;
    _TrackMouseEvent(&tme);
}

LRESULT CPopUpWnd::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    // 如果鼠标不在客户区内,就产生一个鼠标进入事件
    if(!m_bMouseWithin) {
        OnMouseEnter(uMsg /* WM_MOUSEMOVE */, wParam, lParam, bHandled);
    }

    // 开始跟踪鼠标停留/离开事件
    if(!m_bMouseTracking) {
        StartTrack();
        m_bMouseTracking = true;
        return 0;
    }
    

    TCHAR text[MAX_PATH];
    wsprintf(text,_T("鼠标移动: %d,%d"),GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));

    m_pMousePos->SetText(text);


    return 0;
}



LRESULT CPopUpWnd::OnMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
     m_bMouseTracking = false;

     TCHAR text[MAX_PATH];
     wsprintf(text,_T("鼠标停留: %d,%d"),GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
     m_pMousePos->SetText(text);


     return 0;
}

LRESULT CPopUpWnd::OnMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    m_bMouseTracking = false;
    m_bMouseWithin = false;

    SetTimer(m_hWnd,ID_TIMER_DISPLAY_DELAY,3000,NULL);


     TCHAR text[MAX_PATH];
     wsprintf(text,_T("鼠标离开: %d,%d"),GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
     m_pMousePos->SetText(text);

    return 0;
}

LRESULT CPopUpWnd::OnMouseEnter(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    m_bMouseWithin = true;

    
    KillTimer(m_hWnd,ID_TIMER_DISPLAY_DELAY);

    TCHAR text[MAX_PATH];
    wsprintf(text,_T("鼠标进入:%d,%d"),GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
    m_pMousePos->SetText(text);
    return 0;
}


LRESULT CPopUpWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    LRESULT lRes = 0;
    BOOL bHandled = TRUE;

    switch( uMsg ) 
    {
    case WM_NCLBUTTONDBLCLK:
        //不做处理
        {
            return 0;
        }
        break;
    case WM_TIMER:
        lRes = OnTimer(uMsg,wParam,lParam,bHandled);
        break;
    case WM_MOUSELEAVE:
        lRes = OnMouseLeave(uMsg,wParam,lParam,bHandled);
        break;
    default:
        bHandled = FALSE;
    }
    return WindowImplBase::HandleMessage(uMsg,wParam,lParam);
}

原文地址:https://www.cnblogs.com/chechen/p/7347236.html