在VC6.0中用GDI+调用png图片实现半透明渐变的特效窗口

http://www.vckbase.com/document/viewdoc/?id=1745


一、概述

  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);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Visual C++6.0使用GDI+的一般方法 1. 载解压GDI+开发包; 2. 正确设置include & lib 目录; 3. stdafx.h 添加: #ifndef ULONG_PTR #define ULONG_PTR unsigned long* #endif #include 4. 程序中添加GDI+的包含文件gdiplus.h以及附加的类库gdiplus.lib。 通常gdiplus.h包含文件添加在应用程序的stdafx.h文件中,而gdiplus.lib可用两种进行添加: 第一种是直接在stdafx.h文件中添加下列语句: #pragma comment( lib, "gdiplus.lib" ) 另一种方法是: 在VC.net中添加库文件在:项目菜单->属性->链接器->输入 举个例子: (1)在应用程序项目的应用类中,添加一个成员变量,如下列代码: ULONG_PTR m_gdiplusToken; 其中,ULONG_PTR是一个DWORD数据类型,该成员变量用来保存GDI+被初始化后在应用程序中的GDI+标识,以便能在应用程序退出后,引用该标识来调用Gdiplus:: GdiplusShutdown来关闭GDI+。 (2)在应用类中添加ExitInstance的重载,并添加下列代码用来关闭GDI+: int CGDITestApp::ExitInstance() { Gdiplus::GdiplusShutdown(m_gdiplusToken); return CWinApp::ExitInstance(); } (3)在应用类的InitInstance函数中添加GDI+的初始化代码: 注意:下面这些GDI+的初始化代码必须放在m_pMainWnd->UpdateWindow();之前。 CWinApp::InitInstance(); Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL); (4)在需要绘图的窗口或视图类中添加GDI+的绘制代码。 下面分别就单文档和基于对话框应用程序为例,说明使用GDI+的一般过程和方法。 1. 在单文档应用程序中使用GDI+ 在上面的过程中,我们就是以一个单文档应用程序Ex_GDIPlus作为示例的。下面列出第4步所涉及的代码: void CGDITestView::OnDraw(CDC* pDC) { CGDITestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here usingnamespace Gdiplus; Graphics graphics(pDC->m_hDC); Pen newPen(Color(255,0,0),3); HatchBrush newBrush(HatchStyleCross,Color(255,0,255,0),Color(255,0,0,255));//创建一个填充画刷,前景色为绿色,背景色为蓝色 graphics.DrawRectangle(&newPen,50,50,100,60);// 在(50,50)处绘制一个长为100,高为60的矩形 graphics.FillRectangle(&newBrush,50,50,100,60); // 在(50,50)处填充一个长为100,高为60的矩形区域 } 编译并运行,结果如图:
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值