设置窗口分层透明和固定秒数后自动消失

本文介绍了如何使用SetLayeredWindowAttributes函数设置C++ MFC应用程序中的窗口分层透明,并逐渐消失。内容包括函数参数解析、透明效果实现及在OnInitDialog中设置扩展样式WS_EX_LAYERED。在透明度变为全透明后,可通过隐藏窗口来消除残留的边界。文中还提到了在WM_MOUSEMOVE消息响应和定时器中实现这一功能的技巧。
摘要由CSDN通过智能技术生成

设置窗口分层透明逐渐消失要用到一个函数:SetLayeredWindowAttributes

此函数用于设置分层窗口透明度,常和UpdateLayeredWindow 函数结合使用。

先看看该函数的原型和参数:

C++申明:

BOOLSetLayeredWindowAttributes(

HWNDhwnd, // 指定分层窗口句柄

COLORREFcrKey, // 指定需要透明的背景颜色值,可用RGB()宏

BYTEbAlpha, // 设置透明度,0表示完全透明,255表示不透明

DWORDdwFlags // 透明方式

);

其中,dwFlags参数可取以下值:

LWA_ALPHA时:crKey参数无效,bAlpha参数有效;

LWA_COLORKEY窗体中的所有颜色为crKey的地方将变为透明,bAlpha参数无效。其常量值为1。

LWA_ALPHA| LWA_COLORKEYcrKey的地方将变为全透明,而其它地方根据bAlpha参数确定透明度。

注:要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性,方法可以在CreateWindowEx时指定,也可以SetWindowLong动态设置。如下代码可设置分层窗口:

LONG t =GetWindowLong(m_hWnd, GWL_EXSTYLE);

t |=WS_EX_LAYERED;

SetWindowLong(m_hWnd,GWL_EXSTYLE, t);

一般可以再初始化函数中,即OnInitDialog函数中设置eg:

Void XXX:: OnInitDialog
{
    UIDialog::OnInitDialog();
    SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)|WS_EX_LAYERED);
}

这里还有一点需要注意: 设置时当透明度变化后,如果鼠标移动到对话框上时,应该透明度变回来,窗口不消失,这时,如果整个窗口被子控件充满的话(如下图1所示的),则不会响应鼠标移动WM_MOUSEMOVE消息。如果要响应需要控件类父类的OnMouseMove函数中post消息通知父窗口就会响应。图1

实现该功能的主要代码为:(一)

xxx.h文件


class COnlineTipDlg : public CDialog
{
public:
<span style="white-space:pre">	</span>COnlineTipDlgCOnlineTipDlg(int nVehicleId, CWnd* pParent = NULL);   // 标准构造函数
<span style="white-space:pre">	</span>virtual ~COnlineTipDlg();
protected:
    virtual BOOL OnInitDialog();
    HANDLE m_hDisappear;
public:
    int m_nDisAppearCount;
    CRITICAL_SECTION m_csDisAppearCount;
    BOOL m_bMouseHover;
    BOOL m_bMouseTrack;
    static DWORD WINAPI AutoDisappear(LPVOID pParam);

    void ResetTimeInterVal();
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnMouseLeave();
};


xxx.cpp文件

#define DISAPPEARTIME (10 * 1000)
#define DISAP_TOTALTIMES 50
#define TOTAL_ALPHA 255
// COnlineTip 对话框
COnlineTipDlg::COnlineTipDlg(int nVehicleId, CWnd* pParent /*=NULL*/)
	: UIDialog(COnlineTipDlg::IDD, pParent)
    ,m_bMouseHover(FALSE)
    , m_bMouseTrack(TRUE)
    , m_hDisappear(NULL)
    , m_nDisAppearCount(0)
{
    InitializeCriticalSection(&m_csDisAppearCount);  //锁
}

COnlineTipDlg::~COnlineTipDlg()
{
}

