• C++ 异形窗口


    本文参考:Duilib源码

    原理:分层窗口,通过定时器和手动触发绘画窗口
    由于GDI对透明通道支持不是很好,最好选择GDI+进行绘画。

    1.设置窗口属性WS_EX_LAYERED和绘画定时器
     DWORD dwStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
     SetWindowLong(hWnd, GWL_EXSTYLE, dwStyle | WS_EX_LAYERED);
     ::SetTimer(hWnd, LAYEREDUPDATE_TIMERID, 10L, NULL);
    
    • 1
    • 2
    • 3
    2.UpdateLayeredWindow绘画窗口并且支持透明度设置
    void onPaint()
    {
    	if (::IsIconic(hWnd))return 0;
    	 RECT rtWindow;
         GetWindowRect(hWnd, &rtWindow);
         COLORREF *pOffscreenBits = NULL;
         PAINTSTRUCT ps;
         HDC hdc = BeginPaint(hWnd, &ps);
         HDC hDcOffscreen = ::CreateCompatibleDC(hdc);
         //创建支持透明通道的BITMAP,pOffscreenBits位图的起始位置,默认色值为ARGB。默认值为0
         HBITMAP hbmpOffscreen = CreateRGBA32Bitmap(hdc, rtWindow.right - rtWindow.left, rtWindow.bottom - rtWindow.top, &pOffscreenBits);
         HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(hDcOffscreen, hbmpOffscreen);
    
    	 RECT rtPaint = { 0,0,rtWindow.right - rtWindow.left, rtWindow.bottom - rtWindow.top };
         PaintContent(hDcOffscreen, rtPaint);
         
    	//绘画分层窗口,将BITMAP展示出来,如果PaintContent内容为空,则整个界面什么都没有,因为完全透明
    	BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
     	SIZE sizeWnd = { rtWindow.right - rtWindow.left, rtWindow.bottom - rtWindow.top };
        POINT ptPos = { rtWindow.left, rtWindow.top };
    	POINT ptSrc = { 0,0 };
    	UpdateLayeredWindow(hWnd, hdc, &ptPos, &sizeWnd, hDcOffscreen, &ptSrc, 0, &bf, ULW_ALPHA);
        DeleteDC(hDcOffscreen);
        DeleteObject(hbmpOffscreen);
        EndPaint(hWnd, &ps);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    //创建32位支持透明通道的位图RGBA
    HBITMAP CreateRGBA32Bitmap(HDC hDC, int cx, int cy, COLORREF** pBits)
    {
    	LPBITMAPINFO lpbiSrc = NULL;
    	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
    	if (lpbiSrc == NULL) return NULL;
    
    	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	lpbiSrc->bmiHeader.biWidth = cx;
    	lpbiSrc->bmiHeader.biHeight = cy;
    	lpbiSrc->bmiHeader.biPlanes = 1;
    	lpbiSrc->bmiHeader.biBitCount = 32;
    	lpbiSrc->bmiHeader.biCompression = BI_RGB;
    	lpbiSrc->bmiHeader.biSizeImage = cx * cy;
    	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
    	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
    	lpbiSrc->bmiHeader.biClrUsed = 0;
    	lpbiSrc->bmiHeader.biClrImportant = 0;
    
    	HBITMAP hBitmap = CreateDIBSection(hDC, lpbiSrc, DIB_RGB_COLORS, (void**)pBits, NULL, NULL);
    	delete[] lpbiSrc;
    	return hBitmap;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //通过gdi的方式实现支持Alpha填充背景色的功能
    void DrawColor(HDC hDC, const RECT& rc, DWORD color)
    {
        COLORREF* pColors = nullptr;
        HDC hMemDC = ::CreateCompatibleDC(hDC);
        HBITMAP hBitMap = CreateRGBA32Bitmap(hDC, rc.right - rc.left, rc.bottom - rc.top, &pColors);
        ::SelectObject(hMemDC, hBitMap);
    
        COLORREF* pTempOffscreenBits = NULL;
        for (LONG y = 0; y < rc.bottom - rc.top; ++y) {
            for (LONG x = 0; x < rc.right - rc.left; ++x) {
                pTempOffscreenBits = pColors + y * (rc.right - rc.left) + x;
               
                *pTempOffscreenBits = color;
            }
        }
        BLENDFUNCTION bf = { AC_SRC_OVER, 0, GetAValue(color), AC_SRC_ALPHA };
        AlphaBlend(hDC, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, hMemDC, 0, 0, rc.right - rc.left, rc.bottom - rc.top, bf);
        DeleteObject(hBitMap);
        DeleteDC(hMemDC);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    void DrawPng(HDC hDC,RECT rtDest)
    {
    	int w = 0, h = 0, channels = 0;
    	stbi_uc* pdata = stbi_load("icon_user_disk.png", &w, &h, &channels, 4);
        if (pdata)
        {
    		COLORREF* pColors = nullptr;
    		HDC hMemDC = ::CreateCompatibleDC(hDC);
    		HBITMAP hBitMap = CreateRGBA32Bitmap(hDC, w, h, &pColors);
    		::SelectObject(hMemDC, hBitMap);
            //BGRA -> RGBA
            COLORREF* dest = (COLORREF*)pdata;
            for (int x = 0;x < w;++x)
            {
                for (int y = 0;y < h;++y)
                {
                    stbi_uc* bDestColorBits = (stbi_uc*)(&pColors[x * h + y]);
                    stbi_uc* bsrcColorBits = (stbi_uc*)(&dest[x * h + y]);
                    /* BGRA -> RGBA */
                    bDestColorBits[3] = bsrcColorBits[3];
                    bDestColorBits[2] = bsrcColorBits[0];
                    bDestColorBits[1] = bsrcColorBits[1];
                    bDestColorBits[0] = bsrcColorBits[2];
                }
            }
    		BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
    		AlphaBlend(hDC, rtDest.left, rtDest.top, rtDest.right - rtDest.left, rtDest.bottom - rtDest.top, hMemDC, 0, 0, w, h, bf);
    		DeleteObject(hBitMap);
    		DeleteDC(hMemDC);
        }
    	STBI_FREE(pdata);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    void PaintContent(HDC hDc, RECT rcPaint)
    {
    	RECT rtPaint = { 0,0,rcPaint.right - rcPaint.left, rcPaint.bottom - rcPaint.top };
    	RECT rcItem1 = { rtPaint.left + 10,rtPaint.top + 10,rcItem1.left + 100,rcItem1.top + 100 };
    
    	RECT rcItem2 = { rcItem1.right + 10,rtPaint.top + 10,rcItem2.left + 100,rcItem2.top + 100 };
    	//DrawColor(hDc, rcItem1, 0xad00ff00);
    
    	HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SMALL));
    	DrawIcon(hDc, rcItem2.right + 10, rcItem2.top, hIcon);
    	::SetBkMode(hDc, TRANSPARENT);
    	::SetTextColor(hDc, RGB(255, 0, 0));
    	std::wstring strText = L"Hellow word!!中国";
    	DrawText(hDc, strText.c_str(), strText.size(), &rcItem2, DT_SINGLELINE | DT_VCENTER);
    
    	RECT rcItem3 = { rcItem1.right + 10,rcItem1.bottom + 10,rcItem3.left + 100,rcItem3.top + 100 };
    	Gdiplus::Image img(L"E:\\work\\PMS\\yiletu\\xiaoyi\\xyBar\\binx86\\Debug\\skin\\res\\yiletoo.png");
    	Gdiplus::Graphics g(hDc);
    	g.DrawImage(&img, (INT)rcItem3.left, (INT)rcItem3.top);
        Gdiplus::Font ft(L"宋体", 18);
        Gdiplus::PointF pt = { (REAL)rcItem3.right + 10.0f,(REAL)rcItem3.top };
        Gdiplus::SolidBrush b(Color(0x99, 0xff, 0, 0));
        g.SetTextRenderingHint(TextRenderingHintAntiAliasGridFit);
        g.SetPixelOffsetMode(PixelOffsetModeDefault);
        g.SetCompositingMode(CompositingModeSourceOver);
        g.SetCompositingQuality(CompositingQualityDefault);
        g.DrawString(strText.c_str(), strText.size(), &ft, pt, &b);
    
        Gdiplus::RectF rtf = { (REAL)rcItem1.left,(REAL)rcItem1.top,(REAL)rcItem1.right - rcItem1.left,(REAL)rcItem1.bottom - rcItem1.top };
        g.FillRectangle(&b, rtf);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    效果图:
    在这里插入图片描述

  • 相关阅读:
    AI 智能时代,如何快速搞懂向量数据库库?
    立创EDA——PCB的走线(五)
    拿什么拯救你?这暴热的天气!只能在家用python分析做个可视化康康
    驱动和嵌入式开发其他注意事项——Volatile 关键字
    后端接口性能优化分析-多线程优化
    C语言入门(四):有关逻辑的运算符和表达式
    ThemeForest – Canvas 7.2.0 – 多用途 HTML5 模板
    苹果录音删除了可以恢复吗?请收藏好这些方法!
    Android 查看按键信息的常用命令详解
    达利欧《原则》读书思考笔记
  • 原文地址:https://blog.csdn.net/CAir2/article/details/133905277