社区应用 最新帖子 精华区 社区服务 会员列表 统计排行 银行

  • 6117阅读
  • 15回复

windows(vc做开发工具,依赖mfc)界面编程

级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0

Windows界面编程第一篇 位图背景与位图画刷

    可以通过WM_CTLCOLORDLG消息来设置对话框的背景,MSDN上对这个消息的说明如下:

The WM_CTLCOLORDLG message is sent to a dialog box before the system draws the dialog box. By responding to this message, the dialog box can set its text and background colors using the specified display device context handle.

当窗口消息响应函数接收这个消息时,wParam表示对话框的设备上下方即HDClParam表示对话框的句柄。如果程序处理了这个消息,应返回一个画刷。系统将会用这个画刷来重绘对话框背景。

因此我们在这个WM_CTLCOLORDLG消息中得到对话框的大小,并通过StretchBlt函数将位图缩放后贴到对话框的HDC中就完成了对话框背景的设置,然后返回一个空画刷给系统,这样系统就不会将位图背景给覆盖了。

代码非常简单,要注意的是在使用StretchBlt函数缩放位图时,最好先使用

SetStretchBltMode函数来设置下位图内容伸展模式,这样可以避免缩放后位图失真严重。SetStretchBltMode函数原型如下:

int SetStretchBltMode(

    HDChdc,           // handle to DC

    int iStretchMode   // bitmap stretching mode

);

第一个参数就是设备上下方即HDC

第二个参数有四种设置:

1. BLACKONWHITE or STRETCH_ANDSCANS

 如果两个或多个像素得合并成一个像素,那么StretchBlt会对像素执行一个逻辑AND运算。这样的结果是只有全部的原始像素是白色时该像素才为白色,其实际意义是黑色像素控制了白色像素。这适用于白色背景中主要是黑色的单色点阵图。

2. WHITEONBLACK or STRETCH_ORSCANS

 如果两个或多个像素得合并成一个像素,那么StretchBlt会对像素执行逻辑OR运算。这样的结果是只有全部的原始像素都是黑色时该像素才为黑色,也就是说由白色像素决定颜色。这适用于黑色背景中主要是白色的单色点阵图。

3. COLORONCOLOR or STRETCH_DELETESCANS

 简单地消除图素行或列,而没有任何逻辑组合。这是通常是处理彩色点阵图的最佳方法。

4. HALFTONE or STRETCH_HALFTONE

根据组合起来的来源颜色来计算目的的平均颜色。

 