BOOL COnlineTipDlg::OnInitDialog()
{
    UIDialog::OnInitDialog();
    ......
    /*一个简单处理方法是设置定时器,半分钟后关闭(隐藏)
     SetTimer(TIME_ID_VEHICLE_STATE, TIME_ELASPE_VEHICLE_STATE, NULL);或者将此设置透明窗口放在定时器中完成即可*/

    m_nDisAppearCount = DISAP_TOTALTIMES;
    SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,   
        GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE) | WS_EX_LAYERED);  //要使使窗体拥有透明效果,必须要有WS_EX_LAYERED扩展属性
    m_hDisappear = CreateThread(NULL, 0, AutoDisappear, this, 0, NULL);   //起线程专门干这件事

    return TRUE;
}
DWORD WINAPI COnlineTipDlg::AutoDisappear(LPVOID pParam)
{
    COnlineTipDlg* pMan = (COnlineTipDlg*)pParam;
    if (!pMan)
    {
        return -1;
    }
    BYTE btAlpha = TOTAL_ALPHA;
    float fDisappear = 1;
    int nTimeCount = DISAPPEARTIME;
    int nInterval = nTimeCount / pMan->m_nDisAppearCount;
    while(pMan->m_nDisAppearCount != 0)
    {
        if (pMan->m_bMouseHover)
        {
            pMan->ResetTimeInterVal();
        }
        else
        {
            CGuard guard(&pMan->m_csDisAppearCount);
            -- pMan->m_nDisAppearCount;
        }
        fDisappear = pMan->m_nDisAppearCount * 1.0 / DISAP_TOTALTIMES;
        btAlpha = TOTAL_ALPHA * fDisappear;
        ::SetLayeredWindowAttributes(pMan->GetSafeHwnd(), 0, btAlpha, LWA_ALPHA);   //此函数用于设置分层窗口透明度,常和 UpdateLayeredWindow 函数结合使用
        Sleep(nInterval);
    }
    return 0;
}
void COnlineTipDlg::ResetTimeInterVal()
{
    CGuard guard(&m_csDisAppearCount);
    m_nDisAppearCount = DISAP_TOTALTIMES;
}
void COnlineTipDlg::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (m_bMouseTrack)     // 若允许 追踪,则。
    {
        TRACKMOUSEEVENT csTME;
        csTME.cbSize = sizeof (csTME);
        csTME.dwFlags = TME_LEAVE|TME_HOVER;
        csTME.hwndTrack = m_hWnd ;// 指定要 追踪 的窗口
        csTME.dwHoverTime = 10;  //
        ::_TrackMouseEvent (&csTME); // 开启 Windows 的 WM_MOUSELEAVE , WM_MOUSEHOVER 事件

        m_bMouseTrack=FALSE ;   // 若已经追踪 ,则不在追踪
    }
    //SetCursor(LoadCursor(NULL,IDC_HAND));  //设置鼠标样式为小手
    ResetTimeInterVal();
    m_bMouseHover = TRUE;
    UIDialog::OnMouseMove(nFlags, point);

    /*这里有一点需要注意:这里的对话框中被一个列表全部塞满,因为子控件不响应WM_MOUSEMOVE消息,所以需要在父类的OnMouseMove
    函数中post消息通知父窗口就会响应*/
}
void COnlineTipDlg::OnMouseLeave()
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    m_bMouseHover = FALSE;
    m_bMouseTrack = TRUE;
    UIDialog::OnMouseLeave();
}

(二) 以上代码是开启了新的线程。但根据我的项目环境,窗口全透明之后会有一个透明的对话框边界 留在界面上,这时可以将对话框在透明度变为全透明后将其隐藏掉。如果开了线程的不太好做,所以可以在定时器中实现,具体做法,待敞口透明度变为0之后调用showWindow(SW_HIDE) 将其隐藏。主要代码还用以上代码修改:在自己的逻辑中的适当位置设置定时器(可在OnInitDialog中设置),然后响应Ontimer函数;

void COnlineTipDlg::OnTimer(UINT_PTR nIDEvent)
 {
     switch(nIDEvent)
     {
        case TIME_ID_VEHICLE_STATE:
            if (m_bMouseHover)  //鼠标悬浮则不透明
            {
                m_nDisAppearCount = 255;
            }
            else
            {
                m_nDisAppearCount -= 3;  //发现这里如果-4 减不到0 ,所以消失又会弹出来,最好用百分比,上面代码可以直接复用即可
            }
            SetLayeredWindowAttributes(0, m_nDisAppearCount, LWA_ALPHA); 
            
            if (m_nDisAppearCount == 0)
            {
                ShowWindow(SW_HIDE);
            }
            break;
     }
     UIDialog::OnTimer(nIDEvent);
 }

还需要将以上OnMouseMove函数中的父窗口改为子控件的句柄即修改这行代码:

<span style="white-space:pre">	</span>csTME.hwndTrack = m_ctrlListOnlineTip.GetSafeHwnd() ;
  因为穿够哦位置原因,最好对消息进行过滤,如下:

BOOL COnlineTipDlg::PreTranslateMessage(MSG* pMsg)  //PreTranslateMessage是消息在送给TranslateMessage函数之前被调用.
{
    if (pMsg->hwnd == m_ctrlListOnlineTip.GetSafeHwnd())
    {
        switch(pMsg->message)
        {
        case WM_MOUSELEAVE:
            {
                OnMouseLeave();
            }
            break;
        case WM_MOUSEHOVER:
            {
                OnMouseHover(pMsg->wParam, pMsg->lParam);
            }
            break;
        default:
            break;
        }
    }
    return UIDialog::PreTranslateMessage(pMsg);
}
完美解决!!!

大致就这些!!希望对大家有用!!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值