亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

使用分層窗口及透明png圖片實(shí)現(xiàn)一個(gè)異形窗口

系統(tǒng) 1752 0

搞Windows程序的人盡皆知分層窗口能夠?qū)崿F(xiàn)很多不錯(cuò)的效果,之前看過一些異形窗口的實(shí)現(xiàn),所以就手癢也想自己搞一個(gè)玩一玩。自己動(dòng)手實(shí)現(xiàn)過程才發(fā)現(xiàn)還是有不少問題的。

基本思路是:
1.將窗口擴(kuò)展屬性設(shè)置為分層屬性WS_EX_LAYERED。
2.選一張透明的png圖片,并將其加載進(jìn)來。
3.創(chuàng)建與窗口兼容的內(nèi)存設(shè)備上下文,以及兼容位圖,將兼容位圖選入兼容設(shè)備上下文。
4.將png圖片繪制到內(nèi)存設(shè)備上下文中。
5.設(shè)置BLENDFUNCTION結(jié)構(gòu),調(diào)用UpdateLayeredWindow。


第一步設(shè)置窗口的分層屬性比較簡單:

      windowStyle =
      
         GetWindowLong(hWnd, GWL_EXSTYLE);
windowStyle 
      
      = windowStyle |
      
         WS_EX_LAYERED;
SetWindowLong(hWnd, GWL_EXSTYLE, windowStyle);
      
    


第二步是將png圖片加載到程序中,ATL的CImage和GDI+的Image這兩個(gè)類比較常用。使用CImage直接通過Load方法加載絕對(duì)路徑圖片或者內(nèi)存中的圖片,我這里就是使用CImage類實(shí)現(xiàn)。代碼:

      
        //
      
      
        CImage類方式加載圖片
      
      
        CImage img;
img.Load(TEXT(
      
      
        "絕對(duì)路徑
      
      
        png圖片
      
      
        "
      
      )); 
      
        //
      
      
        將圖片與類關(guān)聯(lián)起來
      
    

然后是使用Image類方式:

      
        //
      
      
        Image類方式加載圖片
      
      
Image* pImage = Image::FromFile(_T(
      
        "
      
      
        絕對(duì)路徑png圖片
      
      
        "
      
      ));
    


第三步比較繁瑣點(diǎn)。加載了圖片后就需要?jiǎng)?chuàng)建一個(gè)位圖句柄HBITMAP,創(chuàng)建位圖句柄有兩種方式:CreateCompatibleBitmap和CreateDIBSection這兩個(gè)函數(shù)。先介紹下這兩個(gè)函數(shù)。

      HBITMAP CreateCompatibleBitmap( HDC hdc, 
      
        //
      
      
         handle to DC
      
      
        int
      
       nWidth, 
      
        //
      
      
         width of bitmap, in pixels
      
      
        int
      
       nHeight 
      
        //
      
      
         height of bitmap, in pixels);
      
    
      HBITMAP CreateDIBSection( HDC hdc, 
      
        //
      
      
         handle to DC
      
      
    CONST BITMAPINFO *pbmi, 
      
        //
      
      
         bitmap data
      
      
    UINT iUsage, 
      
        //
      
      
         data type indicator
      
      
    VOID **ppvBits, 
      
        //
      
      
         bit values
      
      
    HANDLE hSection, 
      
        //
      
      
         handle to file mapping object
      
      
    DWORD dwOffset 
      
        //
      
      
         offset to bitmap bit values
      
      
);
    

首先看看CreateCompatibleBitmap函數(shù)的代碼:

      
        //
      
      
        CreateCompatibleBitmap函數(shù)創(chuàng)建
      
      
        hdc = GetDC(hWnd); 
      
        //
      
      
        hWnd為需要分層窗口的句柄
      
      
        hdcMem = CreateCompatibleDC(hdc); 
      
        //
      
      
        創(chuàng)建與hdc相兼容的內(nèi)存句柄
      
      
        hBitmap = CreateCompatibleBitmap(hdc, sz.cx, sz.cy); 
      
        //
      
      
        創(chuàng)建與hdc相兼容的位圖句柄
      
      
        SelectObject(hdcMem,(HGDIOBJ)hBitmap); 
      
        //
      
      
        將位圖選入內(nèi)存句柄作為畫板   
      
    