其它技术细节可以见代码中的注释,完整代码如下(也可以下载,下载地址为:http://download.csdn.net/download/morewindows/4947377):

  1. // 对话框位图背景  - WM_CTLCOLORDLG中使用StretchBlt贴图  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4. #include "resource.h"  
  5.   
  6. const char szDlgTitle[] = "位图背景 使用StretchBlt贴图 MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  7.   
  8. // 对话框消息处理函数  
  9. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);  
  10.             
  11. int APIENTRY WinMain(HINSTANCE hInstance,  
  12.                      HINSTANCE hPrevInstance,  
  13.                      LPSTR     lpCmdLine,  
  14.                      int       nCmdShow)  
  15. {  
  16.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);  
  17.     return 0;  
  18. }  
  19.   
  20.   
  21. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  22. {  
  23.     RECT       rcDialog;  
  24.     HBITMAP    hBitmap;  
  25.     static BITMAP s_bm;  
  26.     static HDC    s_hdcMem;  
  27.   
  28.     switch (message)  
  29.     {  
  30.     case WM_INITDIALOG:  
  31.         // 设置对话框标题  
  32.         SetWindowText(hDlg, szDlgTitle);  
  33.         // 设置对话框大小可调节  
  34.         SetWindowLong(hDlg, GWL_STYLE, GetWindowLong(hDlg, GWL_STYLE) | WS_SIZEBOX);  
  35.   
  36.         // 加载背影图片  
  37.         hBitmap = (HBITMAP)LoadImage(NULL, "005.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);  
  38.         if (hBitmap == NULL)  
  39.         {  
  40.             MessageBox(hDlg, "LoadImage failed""Error", MB_ICONERROR);  
  41.             exit(0);  
  42.         }         
  43.         else  
  44.         {  
  45.             // 将背影图片放入HDC - s_hdcMem  
  46.             HDC        hdc;  
  47.             hdc = GetDC(hDlg);  
  48.             s_hdcMem = CreateCompatibleDC(hdc);  
  49.             SelectObject(s_hdcMem, hBitmap);      
  50.             ReleaseDC(hDlg, hdc);  
  51.   
  52.             // 得到位图信息  
  53.             GetObject(hBitmap, sizeof(s_bm), &s_bm);  
  54.         }  
  55.   
  56.         return 0;  
  57.   
  58.     case WM_COMMAND:  
  59.         switch (LOWORD(wParam))  
  60.         {  
  61.         case IDCANCEL:  
  62.             DeleteDC(s_hdcMem);  
  63.             EndDialog(hDlg, LOWORD(wParam));  
  64.             return TRUE;  
  65.         }  
  66.         break;  
  67.   
  68.   
  69.     case WM_SIZE:  
  70.         InvalidateRect(hDlg, NULL, TRUE);  
  71.         return TRUE;  
  72.   
  73.     case WM_CTLCOLORDLG:  
  74.         GetClientRect(hDlg, &rcDialog);  
  75.         //通过SetStretchBltMode的设置能使StretchBlt在缩放图像更加清晰  
  76.         SetStretchBltMode((HDC)wParam, COLORONCOLOR);  
  77.         StretchBlt((HDC)wParam, 0, 0, rcDialog.right, rcDialog.bottom, s_hdcMem, 0, 0, s_bm.bmWidth, s_bm.bmHeight, SRCCOPY);     
  78.         return (BOOL)((HBRUSH)GetStockObject(NULL_BRUSH));  
  79.     }  
  80.     return FALSE;  
  81. }  

运行结果如下:

 

 

在上面这种方法中,我们是在WM_CTLCOLORDLG中贴图来完成背景设置了,也可以创建一个位图画刷,然后在WM_CTLCOLORDLG消息中直接返回这个画刷,这样系统将完成贴图功能。

       位图画刷的创建函数为CreatePatternBrush,其函数原型如下:

HBRUSHCreatePatternBrush(

    HBITMAPhbmp   // handle to bitmap

);

只要给这个函数传入位图句柄即可,完整代码如下(下载地址为:http://download.csdn.net/download/morewindows/4947377):

  1. // 对话框位图背景 - 直接在WM_CTLCOLORDLG中使用位图画刷  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4. #include "resource.h"  
  5.   
  6. const char szDlgTitle[] = "位图画刷 MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  7.   
  8.   
  9. // 对话框消息处理函数  
  10. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);  
  11.   
  12. int APIENTRY WinMain(HINSTANCE hInstance,  
  13.                      HINSTANCE hPrevInstance,  
  14.                      LPSTR     lpCmdLine,  
  15.                      int       nCmdShow)  
  16. {  
  17.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);  
  18.     return 0;  
  19. }  
  20.   
  21.   
  22. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  23. {  
  24.     static HBRUSH    s_hBitmapBrush; //位图画刷  
  25.   
  26.     switch (message)  
  27.     {  
  28.     case WM_INITDIALOG:  
  29.         // 设置对话框标题  
  30.         SetWindowText(hDlg, szDlgTitle);  
  31.         // 设置对话框大小可调节  
  32.         SetWindowLong(hDlg, GWL_STYLE, GetWindowLong(hDlg, GWL_STYLE) | WS_SIZEBOX);  
  33.   
  34.         // 加载背影图片  
  35.         HBITMAP hBitmap;  
  36.         hBitmap = (HBITMAP)LoadImage(NULL, "005.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);  
  37.         if (hBitmap == NULL)  
  38.         {  
  39.             MessageBox(hDlg, "LoadImage failed""Error", MB_ICONERROR);  
  40.             exit(0);  
  41.         }         
  42.   
  43.         // 创建位图画刷  
  44.         s_hBitmapBrush = CreatePatternBrush(hBitmap);  
  45.         return 0;  
  46.   
  47.   
  48.     case WM_COMMAND:  
  49.         switch (LOWORD(wParam))  
  50.         {  
  51.         case IDCANCEL:  
  52.             DeleteObject(s_hBitmapBrush);  
  53.             EndDialog(hDlg, LOWORD(wParam));  
  54.             return TRUE;  
  55.         }  
  56.         break;  
  57.   
  58.     case WM_CTLCOLORDLG:  
  59.         return (BOOL)s_hBitmapBrush;  
  60.     }  
  61.     return FALSE;  
  62. }  

运行结果如下:

 

 

注意,这两做法在窗口大小超过位图大小时会表现不同,前一种做法会拉伸位图以适应窗口大小,后一种做法是直接平铺。详见下图:

 

 

本篇《Windows界面编程第一篇位图背景与位图画刷》主要介绍了通过WM_CTLCOLORDLG消息来设置对话框的背景,在Windows系统中还有类似于WM_CTLCOLORDLG消息的还有WM_CTLCOLORBTNWM_CTLCOLOREDITWM_CTLCOLORLISTBOXWM_CTLCOLORSCROLLBARWM_CTLCOLORSTATIC这五种来分别管理按钮,编辑框,列表框,滚动条,静态框。有兴趣的读者可以试验下。

 

下一篇将介绍调节窗体透明度的方法,欢迎继续浏览《Windows界面编程第二篇 半透明窗体

 

 当窗口的背景用彩色图片来装饰时,其它控件如果还是用灰色的背景会显的比较不谐调,《Windows界面编程第五篇 静态控件背景透明化》将介绍如何为静态框设置透明背景。

 


 本文配套程序下载地址为:http://download.csdn.net/download/morewindows/4947377

转载请标明出处,原文地址:http://blog.csdn.net/morewindows/article/details/8451629

关键词: 技术 编程 mfc 界面
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 沙发  发表于: 2013-01-07
界面编程第二篇 半透明窗体

本篇将介绍动态调节窗体透明度的方法。

    调节窗体透明度可以先使用SetWindowLong为窗体加上WS_EX_LAYERED属性,再使用来SetLayeredWindowAttributes指定窗体的透明度。这样就可以在程序运行时动态的调节窗体的透明度了。

    下面先介绍下SetWindowLongSetLayeredWindowAttributes函数。

SetWindowLong可以用来设置窗口的一些属性,其函数原型如下:

LONGSetWindowLong(

    HWNDhWnd,

    int nIndex,

    LONGdwNewLong

);

第一个参数表示窗口句柄。

第二个参数代表要设置的哪一种值,如GWL_STYLE表示将设置窗口的风格,这个参数还可以取GWL_EXSTYLEGWL_WNDPROCDWL_DLGPROCGWL_HINSTANCEGWL_USERDATA等等。

第三个参数表示要设置的值。

比如要设置对话框也能够可调节窗口大小,可以用:

 // 设置对话框大小可调节

SetWindowLong(hDlgGWL_STYLEGetWindowLong(hDlgGWL_STYLE) |WS_SIZEBOX);

 

SetLayeredWindowAttributesMSDN上解释如下:

The SetLayeredWindowAttributes function sets the opacity and transparency color key of a layered window.

其函数原型为:

BOOLSetLayeredWindowAttributes(

    HWNDhwnd,

    COLORREFcrKey,

    BYTEbAlpha,

    DWORDdwFlags

);

第一个参数表示窗口句柄。

第二个参数表示透明色。

第三个参数表示透明度。

第四个参数表示函数将完成什么样的功能,设置成LWA_COLORKEY表示为窗口指定了透明色,设置成LWA_ALPHA表示将调整窗口的透明度,可以同时设置这两种功能。

 

程序代码还将用到Slider控件,这种控件可以有如下操作:

1.通过SendMessage TBM_SETRANGE来设置滑块变化的范围。

2.通过SendMessage TBM_SETPOS来设置滑块当前位置。

3.通过SendMessage TBM_GETPOS来获得滑块当前位置。

4.当滑块位置发生变化时,在其父窗口中通过WM_HSCROLLWM_VSCROLL来响应消息。

 

下面给出完整的源代码(下载地址:http://download.csdn.net/download/morewindows/4947386

  1. // 可变透明度窗体 先加上WS_EX_LAYERED属性再SetLayeredWindowAttributes设置透明度  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4. #include <commctrl.h>  
  5. #include "resource.h"  
  6. const char szDlgTitle[] = "可变透明度窗体 MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  7. // 对话框消息处理函数  
  8. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);  
  9.   
  10. int APIENTRY WinMain(HINSTANCE hInstance,  
  11.                      HINSTANCE hPrevInstance,  
  12.                      LPSTR     lpCmdLine,  
  13.                      int       nCmdShow)  
  14. {  
  15.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);  
  16.     return 0;  
  17. }  
  18.   
  19.   
  20. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  21. {  
  22.     const int INIT_TRANSPARENT = 200; //窗体初始透明度  
  23.     static HBRUSH    s_hBitmapBrush; //位图画刷  
  24.   
  25.     switch (message)  
  26.     {  
  27.     case WM_INITDIALOG:  
  28.         // 设置对话框标题  
  29.         SetWindowText(hDlg, szDlgTitle);  
  30.   
  31.         // 加载背影图片  
  32.         HBITMAP hBitmap;  
  33.         hBitmap = (HBITMAP)LoadImage(NULL, "005.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);  
  34.         if (hBitmap == NULL)  
  35.         {  
  36.             MessageBox(hDlg, "LoadImage failed""Error", MB_ICONERROR);  
  37.             exit(0);  
  38.         }         
  39.   
  40.         // 创建位图画刷  
  41.         s_hBitmapBrush = CreatePatternBrush(hBitmap);  
  42.   
  43.         // 设置分层属性  
  44.         SetWindowLong(hDlg, GWL_EXSTYLE, GetWindowLong(hDlg, GWL_EXSTYLE) | WS_EX_LAYERED);  
  45.         // 设置透明度 0 - completely transparent   255 - opaque  
  46.         SetLayeredWindowAttributes(hDlg, 0, INIT_TRANSPARENT, LWA_ALPHA);  
  47.   
  48.         // 设置滑动条变化范围  
  49.         SendMessage(GetDlgItem(hDlg, IDC_SLIDER_TRANSPARENT), TBM_SETRANGE, (WPARAM)FALSE, MAKELONG(0, 255));  
  50.         // 设置滑块初始位置  
  51.         SendMessage(GetDlgItem(hDlg, IDC_SLIDER_TRANSPARENT), TBM_SETPOS, (WPARAM)TRUE, INIT_TRANSPARENT);  
  52.         return 0;  
  53.   
  54.   
  55.     case WM_COMMAND:  
  56.         switch (LOWORD(wParam))  
  57.         {  
  58.         case IDCANCEL:  
  59.             DeleteObject(s_hBitmapBrush);  
  60.             EndDialog(hDlg, LOWORD(wParam));  
  61.             return TRUE;  
  62.         }  
  63.         break;  
  64.   
  65.   
  66.     case WM_HSCROLL: // slider control 滑块位置有变化时的响应函数  
  67.         {  
  68.             // 获取当前滑块位置  
  69.             int nTransparent = SendMessage(GetDlgItem(hDlg, IDC_SLIDER_TRANSPARENT), TBM_GETPOS, 0, 0);   
  70.             // 设置新透明度  
  71.             SetLayeredWindowAttributes(hDlg, 0, nTransparent, LWA_ALPHA);  
  72.         }  
  73.         break;  
  74.   
  75.   
  76.     case WM_CTLCOLORDLG:  //对话框背影  
  77.         return (BOOL)s_hBitmapBrush;  
  78.     }  
  79.     return FALSE;  
  80. }  

运行结果如下:

 

在本篇文章中我们通过SetWindowLong为窗体加上WS_EX_LAYERED属性,再使用SetLayeredWindowAttributes完成窗体的透明度调节。下面两篇也将使用这两个函数来完成另一个功能——异形窗口(异形窗体)。异形窗口可以使得窗口更加美观,它能灵活的变动窗口的形状。

QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 板凳  发表于: 2013-01-07
编程第三篇 异形窗体 普通版

上一篇《Windows界面编程第二篇 半透明窗体》介绍了先使用SetWindowLong为窗体加上WS_EX_LAYERED属性,再使用SetLayeredWindowAttributes调整窗体的透明度。本篇将使用这二个函数来完成另一个实用的功能——异形窗口(异形窗体)。

异形窗口的原理很简单,首先加载一张位图画刷作窗口背景,然后设置透明色就可以使得窗口由矩形变成任意形状。这样使得窗口的显示更加美观。

 

    下面先简单介绍下Win32 SDK方式创建窗口的流程(按《Windows程序设计》中的大体流程):

1.设置WNDCLASS类型的变量,这个变量将描述窗口的风格、窗口消息处理函数、程序图标、光标、窗口背景画刷等待。

2.使用RegisterClassWNDCLASS类型的变量注册下。

3.使用CreateWindowCreateWindowEx创建窗口,这里可以设置窗口的初始位置、初始大小、扩展属性等等。

4.通过ShowWindowUpdateWindow将窗口显示出来。

5.窗口显示完成后,在WinMain()函数中添加消息处理:   

       MSG msg;

       while (GetMessage(&msgNULL, 0, 0))

       {

              TranslateMessage(&msg);

              DispatchMessage(&msg);

       }

通过这五步就完成了一个窗口的创建了。

对于窗口消息函数,一般只要在WM_DESTROY消息中调用下PostQuitMessage(0);其它的消息都可以使用默认消息处理函数DefWindowProc

 

对于异形窗口,可以在WM_CREATE即窗口初始化时设置好透明色就完成了窗口形状的改变,不过为了支持鼠标对窗口的拖曳,还要在WM_LBUTTONDOWN消息中加入:

PostMessage(hwndWM_SYSCOMMANDSC_MOVE | HTCAPTION, 0);

这样,异形窗口就可以在屏幕上像普通窗口一样的移动了。

 

完整的源代码如下所示(下载地址:http://download.csdn.net/download/morewindows/4966815):

  1. //   异形窗口1  窗口背景使用位图画刷再指定透明色  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4.   
  5. const char szAppName[] = "异形窗口1 MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  6.   
  7. /* 
  8.  * 函数名称: GetWindowSize 
  9.  * 函数功能: 得到窗口的宽高 
  10.  * hwnd      窗口句柄 
  11.  * pnWidth   窗口宽 
  12.  * pnHeight  窗口高 
  13. */  
  14. void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight);  
  15.   
  16.   
  17. /* 
  18.  * 函数名称: InitBitmapWindow 
  19.  * 函数功能: 位图窗口初始化 
  20.  * hinstance 进程实例 
  21.  * hBitmap   位图句柄 
  22.  * nCmdshow  显示方式-与ShowWindow函数的第二个参数相同 
  23. */  
  24. BOOL InitBitmapWindow(HINSTANCE hinstance, HBITMAP hBitmap, int nCmdshow);  
  25.   
  26. // 位图窗口消息处理函数  
  27. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm);  
  28.   
  29.   
  30. int APIENTRY WinMain(HINSTANCE hInstance,  
  31.                      HINSTANCE hPrevInstance,  
  32.                      LPSTR     lpCmdLine,  
  33.                      int       nCmdShow)  
  34. {  
  35.     //设置窗口背景画刷为图片画刷,再指定透明颜色即可以创建透明区域。  
  36.     HBITMAP  hBitmap;  
  37.     hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);  
  38.     if (hBitmap == NULL)  
  39.     {  
  40.         MessageBox(NULL, "位图加载失败""Error", MB_ICONERROR);  
  41.         return 0;  
  42.     }  
  43.     if (!InitBitmapWindow(hInstance, hBitmap, nCmdShow))  
  44.         return 0;  
  45.   
  46.     MSG msg;  
  47.     while (GetMessage(&msg, NULL, 0, 0))  
  48.     {  
  49.         TranslateMessage(&msg);  
  50.         DispatchMessage(&msg);  
  51.     }  
  52.     DeleteObject(hBitmap);  
  53.   
  54.     return msg.wParam;  
  55. }  
  56.   
  57.   
  58. BOOL InitBitmapWindow(HINSTANCE hinstance, HBITMAP hBitmap, int nCmdshow)  
  59. {  
  60.     HWND hwnd;  
  61.     WNDCLASS wndclass;  
  62.       
  63.     wndclass.style       = CS_VREDRAW | CS_HREDRAW;  
  64.     wndclass.lpfnWndProc = BitmapWindowWndPrco;   
  65.     wndclass.cbClsExtra  = 0;  
  66.     wndclass.cbWndExtra  = 0;  
  67.     wndclass.hInstance   = hinstance;     
  68.     wndclass.hIcon       = LoadIcon(NULL, IDI_APPLICATION);  
  69.     wndclass.hCursor     = LoadCursor(NULL, IDC_ARROW);  
  70.     wndclass.hbrBackground = CreatePatternBrush(hBitmap);//位图画刷  
  71.     wndclass.lpszMenuName  = NULL;  
  72.     wndclass.lpszClassName = szAppName;  
  73.       
  74.     if (!RegisterClass(&wndclass))  
  75.     {  
  76.         MessageBox(NULL, "Program Need Windows NT!""Error", MB_ICONERROR);  
  77.         return FALSE;  
  78.     }  
  79.   
  80.     BITMAP bm;  
  81.     GetObject(hBitmap, sizeof(bm), &bm);  
  82.     hwnd = CreateWindowEx(WS_EX_TOPMOST,  
  83.                         szAppName,  
  84.                         szAppName,   
  85.                         WS_POPUP,  
  86.                         CW_USEDEFAULT,   
  87.                         CW_USEDEFAULT,   
  88.                         bm.bmWidth,   
  89.                         bm.bmHeight,  
  90.                         NULL,  
  91.                         NULL,  
  92.                         hinstance,  
  93.                         NULL);  
  94.     if (hwnd == NULL)  
  95.         return FALSE;  
  96.       
  97.     ShowWindow(hwnd, nCmdshow);  
  98.     UpdateWindow(hwnd);  
  99.       
  100.     return TRUE;  
  101. }  
  102.   
  103. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm)  
  104. {  
  105.     static HDC s_hdcMem;  
  106.     static HBRUSH s_hBackBrush;  
  107.       
  108.     switch (message)  
  109.     {  
  110.     case WM_CREATE:  
  111.         {  
  112.             // 设置分层属性  
  113.             SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);  
  114.             // 设置透明色  
  115.             COLORREF clTransparent = RGB(0, 0, 0);  
  116.             SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY);  
  117.         }  
  118.         return 0;  
  119.   
  120.           
  121.     case WM_KEYDOWN:   
  122.         switch (wParam)  
  123.         {  
  124.         case VK_ESCAPE: //按下Esc键时退出  
  125.             SendMessage(hwnd, WM_DESTROY, 0, 0);  
  126.             return 0;  
  127.         }  
  128.         break;  
  129.       
  130.   
  131.     case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口  
  132.         PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);   
  133.         return 0;  
  134.   
  135.   
  136.     case WM_DESTROY:  
  137.         PostQuitMessage(0);  
  138.         return 0;  
  139.     }  
  140.     return DefWindowProc(hwnd, message, wParam, lParm);  
  141. }  
  142.   
  143. void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight)  
  144. {  
  145.     RECT rc;  
  146.     GetWindowRect(hwnd, &rc);  
  147.     *pnWidth = rc.right - rc.left;  
  148.     *pnHeight = rc.bottom - rc.top;  
  149. }  

