#include "LayeredWindow.h" namespace ezui { std::vector g_layeredWnds; Timer g_layeredWndTimer; //WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT LayeredWindow::LayeredWindow(int width, int height, HWND owner, DWORD dwStyle, DWORD dwExStyle) :BorderlessWindow(width, height, owner, dwStyle, dwExStyle | WS_EX_LAYERED) { //初始化全局绘制计时器 if (g_layeredWndTimer.Tick == NULL) { g_layeredWndTimer.Interval = 5; g_layeredWndTimer.Tick = [](Timer* t) { t->Stop(); Invoke([]() { for (auto& it : g_layeredWnds) { it->Paint(); } }); }; } //添加到全局绘制队列 g_layeredWnds.push_back(this); //获取公共数据 auto* publicData = this->GetPublicData(); publicData->InvalidateRect = [this](const Rect& rect) ->void { //标记窗口无效区域 this->InvalidateRect(rect); }; publicData->Refresh = [this]()->void { //立即更新窗口中的无效区域 this->Paint(); }; //获取客户区大小 创建一个位图给窗口绘制 Size sz = GetClientRect().GetSize(); m_winBitmap = new Bitmap(sz.Width, sz.Height); } LayeredWindow::~LayeredWindow() { if (m_winBitmap) { delete m_winBitmap; } //从全局中移除 auto itor = std::find(g_layeredWnds.begin(), g_layeredWnds.end(), this); if (itor != g_layeredWnds.end()) { g_layeredWnds.erase(itor); } } void LayeredWindow::InvalidateRect(const Rect& _rect) { //将此区域添加到无效区域 m_invalidateRect.push_back(_rect); //timer延迟绘制 g_layeredWndTimer.Start(); } void LayeredWindow::BeginPaint(Rect* out_rect) { const Rect& clientRect = GetClientRect(); int Width = clientRect.Width; int Height = clientRect.Height; //将所有无效区域并集 for (auto& it : m_invalidateRect) { Rect rect = it; //这段代码是保证重绘区域一定是在窗口内 if (rect.X < 0) { rect.Width += rect.X; rect.X = 0; if (rect.Width < 0) rect.Width = 0; } if (rect.Y < 0) { rect.Height += rect.Y; rect.Y = 0; if (rect.Height < 0) rect.Height = 0; } if (rect.GetRight() > Width) { rect.Width = Width - rect.X; if (rect.Width < 0) rect.Width = 0; } if (rect.GetBottom() > Height) { rect.Height = Height - rect.Y; if (rect.Height < 0) rect.Height = 0; } //并集 Rect::Union(*out_rect, *out_rect, rect); } } void LayeredWindow::EndPaint() { m_invalidateRect.clear(); } void LayeredWindow::Paint() { if (IsVisible()) { Rect invalidateRect; BeginPaint(&invalidateRect); if ((m_winBitmap && !invalidateRect.IsEmptyArea())) { m_winBitmap->Earse(invalidateRect);//清除背景 HDC winHDC = m_winBitmap->GetDC(); #if 1 //不使用双缓冲 DoPaint(winHDC, invalidateRect); #else //使用双缓冲 Bitmap doubleBuff(m_winBitmap->Width(), m_winBitmap->Height()); DoPaint(doubleBuff.GetHDC(), invalidateRect); //使用BitBlt函数进行复制到winHDC //如果窗体不规则 不适用于BitBlt进行复制 ::BitBlt(winHDC, invalidateRect.X, invalidateRect.Y, invalidateRect.Width, invalidateRect.Height, doubleBuff.GetHDC(), invalidateRect.X, invalidateRect.Y, SRCCOPY); #endif UpdateLayeredWindow(winHDC);//updatelaredwindow 更新窗口 EndPaint(); } } } LRESULT LayeredWindow::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { default: break; } return __super::WndProc(uMsg, wParam, lParam); } void LayeredWindow::OnSize(const Size& sz) { __super::OnSize(sz); if (m_winBitmap) { delete m_winBitmap; } m_winBitmap = new Bitmap(sz.Width, sz.Height); Invalidate(); } void LayeredWindow::UpdateLayeredWindow(HDC hdc) { const Rect& _rectClient = GetClientRect(); POINT point{ _rectClient.X,_rectClient.Y }; SIZE size{ _rectClient.Width, _rectClient.Height }; BLENDFUNCTION blendFunc{ 0 }; blendFunc.SourceConstantAlpha = 255 * this->Opacity; blendFunc.BlendOp = AC_SRC_OVER; blendFunc.AlphaFormat = AC_SRC_ALPHA; blendFunc.BlendFlags = 0; ::UpdateLayeredWindow(Hwnd(), NULL, NULL, &size, hdc, &point, 0, &blendFunc, ULW_ALPHA);//透明 } }