然后是使用CreateDIBSection函數(shù)的代碼:

      
        //
      
      
        CreateDIBSection函數(shù)創(chuàng)建
      
      
        hdc =
      
         GetDC(hWnd);
        hdcMem 
      
      =
      
         CreateCompatibleDC(hdc);

        BITMAPINFO bitmapinfo;
        bitmapinfo.bmiHeader.biSize 
      
      = 
      
        sizeof
      
      
        (BITMAPINFOHEADER);
        bitmapinfo.bmiHeader.biBitCount 
      
      = 
      
        32
      
      
        ;
        bitmapinfo.bmiHeader.biHeight 
      
      =
      
         sz.cy;
        bitmapinfo.bmiHeader.biWidth 
      
      =
      
         sz.cx;
        bitmapinfo.bmiHeader.biPlanes 
      
      = 
      
        1
      
      
        ;
        bitmapinfo.bmiHeader.biCompression
      
      =
      
        BI_RGB;
        bitmapinfo.bmiHeader.biXPelsPerMeter
      
      =
      
        0
      
      
        ;
        bitmapinfo.bmiHeader.biYPelsPerMeter
      
      =
      
        0
      
      
        ;
        bitmapinfo.bmiHeader.biClrUsed
      
      =
      
        0
      
      
        ;
        bitmapinfo.bmiHeader.biClrImportant
      
      =
      
        0
      
      
        ;
        bitmapinfo.bmiHeader.biSizeImage 
      
      = bitmapinfo.bmiHeader.biWidth * bitmapinfo.bmiHeader.biHeight * bitmapinfo.bmiHeader.biBitCount / 
      
        8
      
      
        ;

        hBitmap 
      
      = ::CreateDIBSection(hdcMem,&bitmapinfo, 
      
        0
      
      ,NULL, 
      
        0
      
      , 
      
        0
      
      
        );
        SelectObject(hdcMem,(HGDIOBJ)hBitmap);    
      
    


第四步,將png圖片繪制到內(nèi)存設(shè)備上下文中。這一步根據(jù)前面加載圖片的兩種方式對(duì)應(yīng)不同的繪制函數(shù)。

CImage類方式代碼:

      
        //
      
      
        CImage類方式代碼

      
      
        //
      
      
        將img關(guān)聯(lián)的png圖片繪制到內(nèi)存句柄中
      
      
img.Draw(hdcMem, 
      
        0
      
      , 
      
        0
      
      , sz.cx, sz.cy, 
      
        0
      
      , 
      
        0
      
      
        , sz.cx, sz.cy);

      
      
        //
      
      
        hdcMem為內(nèi)存兼容句柄,之后四個(gè)參數(shù)表明了在內(nèi)存兼容句柄中繪制的位置,最后四個(gè)參數(shù)表示了img關(guān)聯(lián)的png圖片的位置
      
    

然后是Image類方式處理代碼:

      
        //
      
      
        Image類方式代碼
      
      
        Graphics g(hMemDC);
g.DrawImage( pImage, 
      
      
        0
      
      , 
      
        0
      
      );
    


第五步:設(shè)置BLENDFUNCTION結(jié)構(gòu),調(diào)用UpdateLayeredWindow。

設(shè)置BLENDFUNCTION結(jié)構(gòu)代碼如下:

      
        BLENDFUNCTION  bf;
bf.AlphaFormat 
      
      = AC_SRC_ALPHA;
      
        //
      
      
        源位圖具有Alpha通道
      
      
bf.BlendFlags = 
      
        0
      
      ;
      
        //
      
      
        必須為0
      
      
bf.BlendOp = AC_SRC_OVER;
      
        //

      
      bf.SourceConstantAlpha = 
      
        255
      
      ;
      
        //
      
      
        設(shè)置透明度
      
    

然后就是調(diào)用UpdateLayeredWindow函數(shù)了

      UpdateLayeredWindow(hWnd, hdc, NULL, &sz, hdcMem, &pt, NULL, &bf, ULW_ALPHA);
    