运行结果如下:

 

 

现在总结下异形窗口的创建,先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。为了支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理,使得异形窗口可以像普通窗口一样在屏幕上移动。

 

本篇程序中的异形窗口的大小是无法设置的,只能和位图一样

QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 地板  发表于: 2013-01-07
界面编程第四篇 异形窗体 高富帅版

 上一篇《Windows界面编程第三篇 异形窗体 普通版》介绍了异形窗口(异形窗体)的创建,其主要步骤为——先通过创建位图画刷来做窗口的背景画刷,再通过SetWindowLong为窗体加上WS_EX_LAYERED属性,然后使用SetLayeredWindowAttributes指定窗口的透明色来完成窗口形状的调整。并且为了使异形窗口支持鼠标的拖曳,在WM_LBUTTONDOWN消息中作了特殊处理。

然后在下图中有非常相似的两个异形窗体,只不过,左边的异形窗体小,右边的异形窗体大。这个可以怎么实现了?

 

先通过其它软件来缩放位图,然后再让程序加载这种方式来指定异形窗口的大小。这种方法虽然可以完成任务,但毕竟太OUT了。

由《Windows界面编程第一篇位图背景与位图画刷》可以想到不用位图画刷,而直接在窗口背景绘制时使用StretchBlt来缩放位图至窗口大小,这样就可以达到指定窗口大小的功能。

