子窗口的透明

简介: 由于项目中要实现子窗口的透明的功能,在网上找到了这一段提示:子窗口的透明和主窗口完全不同,   主窗口是通过layeredwindow实现的,   而子窗口则必须自己实现,   尤其是半透明,   必须自己对获取的透明背景图进行操作。

由于项目中要实现子窗口的透明的功能,在网上找到了这一段提示:

子窗口的透明和主窗口完全不同,   主窗口是通过layeredwindow实现的,   而子窗口则必须自己实现,   尤其是半透明,   必须自己对获取的透明背景图进行操作。   要实现子窗口的透明需要做到下面几步:

1.   windows的ExStyle中需要包含WS_EX_TRANSPARENT属性
2.   windows的Style中要去掉WS_CLIPSIBLING属性
3.   对继承自windows标准控件的子窗口(   比如edit,   scrollbar等等   ),   需要截获WM_CTLCOLORxxx消息并返回一个style为BS_HOLLOW的brush的handle(即一个透明画刷的handle)
4.   需要截获WM_ERASEBKGND消息并不要清除背景(如果做到了3,   则这一步可以省略)
5.   最关键的一点(也是很多人没有想到或不知道的),   必须将parent窗口style中的WS_CLIPCHILDREN标志去掉,   否则PARENT窗口重画时不会重画被子窗口覆盖的部分.
6.   做到以上各步后,   在子窗口收到WM_PAINT消息时就可以获得完整的背景图了,   接下去对这背景进行处理就可以实现半透明效果.

   另外一点,   最好同时截获parent窗的WM_PAINT消息,   在parent窗重画前调用InvalidateRect让本子窗口显示实效,   这样子窗口才能同样也收到一个WM_PAINT消息(   这样做是为了保险,   因为我不是很确定主窗口重画系统是否会自动给具有WS_EX_TRANSPARENT属性的子窗口同样发WM_PAINT   ).

 

 

如果谁更好的实现方法,请告诉我

 

实现过程中,我没处理第二和第五提示。

我的部分代码如下:

void CWndTool::AlphaCompositeBmp(const HBITMAP& bmpFront,const HBITMAP& bmpBKGround, HBITMAP& bmpDest, int nAlpha)
{
ASSERT(bmpFront);
ASSERT(bmpBKGround);

CBitmap* pBmpFront = CBitmap::FromHandle(bmpFront);
CBitmap* pBmpBkGround = CBitmap::FromHandle(bmpBKGround);

 
CDC memDcFront;
CDC memDcBkGround;
CDC memDcDest;
 
BITMAP bmFront;

CDC* pDc = GetDC();

memDcFront.CreateCompatibleDC(pDc);
memDcDest.CreateCompatibleDC(pDc);
memDcBkGround.CreateCompatibleDC(pDc);

CBitmap* pOldBmpFront = memDcFront.SelectObject(pBmpFront);
pBmpFront->GetBitmap(&bmFront);
 
CBitmap* pOldBmpBkGround = memDcBkGround.SelectObject(pBmpBkGround);

if (m_pTmpDest)
{
 delete m_pTmpDest;
 m_pTmpDest = NULL;
}
m_pTmpDest = new CBitmap();
m_pTmpDest->CreateCompatibleBitmap(pDc, bmFront.bmWidth, bmFront.bmHeight);
CBitmap* pBmpDest = memDcDest.SelectObject(m_pTmpDest);

 
for (int i=0; i  for (int j=0; j  {
  int rFront,gFront,bFront;
  int rBkGround,gBkGround,bBkGround;
  int rDest,gDest,bDest;

  COLORREF crFront = memDcFront.GetPixel(j, i);
  COLORREF bkRgb = memDcBkGround.GetPixel(j, i);

  rFront = GetRValue(crFront);
  gFront = GetGValue(crFront);
  bFront = GetBValue(crFront);

  rBkGround = GetRValue(bkRgb);
  gBkGround = GetGValue(bkRgb);
  bBkGround = GetBValue(bkRgb);

  rDest = (rBkGround*nAlpha+rFront*(256-nAlpha))/256;
  gDest = (gBkGround*nAlpha+gFront*(256-nAlpha))/256;
  bDest = (bBkGround*nAlpha+bFront*(256-nAlpha))/256;

  COLORREF crDest = RGB(rDest, gDest, bDest);
  COLORREF crRet = memDcDest.SetPixel(j, i, crDest);
 }

memDcFront.SelectObject(pOldBmpFront);
memDcBkGround.SelectObject(pOldBmpBkGround);
memDcDest.SelectObject(pBmpDest);

bmpDest = (HBITMAP)(m_pTmpDest->m_hObject);
}

 

void CWndTool::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CUIWnd::OnPaint() for painting messages

 CRect rt;
 GetClientRect(&rt);
 
 CDC memDc;
 memDc.CreateCompatibleDC(&dc);
 CBitmap* pBmp = memDc.SelectObject(CBitmap::FromHandle(m_bmpDest));
 dc.BitBlt(0, 0, rt.Width(), rt.Height(), &memDc, 0, 0, SRCCOPY);
 memDc.SelectObject(pBmp);
}

 

void CWndTool::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_isOverWnd == FALSE)
{
 TRACKMOUSEEVENT tme;
 tme.cbSize = sizeof(tme);
 tme.hwndTrack = m_hWnd;
 tme.dwFlags = TME_HOVER|TME_LEAVE;
 tme.dwHoverTime = 1;
 _TrackMouseEvent(&tme);
 m_isOverWnd = TRUE;
}
CUIWnd::OnMouseMove(nFlags, point);
}