看看MSDN對(duì)UpdateLayeredWindow函數(shù)的介紹:

      
        BOOL UpdateLayeredWindow(
    HWND hwnd,
      
      
        //
      
      
        需要分層的窗口句柄
      
      
    HDC hdcDst, 
      
        //
      
      
        需要分層窗口設(shè)備句柄
      
      
    POINT *pptDst,
      
        //
      
      
        窗口位置不發(fā)生變化可以設(shè)置為NULL
      
      
    SIZE *psize,
      
        //
      
      
        窗口大小不發(fā)生變化可以設(shè)置為NULL
      
      
    HDC hdcSrc,
      
        //
      
      
        繪制源的設(shè)備句柄
      
      
    POINT *pptSrc,
      
        //

      
          COLORREF crKey,
      
        //
      
      
        指定一個(gè)透明色,使用ULW_COLORKEY標(biāo)志時(shí)有效,也就是說crKey為白色時(shí)候,那么位圖上所有白色的地方均為透明,其他地方不透明
      
      
    BLENDFUNCTION *pblend,
      
        //
      
      
        之前介紹過了
      
      
    DWORD dwFlags
      
        //
      
      
        ULW_ALPHA使用Alpha通道,ULW_COLORKEY使用crKey作為透明色,ULW_OPAQUE不透明
      
      
);
    

這樣異形窗口就算完成了。


整理以下代碼如下:

      LONG windowStyle =
      
         GetWindowLong(hWnd, GWL_EXSTYLE);
windowStyle 
      
      = windowStyle |
      
         WS_EX_LAYERED;
SetWindowLong(hWnd, GWL_EXSTYLE, windowStyle);

CImage img;
img.Load(TEXT(
      
      
        "
      
      
        png圖片
      
      
        "
      
      
        ));

SIZE sz;
      
      
        //
      
      
        圖片大小
      
      
sz.cx =
      
         img.GetWidth();
sz.cy 
      
      =
      
         img.GetHeight();

SetWindowPos(hWnd, NULL, 
      
      
        0
      
      , 
      
        0
      
      , sz.cx, sz.cy, SWP_NOREDRAW);
      
        //
      
      
        將窗口大小設(shè)置為圖片大小使之相互合適
      
      
        
HDC hdc 
      
      = GetDC(hWnd);
      
        //
      
      
        獲取窗口設(shè)備句柄
      
      
HDC hdcMem = CreateCompatibleDC(hdc);
      
        //
      
      
        創(chuàng)建一個(gè)與hdc相兼容的內(nèi)存設(shè)備句柄
      
      
HBITMAP    hBitmap =
      
         CreateCompatibleBitmap(hdc, sz.cx, sz.cy);
SelectObject(hdcMem,(HGDIOBJ)hBitmap);
img.Draw(hdcMem, 
      
      
        0
      
      , 
      
        0
      
      , sz.cx, sz.cy, 
      
        0
      
      , 
      
        0
      
      
        , sz.cx, sz.cy);

POINT pt;
pt.x 
      
      = 
      
        0
      
      
        ;
pt.y 
      
      = 
      
        0
      
      
        ;

BLENDFUNCTION  bf;
bf.AlphaFormat 
      
      =
      
         AC_SRC_ALPHA;
bf.BlendFlags 
      
      = 
      
        0
      
      
        ;
bf.BlendOp 
      
      =
      
         AC_SRC_OVER;
bf.SourceConstantAlpha 
      
      = 
      
        255
      
      
        ;

UpdateLayeredWindow(hWnd, hdc, NULL, 
      
      &sz, hdcMem, &pt, NULL, &
      
        bf, ULW_ALPHA);
ReleaseDC(hWnd, hdc);
      
    


說說遇到的問題,最開始就碰到了一個(gè)問題發(fā)現(xiàn)png圖片沒有辦法產(chǎn)生異形的效果,然后才發(fā)現(xiàn)原來我使用的png圖片不是透明png圖片。