由于异形窗口运行后无法通过鼠标来动态调整窗口大小,因此可以窗口初始化时就可以先缩放位图并加载到一个缓冲HDC中,然后再在窗口背景绘制时使用BitBlt来贴图。这种做法只需要缩放位图一次,在每次背景绘制时只须拷贝位图,对程序的效率会有提高。下面给出完整源代码(下载地址:http://download.csdn.net/download/morewindows/4966819

  1. //   异形窗口2  在WM_ERASEBKGND消息中自贴图  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4. const char szAppName[] = "异形窗口2 MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  5.   
  6. /* 
  7.  * 函数名称: GetWindowSize 
  8.  * 函数功能: 得到窗口的宽高 
  9.  * hwnd      窗口句柄 
  10.  * pnWidth   窗口宽 
  11.  * pnHeight  窗口高 
  12. */  
  13. void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight);  
  14.   
  15.   
  16. /* 
  17.  * 函数名称: InitBitmapWindow 
  18.  * 函数功能: 位图窗口初始化 
  19.  * hinstance 进程实例 
  20.  * nWidth    窗口宽 
  21.  * nHeight   窗口高 
  22.  * nCmdshow  显示方式-与ShowWindow函数的第二个参数相同 
  23. */  
  24. BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow);  
  25.   
  26. // 位图窗口消息处理函数  
  27. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm);  
  28.   
  29.             
  30. HBITMAP  g_hBitmap;  
  31. int APIENTRY WinMain(HINSTANCE hInstance,  
  32.                      HINSTANCE hPrevInstance,  
  33.                      LPSTR     lpCmdLine,  
  34.                      int       nCmdShow)  
  35. {  
  36.     //先创建一个无背影画刷窗口,  
  37.     //然后在WM_CREATE中并指定透明颜色, 缩放位图后加载至s_hdcMem中.  
  38.     //最后在WM_ERASEBKGND中用s_hdcMem贴图即可  
  39.     g_hBitmap = (HBITMAP)LoadImage(NULL, "Kitty.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);  
  40.     if (g_hBitmap == NULL)  
  41.     {  
  42.         MessageBox(NULL, "位图加载失败""Error", MB_ICONERROR);  
  43.         return 0;  
  44.     }  
  45.   
  46.     // 设置异形窗口大小  
  47.     BITMAP bm;  
  48.     GetObject(g_hBitmap, sizeof(bm), &bm);  
  49.     int nWindowWidth = bm.bmWidth;  
  50.     int nWindowHeight = bm.bmHeight + 100; //拉高100高度  
  51.   
  52.     if (!InitBitmapWindow(hInstance, nWindowWidth, nWindowHeight, nCmdShow))  
  53.         return 0;  
  54.   
  55.     MSG msg;  
  56.     while (GetMessage(&msg, NULL, 0, 0))  
  57.     {  
  58.         TranslateMessage(&msg);  
  59.         DispatchMessage(&msg);  
  60.     }  
  61.     DeleteObject(g_hBitmap);  
  62.   
  63.     return msg.wParam;  
  64. }  
  65.   
  66.   
  67. BOOL InitBitmapWindow(HINSTANCE hinstance, int nWidth, int nHeight, int nCmdshow)  
  68. {  
  69.     HWND hwnd;  
  70.     WNDCLASS wndclass;  
  71.       
  72.     wndclass.style       = CS_VREDRAW | CS_HREDRAW;  
  73.     wndclass.lpfnWndProc = BitmapWindowWndPrco;   
  74.     wndclass.cbClsExtra  = 0;  
  75.     wndclass.cbWndExtra  = 0;  
  76.     wndclass.hInstance   = hinstance;     
  77.     wndclass.hIcon       = LoadIcon(NULL, IDI_APPLICATION);  
  78.     wndclass.hCursor     = LoadCursor(NULL, IDC_ARROW);  
  79.     wndclass.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);//窗口背影画刷为空  
  80.     wndclass.lpszMenuName  = NULL;  
  81.     wndclass.lpszClassName = szAppName;  
  82.       
  83.     if (!RegisterClass(&wndclass))  
  84.     {  
  85.         MessageBox(NULL, "Program Need Windows NT!""Error", MB_ICONERROR);  
  86.         return FALSE;  
  87.     }  
  88.       
  89.     hwnd = CreateWindowEx(WS_EX_TOPMOST,  
  90.                         szAppName,  
  91.                         szAppName,   
  92.                         WS_POPUP,  
  93.                         CW_USEDEFAULT,   
  94.                         CW_USEDEFAULT,   
  95.                         nWidth,   
  96.                         nHeight,  
  97.                         NULL,  
  98.                         NULL,  
  99.                         hinstance,  
  100.                         NULL);  
  101.     if (hwnd == NULL)  
  102.         return FALSE;  
  103.       
  104.     ShowWindow(hwnd, nCmdshow);  
  105.     UpdateWindow(hwnd);  
  106.       
  107.     return TRUE;  
  108. }  
  109.   
  110. LRESULT CALLBACK BitmapWindowWndPrco(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParm)  
  111. {  
  112.     static HDC s_hdcMem; //放置缩放后的位图  
  113.       
  114.     switch (message)  
  115.     {  
  116.     case WM_CREATE:  
  117.         {  
  118.             // 设置分层属性  
  119.             SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);  
  120.             // 设置透明色  
  121.             COLORREF clTransparent = RGB(0, 0, 0);  
  122.             SetLayeredWindowAttributes(hwnd, clTransparent, 0, LWA_COLORKEY);  
  123.               
  124.             //   缩放位图  
  125.             // 加载位图到hdcTemp中  
  126.             HDC hdc = GetDC(hwnd);  
  127.             HDC hdcTemp = CreateCompatibleDC(hdc);  
  128.             SelectObject(hdcTemp, g_hBitmap);  
  129.   
  130.             // 得到窗口大小  
  131.             int nWidth, nHeight;  
  132.             GetWindowSize(hwnd, &nWidth, &nHeight);  
  133.   
  134.             // 创建与窗口大小相等且能容纳位图的HDC - s_hdcMem  
  135.             s_hdcMem = CreateCompatibleDC(hdc);  
  136.             HBITMAP hbmp = CreateCompatibleBitmap(hdc, nWidth, nHeight);  
  137.             SelectObject(s_hdcMem, hbmp);  
  138.   
  139.             // 将原位图缩放到窗口大小  
  140.             BITMAP bm;  
  141.             GetObject(g_hBitmap, sizeof(bm), &bm);  
  142.             StretchBlt(s_hdcMem, 0, 0, nWidth, nHeight, hdcTemp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);  
  143.               
  144.             // 释放资源  
  145.             DeleteDC(hdcTemp);  
  146.             ReleaseDC(hwnd, hdc);  
  147.         }  
  148.         return 0;  
  149.   
  150.           
  151.     case WM_KEYDOWN:   
  152.         switch (wParam)  
  153.         {  
  154.         case VK_ESCAPE: //按下Esc键时退出  
  155.             SendMessage(hwnd, WM_DESTROY, 0, 0);  
  156.             return TRUE;  
  157.         }  
  158.         break;  
  159.       
  160.   
  161.     case WM_LBUTTONDOWN: //当鼠标左键点击时可以拖曳窗口  
  162.         PostMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);   
  163.         return TRUE;  
  164.                   
  165.     case WM_ERASEBKGND: //在窗口背景中直接贴图  
  166.         {  
  167.             HDC hdc = (HDC)wParam;  
  168.             int nWidth, nHeight;  
  169.             GetWindowSize(hwnd, &nWidth, &nHeight);  
  170.             BitBlt(hdc, 0, 0, nWidth, nHeight, s_hdcMem, 0, 0, SRCCOPY);  
  171.             return TRUE;  
  172.         }  
  173.   
  174.     case WM_DESTROY:  
  175.         DeleteDC(s_hdcMem);  
  176.         PostQuitMessage(0);  
  177.         return 0;  
  178.     }  
  179.     return DefWindowProc(hwnd, message, wParam, lParm);  
  180. }  
  181.   
  182.   
  183. void GetWindowSize(HWND hwnd, int *pnWidth, int *pnHeight)  
  184. {  
  185.     RECT rc;  
  186.     GetWindowRect(hwnd, &rc);  
  187.     *pnWidth = rc.right - rc.left;  
  188.     *pnHeight = rc.bottom - rc.top;  
  189. }  

运行程序将得到如文章中每一张图右边所示的异形窗口。

 

最后总结一下异形窗口的“三要素”:

1.WS_EX_LAYERED属性

2.以位图为窗口背景(自贴图或位图画刷)

3.指定透明色

 

本文配套程序下载地址为:http://download.csdn.net/download/morewindows/4966819

 

当窗口的背景用彩色图片来装饰时,其它控件如果还是用灰色的背景会显的比较不谐调,《Windows界面编程第五篇 静态控件背景透明化》将介绍如何为静态框设置透明背景。

QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 4楼 发表于: 2013-01-07
界面编程第五篇 静态控件背景透明化

 上一篇《Windows界面编程第三篇 异形窗体 普通版》和《Windows界面编程第四篇异形窗体 高富帅版》介绍了异形窗口(异形窗体)的创建,并总结出了异形窗口的“三要素”:

1.WS_EX_LAYERED属性

2.指定透明色

3.以位图为窗口背景

 

    本篇文章将主要介绍Windows编程中如何实现静态控件背景的透明化,这将进一步的美化界面。下面先看一张没有做静态控件背景透明化的对话框程序的运行画面,对话框的彩色图片背景可以参考《Windows界面编程第一篇位图背景与位图画刷》。

    可以看出静态控件的灰度背景在对话框的彩色图片背景中显得很不谐调,因此有必要对其美化一下。

    在第一篇《Windows界面编程第一篇位图背景与位图画刷》中介绍了通过WM_CTLCOLORDLG消息来设置对话框的背景,而在Windows系统中还有类似于WM_CTLCOLORDLG消息的还有WM_CTLCOLORBTNWM_CTLCOLOREDITWM_CTLCOLORLISTBOXWM_CTLCOLORSCROLLBARWM_CTLCOLORSTATIC这五种来分别管理按钮,编辑框,列表框,滚动条,静态框。因此我们首先在WM_CTLCOLORSTATIC消息中返回一个空画刷看看能不能达到背景透明化的要求。另外对于文字区域的背景透明可以通过SetBkMode来设置。其函数原型如下:

int SetBkMode(

    HDC hdc,      // handle to DC

    int iBkMode   // background mode

);

