MFC编程时,有时候我们需要实现窗口透明化,可以通过SetLayeredWindowAttributes设置窗口透明色和透明度来实现窗口透明化。而要使窗口拥有透明效果,前提是窗口要有WS_EX_LAYERED扩展属性,需用SetWindowLong设置窗口支持拓展风格。
一、窗口透明化说明
1.窗口透明化有三种模式:
第一种是全窗口按透明度透明化,透明度为0时,窗口不可见,鼠标可以点击其覆盖的下层窗口;
第二种是窗口指定颜色全透明化;
第三种是窗口指定颜色全透明化,其余颜色按透明度进行透明化。
而第二、三种模式全透明化区域,根据指定颜色的不同又分为两种方式:
(1)透明,但不穿透:鼠标不能穿透窗口透明区域点击其覆盖的下层窗口。
(2)透明且穿透:鼠标可以穿透窗口透明区域点击其覆盖的下层窗口。
2.透明色特性:
(1)红色和蓝色透明色透明区域不穿透,绿色透明色透明区域穿透(其它颜色没细究过,需要自己摸索);
(2)透明色会影响画笔绘画颜色,原因不明,但可以调节透明色和画笔颜色,获得需要的绘画显示颜色,不过比较麻烦,且得不到精确RGB值的颜色。比如:红色(RGB(255,0,0))的画笔,透明色为RGB(255,0,0),在透明化窗口绘画,画笔颜色显示不为红色;透明色为RGB(0, 0, 255),在透明穿透窗口绘画,蓝色(RGB(0, 0, 255))画笔颜色显示为红色。
#define TRANSPARENT_COLOR RGB(255,0,0) //透明色
#define TRANSPARENT_COLOR RGB(0,0,255) //透明色
#define TRANSPARENT_COLOR_THROUGH RGB(0,255,0)//透明穿透色
#define TRANSPARENT_COLOR RGB(255,200,200) //透明色,此透明颜色时画笔颜色为RGB(255,0,0)时绘画显示仍为红色
二、SetLayeredWindowAttributes函数说明
BOOL SetLayeredWindowAttributes(
HWND hwnd, // 需要透明化窗口的句柄
COLORREF crKey, // 透明色,以RGB(r,g,b)的格式
BYTE bAlpha, // 透明度,0是全透明,255是完全不透明
DWORD dwFlags // 透明模式,有LWA_COLORKEY, LWA_ALPHA,LWA_ALPHA | LWA_COLORKEY
);
hwnd是透明窗口的句柄,
crKey为透明色,
bAlpha是透明度,取值范围是[0,255],
dwFlags是透明模式:
1.LWA_ALPHA时,crKey参数无效,bAlpha参数有效,整个窗口透明化,鼠标不能点击窗口覆盖的下层窗口,不需要在OnCtlColor指定透明色画刷,即第一种透明化模式;
2.LWA_COLORKEY时,窗体中的所有颜色为crKey的地方将变为全透明,bAlpha参数无效,需要在OnCtlColor指定透明色画刷,即第二种透明化模式。
3.LWA_ALPHA | LWA_COLORKEY时,窗体中的所有颜色为crKey的地方将变为全透明,而其它地方根据透明度bAlpha进行透明化,需要在OnCtlColor指定透明色画刷,即第三种透明化模式。
注:LWA_COLORKEY=1,LWA_ALPHA =2, LWA_ALPHA | LWA_COLORKEY=3,dwFlags亦可以设为1或者2或者3。
二、实现
1.全窗口按透明度透明化
HINSTANCE hInst = NULL;//DLL指针
typedef BOOL(WINAPI *MYFUNC)(HWND, COLORREF, BYTE, DWORD);
MYFUNC pFun = NULL;//函数指针BOOL CSelectrectDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// TODO: 在此添加额外的初始化SetWindowLong(this->m_hWnd, GWL_EXSTYLE, GetWindowLong(this->m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);//要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性hInst = LoadLibrary(L"User32.DLL"); //显式加载DLLif (hInst != NULL){pFun = (MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");//取得SetLayeredWindowAttributes函数指针if (pFun != NULL)pFun(this->m_hWnd, 0, 0, LWA_ALPHA);//整个窗口按透明度透明化 }return TRUE;
}
注:窗口透明化后,在窗口内绘画,绘图也会按透明度进行透明化。
2.窗口指定颜色全透明化
#define TRANSPARENT_COLOR RGB(255,200,200) //透明色
HINSTANCE hInst = NULL;//DLL指针
typedef BOOL(WINAPI *MYFUNC)(HWND, COLORREF, BYTE, DWORD);
MYFUNC pFun = NULL;//函数指针
CBrush m_brush;//透明色画刷//OnCtlColor在OnInitDialog前就调用了,故需在对话框构造函数中创建透明色画刷
CtestDlg::CtestDlg(CWnd* pParent /*=NULL*/): CDialogEx(CtestDlg::IDD, pParent)
{//需要此处初始化画刷,OnCtlColor才能使用m_brush.CreateSolidBrush(RESERVED_COLOR);//透明色画刷
}BOOL CSelectrectDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// TODO: 在此添加额外的初始化SetWindowLong(this->m_hWnd, GWL_EXSTYLE, GetWindowLong(this->m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);//要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性hInst = LoadLibrary(L"User32.DLL"); //显式加载DLLif (hInst != NULL){pFun = (MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");//取得SetLayeredWindowAttributes函数指针if (pFun != NULL)pFun(this->m_hWnd, TRANSPARENT_COLOR, 0, LWA_COLORKEY);//窗口指定颜色全透明化 }return TRUE;
}
//将窗口的画刷改为透明色画刷
HBRUSH CtestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: 在此更改 DC 的任何特性 return m_brush;// TODO: 如果默认的不是所需画笔,则返回另一个画笔return hbr;
}
实现原理:先在OnCtlColor中将窗口的画刷改为透明色画刷,然后窗口就变成透明色,然后OnInitDialog中SetLayeredWindowAttributes将窗口颜色为透明色的区域变成全透明。
注:如果想实现透明穿透效果,将TRANSPARENT_COLOR换成TRANSPARENT_COLOR_THROUGH。
3.窗口指定颜色全透明化,其余颜色按透明度进行透明化
#define TRANSPARENT_COLOR RGB(255,200,200) //透明色
HINSTANCE hInst = NULL;//DLL指针
typedef BOOL(WINAPI *MYFUNC)(HWND, COLORREF, BYTE, DWORD);
MYFUNC pFun = NULL;//函数指针
CBrush m_brush;//透明色画刷//OnCtlColor在OnInitDialog前就调用了,故需在对话框构造函数中创建透明色画刷
CtestDlg::CtestDlg(CWnd* pParent /*=NULL*/): CDialogEx(CtestDlg::IDD, pParent)
{//需要此处初始化画刷,OnCtlColor才能使用m_brush.CreateSolidBrush(RESERVED_COLOR);//透明色画刷
}BOOL CSelectrectDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// TODO: 在此添加额外的初始化SetWindowLong(this->m_hWnd, GWL_EXSTYLE, GetWindowLong(this->m_hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);//要使使窗体拥有透明效果,首先要有WS_EX_LAYERED扩展属性hInst = LoadLibrary(L"User32.DLL"); //显式加载DLLif (hInst != NULL){pFun = (MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");//取得SetLayeredWindowAttributes函数指针if (pFun != NULL)pFun(this->m_hWnd, TRANSPARENT_COLOR, 0, LWA_ALPHA | LWA_COLORKEY);//窗口指定颜色全透明化,其余颜色按透明度进行透明化 }return TRUE;
}
//将窗口的画刷改为透明色画刷
HBRUSH CtestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: 在此更改 DC 的任何特性 return m_brush;// TODO: 如果默认的不是所需画笔,则返回另一个画笔return hbr;
}
实现原理:先在OnCtlColor中将窗口的画刷改为透明色画刷,然后窗口就变成透明色,然后OnInitDialog中SetLayeredWindowAttributes将窗口颜色为透明色的区域变成全透明,不是透明色的区域按透明度进行透明化处理。
注:如果透明度为0,效果跟第一种透明化模式一样,整个窗口不可见,鼠标可以点击其覆盖的下层窗口;如果想实现透明穿透效果,将TRANSPARENT_COLOR换成TRANSPARENT_COLOR_THROUGH。
三、拓展
OnCtlColor中通过参数pWnd或者nCtlColor判断,可以透明化客户区或者指定某几类控件或者某一控件透明化。以第二种模式为例:
1.改变某类控件的颜色进行透明化
//将窗口的画刷改为透明色画刷
HBRUSH CtestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: 在此更改 DC 的任何特性 if (nCtlColor == CTLCOLOR_STATIC){//有些控件需要改变字体颜色和字体背景色才能全透明 pDC->SetTextColor(TRANSPARENT_COLOR); //设置字体颜色,字体全透明pDC->SetBkColor(TRANSPARENT_COLOR); //字体背景色,字体背景色全透明return m_brush;} // TODO: 如果默认的不是所需画笔,则返回另一个画笔return hbr;
}
2.改变某一控件的颜色进行透明化
//将窗口的画刷改为透明色画刷
HBRUSH CtestDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: 在此更改 DC 的任何特性 if (pWnd->GetDlgCtrlID() == IDC_STATIC){//有些控件需要改变字体颜色和字体背景色才能全透明 pDC->SetTextColor(TRANSPARENT_COLOR); //设置字体颜色,字体全透明pDC->SetBkColor(TRANSPARENT_COLOR); //字体背景色,字体背景色全透明return m_brush;} // TODO: 如果默认的不是所需画笔,则返回另一个画笔return hbr;
}
注:OnCtlColor可以改变客户区和某些控件的画刷颜色,但是改变不了窗口边框的颜色以及某些控件的画刷颜色,例如:Button、Slider、Picture等控件。要想将这些控件也全透明,可以使用ShowWindow(SW_HIDE)隐藏控件,在需要的时候再用ShowWindow(SW_SHOW)显示控件。如果想要将这些控件半透明,可以使用第三种透明化模式,但窗口边框也会半透明;如果想要将这些控件半透明,边框全透明,可以使用第三种透明化模式,同时用SetWindowLong去掉边框。