qxtianlong 发表于 2006-1-5 13:54:39

给windows换肤(一)

region.h
这个是我在flipcode上看到的文章,个人觉得简单易懂就拿过来了
版权归作者 Vander Nunes
我只是起一个媒介的作用,希望和我一样弱的菜菜可以有所收获
   修改者   小鱼儿(qxtianlong)
//首先我们来看看头文件,做些声明


#ifndef _REGION_H_

#define _REGION_H_
#include <windows.h>

// app window handle
HWND hWnd=NULL;

// region toggle
bool bRegioned;

// app window procedure
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);

// window creation helper
bool MakeWindow(int iWidth, int iHeight);

#endif
//以上别告诉我不懂厄

region.cpp
下面我们看看CPP文件
下面是代码部分
#include "region.h"




// ------------------------------------------------------------------------
// The application entry point
// ------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, \
                   LPSTR lpCmdLine, int nCmdShow)
{
// -------------------------------------------------
// create the application window.
// -------------------------------------------------

if ( !MakeWindow(320, 240) ) return -1;

// show window
ShowWindow(hWnd, SW_SHOW);


// -------------------------------------------------
// now just keep the application going...
// -------------------------------------------------

MSG mMsg;

while (1)
{

    if(PeekMessage(&mMsg, 0, 0, 0, PM_REMOVE))
    {
      // -------------------------------------------------
      // the quit message
      // can arrive at any time from our window procedure.
      // -------------------------------------------------
      if(mMsg.message == WM_QUIT)
      { break; }

      // -------------------------------------------------
      // the common stuff, just translate&dispatch.
      // -------------------------------------------------
      TranslateMessage(&mMsg);
      DispatchMessage(&mMsg);
    }

}


// -------------------------------------------------
// free allocated resources
// -------------------------------------------------

DestroyWindow(hWnd);


// tchau!
return 0;
}



// ------------------------------------------------------------------------
// Build a basic region and set it to the window.
// ------------------------------------------------------------------------
void RegionMe()
{
// --------------------------------------------------
// create an elliptical region.
// we use a negative starting y coordinate to make
// the ellipse cover a bit more of the caption.
// --------------------------------------------------
HRGN hRegion1 = CreateEllipticRgn(20,-20,190,150);

// --------------------------------------------------
// create one more elliptical region in other place.
// --------------------------------------------------
HRGN hRegion2 = CreateEllipticRgn(140,100,300,240);

// --------------------------------------------------
// combine the two regions to build a new region
// that will be the sum of the two.
// the resulting region will be stored in region1,
// like if we were making something like:
// hRegion1 = hRegion1 + hRegion2.
// --------------------------------------------------
CombineRgn(hRegion1, hRegion1, hRegion2, RGN_OR);

// --------------------------------------------------
// assign the region to the window
// --------------------------------------------------
SetWindowRgn(hWnd, hRegion1, true);

// --------------------------------------------------
// delete the region objects
// --------------------------------------------------
DeleteObject(hRegion1);
DeleteObject(hRegion2);

// --------------------------------------------------
// flag just to make sure our app knows about it.
// --------------------------------------------------
bRegioned = true;
}



// ------------------------------------------------------------------------
// Remove the region from the window
// ------------------------------------------------------------------------
void UnRegionMe()
{
// --------------------------------------------------
// unassign the region
// --------------------------------------------------
SetWindowRgn(hWnd, NULL, true);

// --------------------------------------------------
// flag just to make sure our app knows about it.
// --------------------------------------------------
bRegioned = false;
}



// ------------------------------------------------------------------------
// A Basic, still smart window creation function.
// ------------------------------------------------------------------------
bool MakeWindow(int iWidth, int iHeight)
{
// our window class
WNDCLASS wndWc;

// ---------------------------------------------------------
// fill window class members
// ---------------------------------------------------------
wndWc.style = CS_OWNDC;
wndWc.lpfnWndProc = (WNDPROC) WndProc;
wndWc.cbClsExtra = 0;
wndWc.cbWndExtra = 0;
wndWc.hInstance = GetModuleHandle(NULL);
wndWc.hIcon = NULL;
wndWc.hCursor = LoadCursor(0, IDC_ARROW);
wndWc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndWc.lpszMenuName = NULL;
wndWc.lpszClassName = "w32skin";

// register class
if (!RegisterClass(&wndWc)) return false;
// ---------------------------------------------------------

// get actual screen resolution
int iSw = (WORD)GetSystemMetrics(SM_CXSCREEN);       // width
int iSh = (WORD)GetSystemMetrics(SM_CYSCREEN);       // height

// make a rectangle on the center of the screen
RECT rc = { (iSw - iWidth)/2, (iSh - iHeight)/2, iWidth, iHeight };

// create the window. the spaces on the window title
// are just to make sure this will be visible when the region
// is active. just run the app and you'll understand. =)
hWnd = CreateWindow("w32skin", "       w32skin",
                      WS_OVERLAPPEDWINDOW,
                      rc.left,rc.top, iWidth,iHeight,
                      NULL, NULL, GetModuleHandle(NULL), NULL);

// return result
return (hWnd?true:false);
}



