DNF阿拉德游戏论坛

 找回密码
 立即注册
搜索
查看: 60|回复: 0
打印 上一主题 下一主题

[PVF] 装备属性相关:在VC6.0中用GDI调用png图片实现半透明渐变特效

[复制链接]
  • TA的每日心情
    无聊
    2020-5-4 11:24
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    354

    主题

    354

    帖子

    568

    积分

    网站编辑

    Rank: 8Rank: 8

    积分
    568
    怒气
    46
    声望
    81
    战力
    6
    跳转到指定楼层
    楼主
    发表于 2020-4-1 16:34:56 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式



    一、概述
      GDI+的应用使得平面图形图象编程变的更加容易,本文以一个基于对话框的时钟程序为例,在VC6.0中调用*.png图片实现半透明渐变窗口,该程序实现了指针式和数字式两种时钟显示方式。窗口实现了半透明渐变窗口、窗口拖动无移动矩形框、隐藏了任务栏窗体按钮等。
    效果图如下:

    图一 程序执行后与WindowXP桌面背景效果图
    二、准备工作
    1、图片资源准备工作。首先在Photoshop中编辑好时钟的背景、时针、分针以及数字时钟显示方式的所有图片,如下图:将这些图片保存成为带透明通道的.png格式(GDI+调用显示时能够透明调背景)。这样程序中图片资源就准备好了。
    2、下面开始做好在VC6.0下展开此项工作的基本准备工作。
    (1)、下载gdiplus forVC6.0的SDK,(总共两兆多)
    (2)、在C盘建立文件夹“GDI+”将开发包拷贝在里面,亦即建立如下路径,以便例子代码顺利编译(当然你可以放到任意你喜欢的地方,只要在你的Project中正确包含路径即可!)。
    C:\GDI+\Includes
    C:\GDI+\Lib
    C:\GDI+\gdiplus.dll
    (3)在stdAfx.h中添加对GDI+环境的设置
    #define UNICODE
    #ifndef ULONG_PTR
    #define ULONG_PTR unsigned long*
    #endif
    #include "c:\gdi+\includes\gdiplus.h" ////请修改为你的头文件路径
    using namespace Gdiplus;
    #pragma comment(lib, "c:\\gdi+\\lib\\gdiplus.lib") ////请修改为你的.lib文件路径
    (4)在GDIPClock.cpp中编辑app的InitInstance()中添加如下代码进行GDI+的初始化工作
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    ......
    //在对话框程序结束后
    //关闭gdiplus的环境
    GdiplusShutdown(gdiplusToken);
    三、程序的实现全过程
    1、建立一个基于对话框的Project,这里的名称为GDIPClock
    2、在GDIPClockDlg.h中定义所有类成员变量,包括所有图片的指针和图片的长宽尺寸信息。
           Image *m_pImageClock;
           Image *m_pImageClock1;
           Image *m_pImageHHour;
           Image *m_pImageHMinu;
           Image *m_pImageHSec;
           Image *m_pImageNum;
           int m_BakWidth , m_BakHeight ;
           int m_HourWidth, m_HourHeight;
           int m_MinuWidth , m_MinuHeight;
           int m_SecWidth  , m_SecHeight ;
           HINSTANCE hFuncInst ;
           Typedef  BOOL (WINAPI*MYFUNC)(HWND,HDC,POINT*,SIZE*,HDC,POINT*,
    COLORREF,BLENDFUNCTION*,DWORD);         
           MYFUNC UpdateLayeredWindow;
      在这一步中需要特别说明的是,在创建透明窗口式需要调用一个Windows API函数UpdateLayeredWindow(),该函数在.net以上的版本的SDK中有申明,但是在VC6.0下要调用要么下载200多兆的高版本SDK,要么从动态链接库“User32.dll”中调用,这里选择从“User32.dll”中调用。以上定义中后三项就是为此作准备的。
    3、在对话框的OnCreate()中添加如下代码:对2的函数和成员变量进行初始化!(其中ImageFromIDResource()函数为从资源中载入Png图像的一个方法!)
    int CGDIPClockDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
           if (CDialog::OnCreate(lpCreateStruct) == -1)
                  return -1;
        hFuncInst = LoadLibrary("User32.DLL");
           BOOL bRet=FALSE;
           if(hFuncInst)
                  UpdateLayeredWindow=(MYFUNC)GetProcAddress(hFuncInst, "UpdateLayeredWindow");
           else
           {
                  AfxMessageBox("User32.dll ERROR!");
                  exit(0);
           }
           //初始化gdiplus的环境
           // Initialize GDI+.
           m_Blend.BlendOp=0; //theonlyBlendOpdefinedinWindows2000
           m_Blend.BlendFlags=0; //nothingelseisspecial...
           m_Blend.AlphaFormat=1; //...
           m_Blend.SourceConstantAlpha=255;//AC_SRC_ALPHA

        // png图片添加到资源中了在"PNG"下:所以这里可以从资源中调用,
        // 这里Image没有提供字节调用资源中图像的函数,
        // ImageFromIDResource()是通过资源名称"PNG"和资源ID号将图像
        // 的Image指针传递给指针应用。来完成的。

        ImageFromIDResource(IDR_PNGBAK1,"PNG",m_pImageClock1);
        ImageFromIDResource(IDR_PNGNUM,"PNG",m_pImageNum);
        ImageFromIDResource(IDR_PNGBAK,"PNG",m_pImageClock);
        ImageFromIDResource(IDR_PNGHOUR,"PNG",m_pImageHHour);
        ImageFromIDResource(IDR_PNGMIN,"PNG",m_pImageHMinu);
        ImageFromIDResource(IDR_PNGSEC,"PNG",m_pImageHSec);
           m_BakWidth  =m_pImageClock->GetWidth();
           m_BakHeight =m_pImageClock->GetHeight();
           m_HourWidth =m_pImageHHour->GetWidth();
           m_HourHeight=m_pImageHHour->GetHeight();
           m_MinuWidth =m_pImageHMinu->GetWidth();
           m_MinuHeight=m_pImageHMinu->GetHeight();
           m_SecWidth  =m_pImageHSec->GetWidth();
           m_SecHeight =m_pImageHSec->GetHeight();
           ::SetWindowPos(m_hWnd, HWND_TOPMOST,0,0,m_BakWidth,m_BakHeight,SWP_NOSIZE|SWP_NOMOVE);   
           return 0;
    }
    4.在OnInitDialog()种添加如下代码对调用透明窗体初始化和设置时钟进行刷新,代码意义有注解:
    //启动后立刻更新窗口样式为透明窗体
           UpdateClockDisplay();
           SetTimer(1,500,NULL);
    //去除任务栏窗口对应按钮
           ModifyStyleEx (WS_EX_APPWINDOW,WS_EX_TOOLWINDOW );
    void CGDIPClockDlg::OnTimer(UINT nIDEvent)
    {
           // TODO: Add your message handler code here and/or call default
           UpdateClockDisplay();
           CDialog::OnTimer(nIDEvent);
    }
    5、透明窗体创建于刷新,均调用以下函数完成,函数的参数表示整个窗体的透明度
    在该函数中包括了GDI+中对Image.DrawImage()函数的集中重载方式的使用,还有在GDI+中图像变换矩阵的使用初步研究。
    BOOL CGDIPClockDlg::UpdateClockDisplay(int Transparent)
    {
           HDC hdcTemp=GetDC()->m_hDC;
           m_hdcMemory=CreateCompatibleDC(hdcTemp);
           HBITMAP hBitMap=CreateCompatibleBitmap(hdcTemp,m_BakWidth,m_BakHeight);
           SelectObject(m_hdcMemory,hBitMap);
           if(Transparent<0||Transparent>100)     Transparent=100;

           m_Blend.SourceConstantAlpha=int(Transparent*2.55);
           HDC hdcScreen=::GetDC (m_hWnd);
           RECT rct;
           GetWindowRect(&rct);
           POINT ptWinPos={rct.left,rct.top};
           Graphics graph(m_hdcMemory);

           Point points[] = { Point(0, 0),
                                 Point(m_BakWidth, 0),
                                          Point(0, m_BakHeight)
                                       };
           static bool bFly=false;
           bFly?graph.DrawImage(m_pImageClock, points, 3): graph.DrawImage(m_pImageClock1, points, 3);
           bFly=!bFly;
            int OxyX=140;//m_BakWidth/2+8;
           int OxyY=90;//m_BakHeight/2+10;
           SYSTEMTIME SystemTime;   // address of system time structure
           GetLocalTime(&SystemTime);

           // 定义一个单位矩阵,坐标原点在表盘中央
           Matrix matrixH(1,0,0,1,OxyX,OxyY);
           // 时针旋转的角度度
           matrixH.Rotate(SystemTime.wHour*30+SystemTime.wMinute/2.0-180);
           Point pointsH[] = { Point(0, 0),Point(m_HourWidth, 0),Point(0, m_HourHeight)};
           matrixH.Translate(-m_HourWidth/2,-m_HourHeight/6);
           // 用该矩阵转换points
           matrixH.TransformPoints( pointsH, 3);
           graph.DrawImage (m_pImageHHour,pointsH, 3);

           // 定义一个单位矩阵,坐标原点在表盘中央
           Matrix matrixM(1,0,0,1,OxyX,OxyY);
           // 分针旋转的角度度
           matrixM.Rotate(SystemTime.wMinute*6-180);
           Point pointsM[] = { Point(0, 0),Point(m_MinuWidth, 0),Point(0, m_MinuHeight)};
           matrixM.Translate(-m_MinuWidth/2,-m_MinuHeight/6);
           // 用该矩阵转换pointsM
           matrixM.TransformPoints( pointsM, 3);
           graph.DrawImage (m_pImageHMinu,pointsM, 3);

           // 定义一个单位矩阵,坐标原点在表盘中央
           Matrix matrix(1,0,0,1,OxyX,OxyY);
           // 秒针旋转的角度度
           matrix.Rotate(SystemTime.wSecond*6-180);
           Point pointsS[] = { Point(0, 0),Point( m_SecWidth,0),Point(0,m_SecHeight )};
           matrix.Translate(-m_SecWidth/2,-m_SecHeight/7);
           // 用该矩阵转换pointsS
           matrix.TransformPoints( pointsS, 3);
           graph.DrawImage (m_pImageHSec,pointsS, 3);
    //HH:MM:SS

           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,0, 0, 14*(SystemTime.wHour/10), 0,14,23,UnitPixel);
           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,20,0, 14*(SystemTime.wHour%10), 0,14,23,UnitPixel);
          //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
          graph.DrawImage(m_pImageNum,20*2,0, 140, 0,14,23,UnitPixel);
           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,20*3, 0, 14*(SystemTime.wMinute/10), 0,14,23,UnitPixel);
           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,20*4,0, 14*(SystemTime.wMinute%10), 0,14,23,UnitPixel);
           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,20*5,0, 140, 0,14,23,UnitPixel);
           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,20*6, 0, 14*(SystemTime.wSecond/10), 0,14,23,UnitPixel);
           //该函数从m_pImageClock中剪切指定rect中的像素draw到指定位置
           graph.DrawImage(m_pImageNum,20*7,0, 14*(SystemTime.wSecond%10), 0,14,23,UnitPixel);

           SIZE sizeWindow={m_BakWidth,m_BakHeight};
           POINT ptSrc={0,0};
           DWORD dwExStyle=GetWindowLong(m_hWnd,GWL_EXSTYLE);
           if((dwExStyle&0x80000)!=0x80000)
                  SetWindowLong(m_hWnd,GWL_EXSTYLE,dwExStyle^0x80000);

           BOOL bRet=FALSE;
           bRet= UpdateLayeredWindow( m_hWnd,hdcScreen,&ptWinPos,
                                &sizeWindow,m_hdcMemory,&ptSrc,0,&m_Blend,2);
           graph.ReleaseHDC(m_hdcMemory);
           ::ReleaseDC(m_hWnd,hdcScreen);
           hdcScreen=NULL;
           ::ReleaseDC(m_hWnd,hdcTemp);
           hdcTemp=NULL;
           DeleteObject(hBitMap);
           DeleteDC(m_hdcMemory);
           m_hdcMemory=NULL;
           return bRet;
    }
    BOOL CGDIPClockDlg::ImageFromIDResource(UINT nID, LPCTSTR sTR,Image * &pImg)
    {
           HINSTANCE hInst = AfxGetResourceHandle();
           HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // type
           if (!hRsrc)
                  return FALSE;
           // load resource into memory
           DWORD len = SizeofResource(hInst, hRsrc);
           BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
           if (!lpRsrc)
                  return FALSE;
           // Allocate global memory on which to create stream
           HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
           BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
           memcpy(pmem,lpRsrc,len);
           IStream* pstm;
           CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
           // load from stream
           pImg=Gdiplus::Image::FromStream(pstm);
           // free/release stuff
           GlobalUnlock(m_hMem);
           pstm->Release();
           FreeResource(lpRsrc);
    }
    void CGDIPClockDlg::OnLButtonDown(UINT nFlags, CPoint point)
    {
            //禁止显示移动矩形窗体框
            ::SystemParametersInfo(SPI_SETDRAGFULLWINDOWS,TRUE,NULL,0);
            //非标题栏移动整个窗口
            SendMessage(WM_SYSCOMMAND,0xF012,0);
            // PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y));
            CDialog::OnLButtonDown(nFlags, point);


    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|DNF阿拉德游戏论坛 ( 蜀ICP备2024115554号

    GMT+8, 2025-6-12 05:15 , Processed in 0.221921 second(s), 17 queries , File On.

    Powered by Discuz! X3.3 网站地图 Auther by PAnoEAde & 地下城与勇士论坛

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表