这个函数的第二个参数设置为TRANSPARENT时就可以将文字区域的前景设置成透明。

 

下面给出完整的源代码(下载地址:http://download.csdn.net/download/morewindows/4966826):

  1. // 静态控件背景透明化WM_CTLCOLORSTATIC中返回空画刷  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4. #include "resource.h"  
  5.   
  6. const char szDlgTitle[] = "静态控件背景透明化MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  7.   
  8. // 对话框消息处理函数  
  9. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);  
  10.             
  11. int APIENTRY WinMain(HINSTANCE hInstance,  
  12.                      HINSTANCE hPrevInstance,  
  13.                      LPSTR     lpCmdLine,  
  14.                      int       nCmdShow)  
  15. {  
  16.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);  
  17.     return 0;  
  18. }  
  19.   
  20.   
  21. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  22. {  
  23.     RECT       rcDialog;  
  24.     HBITMAP    hBitmap;  
  25.     static BITMAP s_bm;  
  26.     static HDC    s_hdcMem;  
  27.   
  28.     switch (message)  
  29.     {  
  30.     case WM_INITDIALOG:  
  31.         // 设置对话框标题  
  32.         SetWindowText(hDlg, szDlgTitle);  
  33.         // 设置对话框大小可调节  
  34.         SetWindowLong(hDlg, GWL_STYLE, GetWindowLong(hDlg, GWL_STYLE) | WS_SIZEBOX);  
  35.   
  36.         // 加载背影图片  
  37.         hBitmap = (HBITMAP)LoadImage(NULL, "006.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);  
  38.         if (hBitmap == NULL)  
  39.         {  
  40.             MessageBox(hDlg, "LoadImage failed""Error", MB_ICONERROR);  
  41.             exit(0);  
  42.         }         
  43.         else  
  44.         {  
  45.             // 将背影图片放入HDC - s_hdcMem  
  46.             HDC        hdc;  
  47.             hdc = GetDC(hDlg);  
  48.             s_hdcMem = CreateCompatibleDC(hdc);  
  49.             SelectObject(s_hdcMem, hBitmap);      
  50.             ReleaseDC(hDlg, hdc);  
  51.   
  52.             // 得到位图信息  
  53.             GetObject(hBitmap, sizeof(s_bm), &s_bm);  
  54.         }  
  55.   
  56.         return 0;  
  57.   
  58.     case WM_COMMAND:  
  59.         switch (LOWORD(wParam))  
  60.         {  
  61.         case IDCANCEL:  
  62.             DeleteDC(s_hdcMem);  
  63.             EndDialog(hDlg, LOWORD(wParam));  
  64.             return TRUE;  
  65.         }  
  66.         break;  
  67.   
  68.   
  69.     case WM_SIZE:  
  70.         InvalidateRect(hDlg, NULL, TRUE);  
  71.         return TRUE;  
  72.   
  73.     case WM_CTLCOLORSTATIC:  
  74.         SetBkMode((HDC)wParam, TRANSPARENT);  
  75.         return (BOOL)((HBRUSH)GetStockObject(NULL_BRUSH));  
  76.   
  77.     case WM_CTLCOLORDLG:  
  78.         GetClientRect(hDlg, &rcDialog);  
  79.         //通过SetStretchBltMode的设置能使StretchBlt在缩放图像更加清晰  
  80.         SetStretchBltMode((HDC)wParam, COLORONCOLOR);  
  81.         StretchBlt((HDC)wParam, 0, 0, rcDialog.right, rcDialog.bottom, s_hdcMem, 0, 0, s_bm.bmWidth, s_bm.bmHeight, SRCCOPY);     
  82.         return (BOOL)((HBRUSH)GetStockObject(NULL_BRUSH));  
  83.     }  
  84.     return FALSE;  
  85. }  

这份代码也是在《Windows界面编程第一篇位图背景与位图画刷》文章的代码上增加了

    case WM_CTLCOLORSTATIC:

             SetBkMode((HDC)wParamTRANSPARENT);

             return (BOOL)((HBRUSH)GetStockObject(NULL_BRUSH));

来达到静态控件背景透明化的效果的,程序运行效果如下:

 

由图可以看出,虽然Static Text控件的是达到了背景透明化的要求,但是Group Box控件的描述文字的显示却显得很不美观。

 

要解决这一问题,可以试下位图画刷,我们在WM_CTLCOLORSTATIC消息中像WM_CTLCOLORDLG消息一样也返回一个位图画刷来试试。

  1. // 静态控件背景透明化- 在WM_CTLCOLORDLG返回窗口背景的位图画刷  
  2. //By MoreWindows-(http://blog.csdn.net/MoreWindows)  
  3. #include <windows.h>  
  4. #include "resource.h"  
  5.   
  6. const char szDlgTitle[] = "静态控件背景透明化MoreWindows-(http://blog.csdn.net/MoreWindows)";  
  7.   
  8.   
  9. // 对话框消息处理函数  
  10. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);  
  11.   
  12. int APIENTRY WinMain(HINSTANCE hInstance,  
  13.                      HINSTANCE hPrevInstance,  
  14.                      LPSTR     lpCmdLine,  
  15.                      int       nCmdShow)  
  16. {  
  17.     DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);  
  18.     return 0;  
  19. }  
  20.   
  21.   
  22. BOOL CALLBACK DlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)  
  23. {  
  24.     static HBRUSH    s_hBitmapBrush; //位图画刷  
  25.   
  26.     switch (message)  
  27.     {  
  28.     case WM_INITDIALOG:  
  29.         // 设置对话框标题  
  30.         SetWindowText(hDlg, szDlgTitle);  
  31.         // 设置对话框大小可调节  
  32.         SetWindowLong(hDlg, GWL_STYLE, GetWindowLong(hDlg, GWL_STYLE) | WS_SIZEBOX);  
  33.   
  34.         // 加载背影图片  
  35.         HBITMAP hBitmap;  
  36.         hBitmap = (HBITMAP)LoadImage(NULL, "006.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);  
  37.         if (hBitmap == NULL)  
  38.         {  
  39.             MessageBox(hDlg, "LoadImage failed""Error", MB_ICONERROR);  
  40.             exit(0);  
  41.         }         
  42.   
  43.         // 创建位图画刷  
  44.         s_hBitmapBrush = CreatePatternBrush(hBitmap);  
  45.         return 0;  
  46.   
  47.   
  48.     case WM_COMMAND:  
  49.         switch (LOWORD(wParam))  
  50.         {  
  51.         case IDCANCEL:  
  52.             DeleteObject(s_hBitmapBrush);  
  53.             EndDialog(hDlg, LOWORD(wParam));  
  54.             return TRUE;  
  55.         }  
  56.         break;  
  57.   
  58.     case WM_CTLCOLORSTATIC:  
  59.         SetBkMode((HDC)wParam, TRANSPARENT);  
  60.   
  61.     case WM_CTLCOLORDLG:  
  62.         return (BOOL)s_hBitmapBrush;  
  63.     }  
  64.     return FALSE;  
  65. }  

与上一个程序一样,这个程序也只是在在《Windows界面编程第一篇位图背景与位图画刷》文章的代码上增加了

       case WM_CTLCOLORSTATIC:

              SetBkMode((HDC)wParamTRANSPARENT);

来设置静态控件背景透明化,程序运行效果如下:

 

由图可以看出,静态控件的透明化还是非常方便的,只要在WM_CTLCOLORSTATIC消息中完成二个步骤即可:

1.通过SetBkMode((HDC)wParamTRANSPARENT);来设置文字区域背景透明。

2.返回空画刷或与父窗口相同的画刷。


 

后面还陆续发布Windows界面编程方面的文章

QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 5楼 发表于: 2013-02-11
windows上实现透明和半透明窗口
和大家分享一下在半透明窗口中显示标准控件的实现方案。通过层叠窗口可以简单实现半透明与不规则形状窗口的效果,但在其上显示标准控件(控件与文字不透明)却是件比较有挑战的事情,这里会给出一个可行的解决方案。同时实现了一些可重用的窗口类,有相关需求时可以进行引用。先看一下效果图:




一、半透明窗口实现原理
绘制半透明窗口的通常做法是为窗口设置WS_EX_LAYERED属性,通过UpdateLayeredWindow或者SetLayeredWindowAttributes来设置窗口透明度等属性。这两种方法有一些区别、适合的场景也不同。
UpdateLayeredWindow:调用后窗口的绘制被接管,应用负责主动调用这个函数进行绘制,窗口及其控件不再能接收到WM_PAINT消息。可以把带有透明像素的PNG图片直接绘制在窗口上,实现不同程序的透明效果。
SetLayeredWindowAttributes:有两种模式:1. 指定特定像素透明。2. 设置整个窗口统一的透明度(包括控件)。使用这个函数再设置窗口透明,窗口及控件仍可以收到WM_PAINT消息。

需要特别注意的是UpdateLayeredWindowSetLayeredWindowAttributes的互斥性,在调用SetLayeredWindowAttributes后再调用UpdateLayeredWindow都会失败。
二、实现不规则窗口绘制
不规则的形状由PNG图片通过设置透明区域来实现,程序需要实现全透明区域的鼠标消息也透明。将需要进行透明处理的区域色彩设置为RGB(r,g,b),可以直接设置为RGB(0,0,0),通过SetLayeredWindowAttributes,将COLORREFcrKey参数设为RGB(r,g,b),即可以实现,这个透明效果不只是视觉上的透明,同时也会透过鼠标消息

三、在半透明背景中实现控件不透明
有时候我们只希望有透明像素的图片来做背景或者希望整个窗口有一定的透明度,但其上的控件不想做透明处理,否则控件上的文字会变得不明显,影响使用。这里提供的是双层窗口的解决方案。前景窗口作为背景窗口的子窗口,两个窗口时刻保持同样尺寸,同时移动,关闭事件关联处理。



前端窗口窗体全透明,并且透过鼠标消息,控件放置在前端窗口,不透明。实现方法是对WM_CTLCOLOR消息进行处理,窗口画刷返回m_crKey(比如RGB(0, 255, 0))颜色的画刷,其它控件默认处理。在窗口初始化的时候使用::SetLayeredWindowAttributes(m_hWnd, m_crKey, 0, LWA_COLORKEY); 设置对这个颜色透明。
[cpp] view plaincopy


    <span style="font-size:18px;">HBRUSH CStandardDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)    {        if (nCtlColor == CTLCOLOR_DLG)        {            return CreateSolidBrush(m_crKey);        }             return CDialog::OnCtlColor(pDC, pWnd, nCtlColor);    }</span>  