當(dāng)png透明圖片問題解決后,發(fā)現(xiàn)窗口出現(xiàn)后,本來那個(gè)應(yīng)該是透明的地方卻是白色不透明的了。這個(gè)問題網(wǎng)上也是有介紹的,我在 這里 得到了答案。下面我把原因重新貼一下:

PNG圖片的透明背景總是一片白色,后來才發(fā)現(xiàn)這其實(shí)是微軟GDI+的設(shè)計(jì)問題,PNG圖片是ARGB,使用GDI+載入圖片的時(shí)候,GDI+會(huì)默認(rèn)已經(jīng)進(jìn)行了預(yù)剩運(yùn)算(PARGB),即每象素的實(shí)際值是已經(jīng)和ALPHA值按比例相乘的結(jié)果,實(shí)際上它根本就沒有做預(yù)乘,在使用透明圖片的象素ALPHA通道的時(shí)候,CImage內(nèi)部正是調(diào)用的AlphaBlend,沒有預(yù)乘的圖當(dāng)作預(yù)乘的圖片處理的結(jié)果就是這相當(dāng)于一張和純白背景進(jìn)行了預(yù)剩,所以圖象總是出現(xiàn)白色背景。

下面給出解決這個(gè)問題的代碼,代碼來源 這里 ,處理還是比較簡單的:

      
        if
      
       (pImage->GetBPP() == 
      
        32
      
      ) 
      
        //
      
      
        確認(rèn)該圖像包含Alpha通道
      
      
           {
       
      
      
        for
      
       (inti=
      
        0
      
      ; i<pImage->GetWidth();i++
      
        )
       {
            
      
      
        for
      
      (
      
        int
      
       j=
      
        0
      
      ; j<pImage->GetHeight(); j++
      
        )
            {
                
      
      
        byte
      
      *pByte = (
      
        byte
      
      *)pImage->
      
        GetPixelAddress(i, j);
                pByte[
      
      
        0
      
      ]= pByte[
      
        0
      
      ] * pByte[
      
        3
      
      ]/ 
      
        255
      
      
        ;
                pByte[
      
      
        1
      
      ]= pByte[
      
        1
      
      ] * pByte[
      
        3
      
      ]/ 
      
        255
      
      
        ;
                pByte[
      
      
        2
      
      ]= pByte[
      
        2
      
      ] * pByte[
      
        3
      
      ]/ 
      
        255
      
      
        ;
            }
       }
   }
      
    

這樣異形窗口也算是完成了,但是這樣生成的exe文件需要依賴外部的png圖片,所以我應(yīng)該把那張png圖片放到資源文件中,然后直接生成的exe就包含了那張png圖片。這就涉及到了如何從資源中加載圖片的問題。

使用分層窗口及透明png圖片實(shí)現(xiàn)一個(gè)異形窗口


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 97色资源| 欧美三级午夜理伦三级小说 | 久草视频网 | 欧美在线观看一区二区 | 日韩成人精品视频 | 久久亚洲国产精品五月天 | 182午夜在线观看 | 色综合亚洲综合网站综合色 | 农村三级孕妇视频在线 | 国产欧美日韩精品一区二区三区 | 日本精品在线观看视频 | 精品无人区乱码1区2区3区免费 | 国产视频观看 | 免费一看一级毛片人 | 中国jizz日本 | 夜夜操狠狠操 | 亚洲精品一区最新 | 亚洲狠狠97婷婷综合久久久久 | 国产成人免费观看在线视频 | 农村妇女又色黄一级毛片 | 中文字幕亚洲一区二区v@在线 | 日本一区二区三区四区在线观看 | 精品国产免费久久久久久 | 九九热免费视频 | 国产精品嫩草影院奶水 | 国产97在线 | 亚洲 | 可以免费观看欧美一级毛片 | 免费毛片在线 | 日本高清在线精品一区二区三区 | 久久视频国产 | 日韩在线第三页 | 国产亚洲精品线观看77 | 欧美日本一本线在线观看 | 婷婷五月情 | 日本精品久久久久中文字幕 1 | 亚洲国产片 | 奇米影视亚洲色图 | 国产成人综合日韩精品婷婷九月 | 久久精品国产亚洲精品 | 九九热在线视频免费观看 | 精品久久久久久18免费看 |