// ------------------------------------------------------------------------
// Our application window procedure.
// Here we'll process the messages sent to our application window.
// ------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
{

switch(uMessage)
{

    case WM_KEYDOWN:
    {
      // ---------------------------------------------------------
      // pressing ESC will finish the app.
      // ---------------------------------------------------------
      switch (wParam)
      {
      case VK_ESCAPE:
          PostQuitMessage(0);
          break;

      case VK_SPACE:
          if (!bRegioned)
            RegionMe();
          else
            UnRegionMe();
      }
      break;
    }

    case WM_PAINT:
    {
      // -------------------------------------------------
      // tell user to press SPACE to toggle region.
      // -------------------------------------------------

      PAINTSTRUCT ps;
      BeginPaint(hWnd,&ps);

      TextOut(ps.hdc, 115,90, "Press SPACE", 11);

      EndPaint(hWnd,&ps);

      break;
    }

    case WM_DESTROY:
    {
      // ---------------------------------------------------------
      // closing the window will finish the app.
      // (the quit message will be read by our main loop)
      // ---------------------------------------------------------
      PostQuitMessage(0);
      break;
    }


}

// ---------------------------------------------------------
// call the default window procedure to keep things going.
// ---------------------------------------------------------
return DefWindowProc(hWnd,uMessage,wParam,lParam);
}

好了以上文件完全可编译,在XPSP2+VS2003下通过
注意:只要去掉我的不正规的文字说明就可以了,别告诉我你不会哇~~

[ 本帖最后由 qxtianlong 于 2006-1-6 17:42 编辑 ]

qxtianlong 发表于 2006-1-5 13:55:16

下面我们来解释一下上面的代码
首先头文件中
HWND hWnd=NULL;
代表窗口的句柄,就是一个标识
bool bRegioned;
代表一个状态量(一个开关)
后面会看到
程序根据bRegioned的值,做相应的处理
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam);
这个是一个事件循环函数的声明(回调函数)
bool MakeWindow(int iWidth, int iHeight);
这个是一个基本的定义一个类和建立一个窗口的函数的声明
在后面我们会看到他的具体定义
不错嘛~~头文件部分我们就介绍完了,其实你也可以直接写在CPP文件中的,怎么样随你便,只要能
达到效果就可以了
---------------------------------------------------------------------------------------------------
下面我们来解释一下CPP文件中的主要内容
---------------------------------------------------------------------------------------------------
#include "region.h"
这句的作用是包含前面的头文件
我们来看看MakeWindow()函数的定义
bool MakeWindow(int iWidth, int iHeight)
{
// 首先定义一个类,这是一个比较老的版本了,新的版本是WNDCLASSEX使用起来大同小异
WNDCLASS wndWc;

// ---------------------------------------------------------
// 填充类成员
// ---------------------------------------------------------
wndWc.style = CS_OWNDC;//似乎是windows属性样式的标志
wndWc.lpfnWndProc = (WNDPROC) WndProc;//指向回调函数的指针
wndWc.cbClsExtra = 0;
wndWc.cbWndExtra = 0;
wndWc.hInstance = GetModuleHandle(NULL);//获得当前应用程序实例
wndWc.hIcon = NULL;//图标
wndWc.hCursor = LoadCursor(0, IDC_ARROW);//光标
wndWc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//背景画刷
wndWc.lpszMenuName = NULL;//菜单
wndWc.lpszClassName = "w32skin";//类名

// 注册类,失败则返回false,这个版本也比较老,新版本为RegisterClassEx()
if (!RegisterClass(&wndWc)) return false;
// ---------------------------------------------------------

// get actual screen resolution
int iSw = (WORD)GetSystemMetrics(SM_CXSCREEN);       // width
int iSh = (WORD)GetSystemMetrics(SM_CYSCREEN);       // height
上面两句为调用(API)GetSystemMetrics获取屏幕大小(像素级)
SM_CXSCREEN,SM_CYSCREEN分别为宽和高
// make a rectangle on the center of the screen
RECT rc = { (iSw - iWidth)/2, (iSh - iHeight)/2, iWidth, iHeight };
上面为定义一个大小为iWidth,iHight的矩形,在这里就理解为大小为iWidth,iHeight的窗口
RECT结构原型如下
typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
似乎left,top分别代表左上角的x,y坐标,right,bottom分别代表右下角的x,y坐标
那么上面的左上角坐标就为
(iSw - iWidth)/2, (iSh - iHeight)/2
怎么样还是容易理解的吧
// create the window. the spaces on the window title
// are just to make sure this will be visible when the region
// is active. just run the app and you'll understand. =)
hWnd = CreateWindow("w32skin", "       w32skin",
                      WS_OVERLAPPEDWINDOW,
                      rc.left,rc.top, iWidth,iHeight,
                      NULL, NULL, GetModuleHandle(NULL), NULL);
上面为创建一个窗口
这个也是一个比较老的版本,新版本CreateWindowEx()
第一个参数为类名
第二个参数为窗口标题名
第三个参数为窗口外观风格
第四个参数为窗口左上角坐标X
第五个参数为窗口左上角坐标Y
第六个参数为窗口的宽
第七个参数为窗口的高
第八个参数为是否有父窗口NULL代表没有父窗口,桌面就是父窗口
第九个参数为是否有菜单NULL为没有菜单
第十个参数为应用程序实例
第十一个参数为一些高级特征通常为NULL
// return result
return (hWnd?true:false);
这一句为窗口创建成功返回true,否则返回false
}