背景窗口使用预设的PNG图片,通过UpdateLayeredWindow绘制,并设置全透明的区域透过鼠标消息。调用UpdateLayeredWindow后窗口内容会被系统缓存,所以在窗口创建初次绘制后,如果没有特殊需要是不需要去重画背景窗口的。

这个方案支持所有标准的控件,同时也支持ActiveX控件,只要继承通用的基类,使用起来十分方便,有兴趣的朋友可以自己玩一下。附件的Demo主窗口展示了不规则形状窗口,镂空效果,控件悬浮效果,及ActiveX控件的使用;控件Demo中罗列了一系列标准控件。在Vista及以后的系统,由于有新API的支持可以实现更简单的半透明窗口(毛玻璃效果),就不用这么费周折了。

四、参考资料
http://www.codeproject.com/Articles/42032/Perfect-Semi-transparent-Shaped-Dialogs-with-Stand
http://www.codeproject.com/Articles/34158/Cool-Semi-transparent-and-Shaped-Dialogs-with-Stan

五、代码下载

http://download.csdn.net/detail/harbinzju/4525285
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 6楼 发表于: 2013-02-11
UpdateLayeredWindow和SetLayeredWindowAttributes
前几天看到一位兄弟模仿Kugou7界面做的一个效果,下载源码一看之后发现在WM_PAINT没有一句自己的代码,只有DrawUI中有绘制的代码。顿时为之一震,原来UpdateLayeredWindow还有种这样的效果。于是乎在网上找了一下资料:
原文地址:http://alexkr.com/source-code/50/layered-windows-and-updatelayeredwindow/
Layered windows and UpdateLayeredWindow
21 Apr 2006 | 1 Comment »

Recently I was playing with transparent (layered) windows in Windows XP.
The basic information about layered windows is available from MSDN,
however the lack of information and examples for UpdateLayeredWindow() inspired me
to write this article.

To create a layered window flag WS_EX_LAYERED must be used.

[pre]//here we create a layered window[/pre][pre]HWND hWnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED, WNDCLASSNAME,WNDCAPTION, WS_POPUP ,WINDOW_X, WINDOW_Y, WINDOW_WIDTH, WINDOW_HEIGHT,NULL, NULL, hInstance, NULL);[/pre]It is also possible to set layered flag after creation of a regular window.

[pre]//setting extended style flag WS_EX_LAYERED);[/pre][pre]SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);[/pre]In short, there are two different methods to work with layered windows under Window 2000 and XP.


Using SetLayeredWindowAttributes()
The idea behind this is that you can easy create a semi transparent window and draw on this window
as you used to draw in a regular Win 32 API applications.

Application processes all regular window messages such as WM_PAINT and WM_ERASEBKGND .
SetLayeredWindowAttributes() can be used in order to change window transparency.
The function works in two alternative modes.
First mode allows to set transparency of pixels of a given color but all other pixels will be absolutely opaque.

The following code makes all white pixels on window 100% transparent

[pre][pre]SetLayeredWindowAttributes(hWnd, RGB(0xff, 0xff, 0xff), 0, LWA_COLORKEY);//                                                                  ^                      ^//                                                                  |                      |//                                                             color key          NOT USED with LWA_COLORKEY[/pre]
Another mode allows to set whole window transparency for all differently colored pixels.
This example makes window 50% transparent.

[pre]SetLayeredWindowAttributes(hWnd, RGB(0xff, 0xff, 0xff), 0x7F, LWA_ALPHA);//                                                            ^                               ^//                                                            |                               |//                                  not used with LWA_ALPHA     opacity level (0 to 255)[/pre]


[/pre][pre]What is good and bad about this method?[/pre]
+ It is easy and intuitive

- It does not allow to set per pixel transparency for complex windows.

- The performance of window drawing with SetLayeredWindowAttributes() is relatively low

Using UpdateLayeredWindow()
This is another method of drawing transparent windows which works relatively faster and it offers more power for programmer.
This function does anything you want for a layered window.
You can change position, size, look and transparency all in one function call.
Also this function can use per pixel Alpha information stored in a bitmap to maintain pixel level transparency.

Note a few moments before using UpdateLayeredWindow().
  1. If you first call SetLayeredWindowAttributes() before UpdateLayeredWindow() you will get errors (0×06).
  2. Since MSDN unclearly says that hdcDst parameter is a “Handle to a device context (DC) for the screen” this actually means a window DC. I got error (number 6) trying to use screen DC.
So the basic scheme is the following.
In a timer message handler I draw the window contents on a memory DC.
Then I update window surface using this function.


[pre][cpp] view plaincopy


    //      // this function is called when hdcBackBuffer bitmap      // contains a fresh look of the window      //      void __fastcall UpdateMemoWindow(HWND hWnd){          HDC hRealDC = GetDC(hWnd);                BLENDFUNCTION bfunc;              bfunc.AlphaFormat = 0;              bfunc.BlendFlags = 0;              bfunc.BlendOp = AC_SRC_OVER;              bfunc.SourceConstantAlpha = ActiveSettings.Opacity;                if (ActiveSettings.TextOnly){                    //                  // BLENDFUNCTION &bfunc is not used in this case                  // because we need to maintain color level opacity                  //                  if (!UpdateLayeredWindow(hWnd, hRealDC, &gWindowPosition, &gWindowSize, \                       hdcBackBuffer, &PointZero, RGB(255,255,255), &bfunc, ULW_COLORKEY \                      )){                      HandleError(L"Failed to update layered window");                  }              }else{                    //                  // the color key RGB(255,255,255) is not used in this case                  // because transparency will be based on pixels of the bitmap                  // selected for hdcBackBuffer                  //                  if (!UpdateLayeredWindow(hWnd, hRealDC, &gWindowPosition, &gWindowSize, \                       hdcBackBuffer, &PointZero, RGB(255,255,255), &bfunc, ULW_ALPHA \                      )){                      HandleError(L"Failed to update layered window");                  }              }            ReleaseDC(hWnd, hRealDC);      }  



[/pre][pre]经过自己的实验,发现和文章还是有一些出入,最后自己做一点总结 :[/pre]
总的来说,调用这两个函数中的任意一个之后,除非程序中调用了InvalidateRect之类的函数,否则系统将接管窗口的绘制,用户收不到WM_PAINT消息,
仿佛就是UpdateLayeredWindow永久改变了HDC的位图一样。而且单独调用UpdateLayeredWindow而没有调用过SetLayeredWindowAttributes的话
每次刷新必须依靠UpdateLayeredWindow,普通地再WM_PAINT中处理是无效的。而调用SetLayeredWindowAttributes