void CWndShowHeaderTool::OnTimer(UINT_PTR id)
{
if (id == TIMER_OVER_TOOLWND)
{
 if (m_nTransparent < 55)
 {
  KillTimer(TIMER_OVER_TOOLWND);
  return;
 }

 if (m_bmpDest)
 {
  DeleteObject(m_bmpDest);
  m_bmpDest = NULL;
 }

 AlphaCompositeBmp(m_bmpFront, m_bmpBKGround, m_bmpDest, m_nTransparent);
 Invalidate(FALSE);
 UpdateWindow();
 m_nTransparent -= 50;
}
if (id == TIMER_LEAVE_TOOLWND)
{
 if (m_nTransparent > 255)
 {
  KillTimer(TIMER_LEAVE_TOOLWND);
  return;
 }

 AlphaCompositeBmp(m_bmpFront, m_bmpBKGround, m_bmpDest, m_nTransparent);
 Invalidate(FALSE);
 UpdateWindow();
 m_nTransparent += 50;
}
}
int CWndTool::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CUIWnd::OnCreate(lpCreateStruct) == -1)
 return -1;

// TODO:  Add your specialized creation code here
DWORD dwExStyle = ::GetWindowLong(m_hWnd, GWL_EXSTYLE);
dwExStyle |= WS_EX_TRANSPARENT;
SetWindowLong(m_hWnd, GWL_EXSTYLE, dwExStyle);

m_bmpFront = LoadBITMAPOBJ(CUIMgr::GetUIPathWithoutTitle()+_T("IDB_CHATWND_TOOL.bmp"));
m_bmpBKGround = LoadBITMAPOBJ(CUIMgr::GetUIPathWithoutTitle()+_T("IDW_CHAT_RIGHT_SHOW_HEADER.bmp"));

AlphaCompositeBmp(m_bmpFront, m_bmpBKGround, m_bmpDest, m_nTransparent);

return 0;
}

LRESULT CWndTool::OnMouseHover( WPARAM wParam, LPARAM lParam )
{
TRACE(_T("CWndShowHeaderTool::OnMouseHover %d/n"), IsMouseOver()?1:0);
if (m_bHaveOverTimer == TRUE)
{
 return 0;
}

m_isOverWnd   = true;
m_bHaveOverTimer = TRUE;
m_nTransparent  = 255;
 
KillTimer(TIMER_LEAVE_TOOLWND);
SetTimer(TIMER_OVER_TOOLWND, 50, NULL);

return 0;
}

LRESULT CWndTool::OnMouseLeave( WPARAM wParam, LPARAM lParam )
{
TRACE(_T("CWndShowHeaderTool::OnMouseLeave %d/n"), IsMouseOver()?1:0);

KillTimer(TIMER_OVER_TOOLWND);
SetTimer(TIMER_LEAVE_TOOLWND, 50, NULL);

m_isOverWnd   = false;
m_bHaveOverTimer = FALSE;
m_nTransparent  = 55;

return 0;
}

 


 

目录
相关文章
|
6月前
|
开发者 容器
小白必看 HarmonyOS Next HMRouter 轻松上手秘籍
本文详细介绍了HarmonyOS页面跳转解决方案——HMRouter的使用方法,帮助开发者快速上手。HMRouter封装了系统Navigation能力,提供路由拦截、页面生命周期管理、自定义转场动画等功能,简化开发流程。文章通过具体示例讲解模块内及跨模块页面跳转、路由传参、自定义动画、拦截器和生命周期管理等核心功能。同时,提供了丰富的资源链接,包括接口文档、高级动画教程和常见问题解答,适合初学者系统学习HMRouter的使用与原理。
443 9
小白必看 HarmonyOS Next HMRouter 轻松上手秘籍
|
Ubuntu Unix Linux
【Linux入门指南:掌握开源操作系统的基础知识】(一)
【Linux入门指南:掌握开源操作系统的基础知识】
349 1
【Linux入门指南:掌握开源操作系统的基础知识】(一)
|
Java Shell Android开发
Android11 有线网和wifi优先级设置
Android11 有线网和wifi优先级设置
1005 0
|
Python
python 股票数据分析、绘制K线图、价格走势图、收益率计算 完整代码+数据 可直接运行
python 股票数据分析、绘制K线图、价格走势图、收益率计算 完整代码+数据 可直接运行
404 0
python 股票数据分析、绘制K线图、价格走势图、收益率计算 完整代码+数据 可直接运行
|
C++ Windows
[√]window下子线程CCLOG导致主线程阻塞问题
[√]window下子线程CCLOG导致主线程阻塞问题
493 0
|
Linux
Linux 如何查看文件系统的块大小
Linux 如何查看文件系统的块大小
638 0
|
缓存 调度 流计算
【Flink】(十四)Flink Runtime 核心机制剖析2
【Flink】(十四)Flink Runtime 核心机制剖析2
287 0
【Flink】(十四)Flink Runtime 核心机制剖析2
|
消息中间件 存储 缓存
Android Handler与Looper原理浅析
Android Handler与Looper原理浅析
281 0
Android Handler与Looper原理浅析
如何用NotePad++查看二进制文件
如何用NotePad++查看二进制文件
2162 0
如何用NotePad++查看二进制文件
|
搜索推荐 机器人 Linux
微软发布新版命令行界面:Windows Terminal,开源六小时冲上GitHub第二
微软在Build开发者大会上公布了新款命令行界面:Windows Terminal,相较于老版的命令行工具,提供了许多新功能和个性化设置,意在改善Windows上的开发环境。它被设计为访问PowerShell,cmd.exe和Windows子系统Linux(WSL)等环境的中心位置。微软正在为想要调整终端应用程序的开发人员添加多个选项卡支持以及主题的自定义。Windows Terminal还支持表情符号和基于GPU的文本呈现。
1103 0
微软发布新版命令行界面:Windows Terminal,开源六小时冲上GitHub第二