下面我们看看主要的绘制部分
void RegionMe()
{
// --------------------------------------------------
// create an elliptical region.
// we use a negative starting y coordinate to make
// the ellipse cover a bit more of the caption.
// --------------------------------------------------
HRGN hRegion1 = CreateEllipticRgn(20,-20,190,150);

// --------------------------------------------------
// create one more elliptical region in other place.
// --------------------------------------------------
HRGN hRegion2 = CreateEllipticRgn(140,100,300,240);
以上是创建两个圆,CreateEllipticRgn原型如下:
HRGN CreateEllipticRgn(
int nLeftRect,   // x-coord of upper-left corner of rectangle
int nTopRect,    // y-coord of upper-left corner of rectangle
int nRightRect,// x-coord of lower-right corner of rectangle
int nBottomRect// y-coord of lower-right corner of rectangle
);

// --------------------------------------------------
// combine the two regions to build a new region
// that will be the sum of the two.
// the resulting region will be stored in region1,
// like if we were making something like:
// hRegion1 = hRegion1 + hRegion2.
// --------------------------------------------------
CombineRgn(hRegion1, hRegion1, hRegion2, RGN_OR);
以上为合并两个区域大小为hRegion1,CombineRgn原型如下:
int CombineRgn(
HRGN hrgnDest,      // handle to destination region
HRGN hrgnSrc1,      // handle to source region
HRGN hrgnSrc2,      // handle to source region
int fnCombineMode   // region combining mode
);
其中fnCombineMode可以为以下的值

Value                      Description
RGN_AND         Creates the intersection of the two combined regions.
RGN_COPY       Creates a copy of the region identified by hrgnSrc1.
RGN_DIFF      Combines the parts of hrgnSrc1 that are not part of hrgnSrc2.
RGN_OR         Creates the union of two combined regions.
RGN_XOR         Creates the union of two combined regions except for any overlapping areas.
// --------------------------------------------------
// assign the region to the window
// --------------------------------------------------
SetWindowRgn(hWnd, hRegion1, true);
这句就是设置hRegion1区域,SetWindowRgn原型如下:
int SetWindowRgn(
HWND hWnd,   // handle to window
HRGN hRgn,   // handle to region
BOOL bRedraw   // window redraw option
);
hWnd
Handle to the window whose window region is to be set.
hRgn
Handle to a region. The function sets the window region of the window to this region.
If hRgn is NULL, the function sets the window region to NULL.

bRedraw
Specifies whether the system redraws the window after setting the window region. If bRedraw is TRUE, the system does so; otherwise, it does not.
Typically, you set bRedraw to TRUE if the window is visible.


// --------------------------------------------------
// delete the region objects
// --------------------------------------------------
DeleteObject(hRegion1);
DeleteObject(hRegion2);
上面为释放对象
// --------------------------------------------------
// flag just to make sure our app knows about it.
// --------------------------------------------------
bRegioned = true;
设置bRegioned的状态为true
}

qxtianlong 发表于 2006-1-5 13:55:31

剩下的这个
void UnRegionMe()
{
// --------------------------------------------------
// unassign the region
// --------------------------------------------------
SetWindowRgn(hWnd, NULL, true);
设置窗口区域为空
// --------------------------------------------------
// flag just to make sure our app knows about it.
// --------------------------------------------------
bRegioned = false;
设置bRegioned状态为false
}
剩下的就很好说了,进入消息循环,根据是否按了空格键来改变窗口的皮肤
按一次空格键bRegioned的状态就会随之改变
也不知道大家能不能看懂,呵呵
我是根据我的理解写的,不对之处请批评指教

waterbluest 发表于 2006-6-6 10:04:32

简单易懂。。。。。刚睡了一个小时,回来还是看不懂

黑夜彩虹 发表于 2006-6-6 10:43:57

支持一下。。。
页: [1]
查看完整版本: 给windows换肤(一)