之后就能阻断UpdateLayeredWindow的这种行为。还有一个重要区别是单独UpdateLayeredWindow之后窗口第一次显示
的时候不会受到WM_PAINT.LayeredWindow窗口效率比较低,不适合大而复杂的窗口。
[pre]楼上那个兄弟是在初始化函数中(OnInitDialog,OnCreate...)调用了修改了窗口的style为WS_EX_LAYERED,然后紧接着[/pre][pre]DrawUI(这个函数是他用来绘制的)。程序中没有调用SetLayeredWindowAttributes所以从始至终都没有收到过[/pre][pre]WM_PAINT(如果没有InvalidateRect的话)。但是这对于习惯于在WM_PAINT中处理绘制代码的我不太习惯,所以我把 DrawUI放在WM_PAINT中了,但是收不到这个消息怎么办?可以在初始化中SetLayeredWindowAttributes这样就[/pre][pre]能收到一次WM_PAINT在第一次显示的时候,但是SetLayeredWindowAttributes的 说明中MSDN:Note that once SetLayeredWindowAttributes has been called for a layered window, subsequent UpdateLayeredWindow calls will fail until the layering style bit is cleared and set again.[/pre][pre]所以这样也是不行的,所以可以选择在OnPaint中修改WS_EX_LAYERED属性而不是在初始化函数中。 [/pre][pre]需要特别注意的是UpdateLayeredWindow和SetLayeredWindowAttributes的互斥性。[/pre][pre][/pre][pre][/pre][pre]另:研究一下Layered Window[/pre][pre]    前几天吴同学问我怎么做这样的透明效果:        
        开始想得很简单, 异型窗口+贴PNG图就搞定了, 仔细一看没这么简单, 这个钟表窗口, 边缘部分是透明的, 中间部分是不透明的, 如果是全透明窗口, 创建LayeredWindow之后调用SetLayeredWindowAttributes即可, 但现在这个部分透明的窗口, 是要用到LayeredWindow针对每个像素的特性, 传说中的东西, 一直没实践过.
         看了一下,也很简单, LayeredWindow提供两种模式:
          1,使用SetLayeredWindowAttributes去设置透明度, 完成窗口的统一透明,此时窗口仍然收到PAINT消息, 其他应用跟普通窗口一样.
          2, 使用UpdateLayeredWindow方法, 向系统提交包含bitmap的DC, 交由系统统一管理,此时再也收不到paint消息, 任何对窗口的改变,只能通过UpdateLayeredWindow来修改.
        
          如果你不需要针对像素级别的不同透明,只需要使用SetLayeredWindowAttributes模式即可,用法与普通窗口用法一样,有一点不同,系统会缓存窗口的bitmap,所以当窗口上面的其他窗口被移开时,这是系统会去自己绘制,不会发送paint消息。使用这种模式的好处时,你基本不用改变你使用窗口的方法,你收到paint消息后,绘制的图像会被系统重定向到另一个函数里面,进行组合,从而得出透明效果。
         如果你需要达到针对像素级别的不同透明,也就是上图的想过,或者你想更加直接的去控制窗口的绘制,就必须使用UpdateLayeredWindow方法了,这个方法不重定向你的绘制结果,也不缓存窗口的bitmap,而是完全由你自己来绘制,这样在内存上来说,是更高效的。需要注意的是,一旦你调用了SetLayeredWindowAttributes,UpdateLayeredWindow的调用就会失败,除非重新设置WS_EX_LAYERED,所以他们是互斥的。
         对layeredwindow来说,在不完全透明的地方,是可以接收到鼠标消息的,在完全透明的地方,鼠标的点击将会被穿过,还有一种情况是对窗口设置了WS_EX_TRANSPARENT属性,鼠标消息也会穿过。
        特别注意的是,WS_EX_LAYERED属性是不可以设置给子窗口的。
        看了一下QQ的个人信息展示栏,底部带有这种透明效果,抓起窗口,发现就是使用layeredwindow的UpdateLayeredWindow模式:        
        而百度Hi的信息栏,就没有这种效果了:
                 虽然也是采用的layeredwindow,但是只是为了渐隐效果采用的。采用的,是SetLayeredWindowAttributes模式。
        对于这种透明的效果,另外又有几种旁门左道可以实现,但终归有缺陷,总结一下,有如下几种:
        1,利用异形窗口实现,由于子窗口不能被设置WS_EX_LAYERED,所以,可以给定A、B、C三个窗口,其中,A为全透明窗口,B为UpdateLayeredWindow型的layered窗口,C为正常子窗口,C的父亲为A,B为A的popup窗口。这样,在C上面有不透明的东西,B上有任意透明的东西,唯一要做的,就是当ABC三窗口有任意一个移动或者改变大小时,其他两个都要相应变化。
         这个方案的缺点,一是不适合大规模使用,第二是有同事试验过,移动时如果移动过快会留下残影,这种方案适用于不移动窗口的简单程序。
         2,利用截图背景实现,窗口显示时,对窗口区域的屏幕进行截图,截完之后,设置为窗口的背景。这种方案的缺点,也是窗口不能移动,并且背后不能有动画。只能是一种假透明。此种方案适用于复杂程序,在手机上变成使用的比较多,因为手机的窗口很多是全屏,不移动。
[/pre]
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 7楼 发表于: 2013-02-11
用GDI+调用png图片实现半透明渐变的特效窗口
一、概述
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);
}
详细实现过程请参考源代码!
四、结束语
编写该程序的主要动力来自于对GDI+图像、图形功能的好奇,网上好多例子和文章都是关于C#或delphi等语言的。本人一直以来习惯于使用VC6.0。希望通过此文能增进与大家交流。

QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 8楼 发表于: 2013-02-11
创建控件容器
有时我们需要有一种容器,将一些控件如按钮编辑框等放在这个容器中,则只须移动这个容器,就容器内的控件就会跟着移动,当容器被隐藏时,容器内的控件也跟着隐藏.
实现方法是由CDialog类派生出一个容器类,将控件放入其中,再将这个容器加入到窗口中.
具体实现方法如下:
首先新建一个workspace,再新建一个对话框资源,ID设置为IDD_DIALOG_PANEL,将其OK和Cancel按钮删掉,就得到一个空白的对话框,这就是一会儿要用到的容器,你可以根据需要在其中加入各种容器,记得将Style标签的Style设置为Child,Border设置为None.
然后运行ClassWizard,会自动提示你新建一个对话框资源对应的类。不妨命名为Panel,继承自CDialog。
在TestPanelDlg.h中加入:
CDialog* m_pPanel;
CRect m_rectPanel;
m_rectPanel主要是用于确定m_Panel的位置。
在TestPanle.cpp中加入:
#include "Panel.h"
在你想创建容器的地方加入如下代码:
CRect rectMainToLefttop; //主窗口相对于屏幕左上角的位置
GetWindowRect(&rectMainToLefttop);

int nCaption = ::GetSystemMetrics(SM_CYCAPTION); //标题栏的高度
int nXEdge = ::GetSystemMetrics(SM_CXEDGE); //横向边距
int nYEdge = ::GetSystemMetrics(SM_CYEDGE); //纵向边距

CRect rectPanelToLefttop; //容器相对于屏幕左上角的位置
GetDlgItem(IDC_STATIC_POSITION )->GetWindowRect(&rectPanelToLefttop);

//计算主窗口有效区域(你从资源编辑器中看到的蓝色虚线框)相对于屏幕左上角的位置
rectMainToLefttop.top=rectMainToLefttop.top+nCaption+nYEdge;
rectMainToLefttop.left=rectMainToLefttop.left+2*nXEdge;

//计算容器相对于主窗口有效区域左上角的位置
m_rectPanel.top=rectPanelToLefttop.top-rectMainToLefttop.top;
m_rectPanel.left=rectPanelToLefttop.left-rectMainToLefttop.left;
m_rectPanel.bottom=rectPanelToLefttop.bottom-rectMainToLefttop.top;
m_rectPanel.right=rectPanelToLefttop.right-rectMainToLefttop.left;

//动态创建容器及其内容,并将其显示在指定位置
m_pPanel = new Panel;
m_pPanel->Create(IDD_DIALOG_PANEL, this);
m_pPanel->ShowWindow(SW_SHOW);
m_pPanel->MoveWindow(m_rectPanel);

QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
级别: 管理员
发帖
8517
金币
2758
威望
3227
贡献值
0
元宝
0
只看该作者 9楼 发表于: 2013-02-12
一个自适应大小的位图控件
对话框编辑器中的控件工具条中的图片控制主要是在一个对话框中快速地显示一个图象,它是很有用的。但是它只能显示图片的原始尺寸。如果你想显示一幅位图,它有可能和其他控制一起重新排列,问题就出来了。如果你改变了对话框的字体,则每个控制的尺寸将发生变化,但是显示位图的图片控制却没有。同样,当系统字体发生变化是也会出现类似问题。

为了解决此问题,我写了一个CStatic的派生类,按照CStatic控制的大小显示位图。当字体尺寸改变时,CStatic的窗口尺寸亦随之发生变化,位图将自动伸缩来适应新的大小。这样就允许显示的图象比原始尺寸小或大了。  

使用此类很容易,将CBitmapPicture类加入到你的项目,然后为你的对话框建立一个CStatic对象,并且将该成员的类型与CBitmapPicture关联起来,接着在你的OnInitDialog函数里调用CBitmapPicture::SetBitmap()设置将要用到的位图即可。  

BOOL SetBitmap(UINT nIDResource);[font=verdana;] // Loads bitmap from resource ID

BOOL SetBitmap(LPCTSTR lpszResourceName); [font=verdana;]// Loads bitmap from resource name
BOOL SetBitmap(HBITMAP hBitmap); [font=verdana;]// Not recommended, as reloads can't be done

[font=verdana;]
源程序:



#if !defined(AFX_BITMAPPICTURE_H__A4BE2021_689E_11D1_ABBA_00A0243D1382__INCLUDED_)
#define AFX_BITMAPPICTURE_H__A4BE2021_689E_11D1_ABBA_00A0243D1382__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

[font=verdana;]// BitmapPicture.h : header file
//
// Copyright (c) Chris Maunder (Chris.Maunder@cbr.clw.csiro.au)
// Written 1 December, 1997


/////////////////////////////////////////////////////////////////////////////
// CBitmapPicture window


class CBitmapPicture : public CStatic
{
[font=verdana;]// Construction
public:
     CBitmapPicture();

[font=verdana;]// Operations
public:
    BOOL SetBitmap(HBITMAP hBitmap); // Not recommended
    BOOL SetBitmap(UINT nIDResource);
    BOOL SetBitmap(LPCTSTR lpszResourceName);
    BOOL ReloadBitmap();

[font=verdana;]// Overrides
    // ClassWizard generated virtual function overrides
   //{{AFX_VIRTUAL(CBitmapPicture)

   protected:
   virtual void PreSubclassWindow();
   virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
   //}}AFX_VIRTUAL
[font=verdana;]
// Implementation

public:
    virtual ~CBitmapPicture();

[font=verdana;]// Attributes
protected:
    HBITMAP m_hBitmap;
    BITMAP m_bmInfo;

private:
    int m_nResourceID;
    CString m_strResourceName;

[font=verdana;]// Generated message map functions
protected:
[font=verdana;]   //{{AFX_MSG(CBitmapPicture)
   afx_msg BOOL OnEraseBkgnd(CDC* pDC);
   afx_msg void OnSysColorChange();
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};

[font=verdana;]/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_BITMAPPICTURE_H__A4BE2021_689E_11D1_ABBA_00A0243D1382__INCLUDED_)

[font=verdana;]
// BitmapPicture.cpp : implementation file
//
// Copyright (c) 1997 Chris Maunder (Chris.Maunder@cbr.clw.csiro.au)
// Written 1 December, 1997

#include "stdafx.h"
#include "BitmapPicture.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

[font=verdana;]// if UPDATE_ENTIRE_CLIENT_AREA is not defined then only the update region of
// the bitmap is updated. Otherwise, on each update, the whole client area of
// the bitmap is drawn. UPDATE_ENTIRE_CLIENT_AREA is slower, but distortion
// of the picture may occur if it is not defined.

#define UPDATE_ENTIRE_CLIENT_AREA
[font=verdana;]
/////////////////////////////////////////////////////////////////////////////
// CBitmapPicture


CBitmapPicture::CBitmapPicture()
{
   m_hBitmap = NULL;

   m_nResourceID = -1;
   m_strResourceName.Empty();
}

CBitmapPicture::~CBitmapPicture()
{
   if (m_hBitmap) ::DeleteObject(m_hBitmap);
}

BEGIN_MESSAGE_MAP(CBitmapPicture, CStatic)
[font=verdana;]//{{AFX_MSG_MAP(CBitmapPicture)
   ON_WM_ERASEBKGND()
   ON_WM_DRAWITEM_REFLECT()
   ON_WM_SYSCOLORCHANGE()
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

[font=verdana;]/////////////////////////////////////////////////////////////////////////////
// CBitmapPicture message handlers


BOOL CBitmapPicture::SetBitmap(HBITMAP hBitmap)
{
   ::DeleteObject(m_hBitmap);
   m_hBitmap = hBitmap;
   return ::GetObject(m_hBitmap, sizeof(BITMAP), &m_bmInfo);
}

BOOL CBitmapPicture::SetBitmap(UINT nIDResource)
{
   m_nResourceID = nIDResource;
   m_strResourceName.Empty();

   HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
                                       MAKEINTRESOURCE(nIDResource),
                                       IMAGE_BITMAP,
                                       0,0,
                                       LR_LOADMAP3DCOLORS);
   if (!hBmp) return FALSE;
   return CBitmapPicture::SetBitmap(hBmp);
}

BOOL CBitmapPicture::SetBitmap(LPCTSTR lpszResourceName)
{
   m_nResourceID = -1;
   m_strResourceName = lpszResourceName;

   HBITMAP hBmp = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
                                      lpszResourceName,
                                      IMAGE_BITMAP,
                                      0,0,
                                      LR_LOADMAP3DCOLORS);
   if (!hBmp) return FALSE;
   return CBitmapPicture::SetBitmap(hBmp);
}

[font=verdana;]// Suggested by P?l K. Used to reload the bitmap on system colour changes.
BOOL CBitmapPicture::ReloadBitmap()
{
   if (m_nResourceID > 0)
      return SetBitmap(m_nResourceID);
   else if (!m_strResourceName.IsEmpty())
      return SetBitmap(m_strResourceName);
   else [font=verdana;]// if SetBitmap(HBITMAP hBitmap) was used directly then we can't reload.
      return FALSE;
}

void CBitmapPicture::PreSubclassWindow()
{
    CStatic::PreSubclassWindow();
    ModifyStyle(0, SS_OWNERDRAW);
}

BOOL CBitmapPicture::OnEraseBkgnd(CDC* pDC)
{
   CRect rect;
   GetClientRect(rect);

[font=verdana;]   // If no bitmap selected, simply erase the background as per normal and return
   if (!m_hBitmap)
   {
      CBrush backBrush(::GetSysColor(COLOR_3DFACE));[font=verdana;] // (this is meant for dialogs)
      CBrush* pOldBrush = pDC->SelectObject(&backBrush);

      pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
      pDC->SelectObject(pOldBrush);

      return TRUE;
    }

[font=verdana;]   // We have a bitmap - draw it.

   // Create compatible memory DC using the controls DC

   CDC dcMem;
   VERIFY( dcMem.CreateCompatibleDC(pDC));

[font=verdana;]   // Select bitmap into memory DC.
   HBITMAP* pBmpOld = (HBITMAP*) ::SelectObject(dcMem.m_hDC, m_hBitmap);

[font=verdana;]   // StretchBlt bitmap onto static's client area
#ifdef UPDATE_ENTIRE_CLIENT_AREA
   pDC->StretchBlt(rect.left, rect.top, rect.Width(), rect.Height(),
        &dcMem, 0, 0, m_bmInfo.bmWidth-1, m_bmInfo.bmHeight-1,SRCCOPY);
#else
    CRect TargetRect; [font=verdana;]// Region on screen to be updated
    pDC->GetClipBox(&TargetRect);
    TargetRect.IntersectRect(TargetRect, rect);

    CRect SrcRect; [font=verdana;]// Region from bitmap to be painted
    SrcRect.left = MulDiv(TargetRect.left, m_bmInfo.bmWidth, rect.Width());
    SrcRect.top = MulDiv(TargetRect.top, m_bmInfo.bmHeight, rect.Height());
    SrcRect.right = MulDiv(TargetRect.right, m_bmInfo.bmWidth, rect.Width());
    SrcRect.bottom = MulDiv(TargetRect.bottom, m_bmInfo.bmHeight, rect.Height());

    pDC->StretchBlt(TargetRect.left, TargetRect.top, TargetRect.Width(), TargetRect.Height(),
       &dcMem, SrcRect.left, SrcRect.top, SrcRect.Width(), SrcRect.Height(),SRCCOPY);
#endif

   ::SelectObject(dcMem.m_hDC, pBmpOld);

   return TRUE;
}

void CBitmapPicture::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
   ASSERT(lpDrawItemStruct != NULL);

   CString str;
   GetWindowText(str);
   if (!str.GetLength()) return;

   CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
   CRect rect = lpDrawItemStruct->rcItem;
   DWORD dwStyle = GetStyle();
   int nFormat = DT_NOPREFIX | DT_NOCLIP | DT_WORDBREAK | DT_SINGLELINE;

   if (dwStyle & SS_CENTERIMAGE) nFormat |= DT_VCENTER;
   if (dwStyle & SS_CENTER) nFormat |= DT_CENTER;
   else if (dwStyle & SS_RIGHT) nFormat |= DT_RIGHT;
   else nFormat |= DT_LEFT;

   int nOldMode = pDC->SetBkMode(TRANSPARENT);
   pDC->DrawText(str, rect, nFormat);
   pDC->SetBkMode(nOldMode);
}

[font=verdana;]// Suggested by P?l K. T?nder.
void CBitmapPicture::OnSysColorChange()
{
   CStatic::OnSysColorChange();
   ReloadBitmap();
}
 
QQ: 378890364 微信:wwtree(省短信费) 紧急事宜发短信到0061432027638  本站微博:http://t.qq.com/wwtree QQ群:122538123
描述
快速回复

您目前还是游客,请 登录注册
批量上传需要先选择文件,再选择上传