最近在弄一个测试程序,希望可以创建一个自定义的窗口来画图,由于在console工程中,所以想自己创建一个窗口,在路上........
http://hi.baidu.com/xiuyuan132/blog/item/12bb3826c9e6653f8644f90a.html
该函数用来创建一个窗体
认识 CreateWindow 函数:
CreateWindow( lpClassName: PChar; {窗口类的名字} lpWindowName: PChar; {窗口标题} dwStyle: DWORD; {窗口样式, 参加下表} X,Y: Integer; {位置; 默认的X,Y可以指定为: Integer(CW_USEDEFAULT)} nWidth,nHeight: Integer;{大小; 默认的宽度、高度可以指定为: Integer(CW_USEDEFAULT)}} hWndParent: HWND; {父窗口句柄} hMenu: HMENU; {主菜单句柄} hInstance: HINST; {模块实例句柄, 也就是当前 exe 的句柄} lpParam: Pointer {附加参数, 创建多文档界面时才用到, 一般设为 nil} ): HWND; {返回所创建的窗口的句柄} //dwStyle 窗口样式参数可选值: WS_OVERLAPPED = 0; {重叠式窗口, 应带标题栏和边框} WS_POPUP = DWORD($80000000); {弹出式窗口, 不能与 WS_CHILD 一起使用} WS_CHILD = $40000000; {子窗口, 不能与 WS_POPUP 一起使用} WS_MINIMIZE = $20000000; {最小化窗口} WS_VISIBLE = $10000000; {初始时可见} WS_DISABLED = $8000000; {禁止输入} WS_CLIPSIBLINGS = $4000000; {裁剪子窗口, 也就是子窗口重绘不影响重叠的其他子窗口, 应与 WS_CHILD 一起使用} WS_CLIPCHILDREN = $2000000; {在父窗口中绘图时绕开子窗口区域, 创建父窗口是使用} WS_MAXIMIZE = $1000000; {最大化窗口} WS_CAPTION = $C00000; {有标题栏} WS_BORDER = $800000; {有细线边框} WS_DLGFRAME = $400000; {对话框窗口} WS_VSCROLL = $200000; {有垂直滚动条} WS_HSCROLL = $100000; {有水平滚动条} WS_SYSMENU = $80000; {带系统标题栏, 须同时指定 WS_CAPTION} WS_THICKFRAME = $40000; {带宽边框, 宽边框用于改变窗口大小} WS_GROUP = $20000; {能用方向键转移焦点} WS_TABSTOP = $10000; {能用 TAB 转移焦点} WS_MINIMIZEBOX = $20000; {有最小化按钮} WS_MAXIMIZEBOX = $10000; {有最大化按钮} WS_TILED = WS_OVERLAPPED; WS_ICONIC = WS_MINIMIZE; WS_SIZEBOX = WS_THICKFRAME; WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED or WS_CAPTION or WS_SYSMENU or WS_THICKFRAME or WS_MINIMIZEBOX or WS_MAXIMIZEBOX); WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW; WS_POPUPWINDOW = (WS_POPUP or WS_BORDER or WS_SYSMENU); WS_CHILDWINDOW = (WS_CHILD); //另外还有一些扩展样式: WS_EX_DLGMODALFRAME = 1; {指定双边界窗口; 藉此指定 WS_CAPTION 创建标题栏} WS_EX_NOPARENTNOTIFY = 4; {在窗口创建或取消时不向父窗口发送 WM_PARENTNOTIFY 消息} WS_EX_TOPMOST = 8; {在所有非最顶层窗口的上面} WS_EX_ACCEPTFILES = $10; {可接受拖放文件} WS_EX_TRANSPARENT = $20; {透明样式, 在同属窗口已重画时该窗口才可重画} WS_EX_MDICHILD = $40; {创建一个 MDI 子窗口} WS_EX_TOOLWINDOW = $80; {工具窗口} WS_EX_WINDOWEDGE = $100; {带立体的边框} WS_EX_CLIENTEDGE = $200; {带阴影的边界} WS_EX_CONTEXTHELP = $400; {标题包含一个问号标志, 不能与 WS_MAXIMIZEBOX 和 WS_MINIMIZEBOX 同时使用} WS_EX_RIGHT = $1000; {窗口具有右对齐属性} WS_EX_LEFT = 0; {窗口具有左对齐属性, WS_EX_LEFT 是缺省设置} WS_EX_RTLREADING = $2000; {窗口文本从右到左} WS_EX_LTRREADING = 0; {窗口文本从左到右, WS_EX_LTRREADING 是缺省设置} WS_EX_LEFTSCROLLBAR = $4000; {垂直滚动条在左边界, 只用于特殊语言环境} WS_EX_RIGHTSCROLLBAR = 0; {垂直滚动条在右边界, WS_EX_RIGHTSCROLLBAR 是缺省设置} WS_EX_CONTROLPARENT = $10000; {允许用户使用 Tab 键在窗口的子窗口间搜索} WS_EX_STATICEDGE = $20000; {窗口不可用时创建一个三维边界} WS_EX_APPWINDOW = $40000; {当窗口可见时, 将一个顶层窗口放置到任务条上} WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE or WS_EX_CLIENTEDGE); {立体边框并带阴影} WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE or WS_EX_TOOLWINDOW or WS_EX_TOPMOST); {立体边框、工具条窗口样式、在顶层} WS_EX_LAYERED = $00080000; {分层或透明窗口, 该样式可使用混合特效} WS_EX_NOINHERITLAYOUT = $00100000; {子窗口不继承父窗口的布局} WS_EX_LAYOUTRTL = $00400000; {从右到左的布局} WS_EX_COMPOSITED = $02000000; {用双缓冲从下到上绘制窗口的所有子孙} WS_EX_NOACTIVATE = $08000000; {处于顶层但不激活}分析:
首先要用 CreateWindow 创建窗口, 才能用 ShowWindow 显示窗口; 因为 ShowWindow 需要 CreateWindow 返回的句柄.
在 CreateWindow 的参数中, 位置与大小与窗口标题无须多说;
父窗口与菜单, 暂时都不需要, 先可置为 0;
程序实例的句柄, Delphi 已经为我们准备好了: HInstance; (参见原来的说明)
窗口样式在前面的例子中我们使用了: WS_OVERLAPPEDWINDOW, 它代表几种特点的组合, 表示了常规窗口.
CreateWindow 还有一个重要参数(第一个参数 lpClassName): 窗口类的名字.
Windows 要求我们要登记并注册一个窗口类以后, 才可以用 CreateWindow 建立窗口!
http://blog.csdn.net/OneOnce/archive/2010/03/05/5349719.aspx
// 包含头文件windows.h
#include <windows.h>
#include "tchar.h"
// 预先声明Message Handler,可以叫做任何名字,这里是MyWindowProcedure
LRESULT CALLBACK MyWindowProcedure(HWND, UINT, WPARAM, LPARAM);
// 以下是所有Windows程序都需要的WinMain函数
// WinMain主要用来实现三个功能:
// 1. 注册Window Class;
// 2. 在内存中创建Window并初始化Window的属性;
// 3. 创建一个Message Loop来检查Message Queue中有没有该Window的Message。
//nCmdShow:指明窗口如何显示
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpszCmdLine,int nCmdShow)
{
wchar_t *szAppName = _T("WinHello"); // 定义一个字符串
HWND hwnd; // 定义一个Window Handle变量
MSG msg; // 定义一个Message结构的变量,用来储存Message的信息
WNDCLASS wc; // 定义一个Window Class数据结构,用来储存Window Class的属性
//下面这段代码用来定义Window的属性,例如Message Handler的地址、窗口背景、光标和图标等
wc.style=CS_HREDRAW|CS_VREDRAW; // 设置style: 当窗口改变大小时就重新绘制窗口
wc.lpfnWndProc=(WNDPROC)MyWindowProcedure; // 设定Window Procedure
wc.cbClsExtra=0; // 用来储存Class Structure后的额外的数据,这里不需要
wc.cbWndExtra=0; // 用来储存Window Instance后的额外的数据,这里不需要
wc.hInstance=hInstance; // Window Procedure所在的Instance
wc.hIcon=LoadIcon(NULL,IDI_APPLICATION); // class的图标
wc.hCursor=LoadCursor(NULL,IDC_ARROW); // class的光标
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1); // 背景刷
wc.lpszMenuName=NULL; // 菜单资源的名字,这里没有
wc.lpszClassName=szAppName; // 应用程序的名字
// 注册Window,通过调用API函数RegisterClass来实现
// 注册Window Class的一个目的就是将Window和Window Procedure关联起来
RegisterClass(&wc);
// 注册Window Class后,WinMain就调用CreateWindow函数来创建应用程序的Window
hwnd = CreateWindow(szAppName, // 已注册的Class名字
L"Hello, World – Windows_98 Style", // Window名字(标题)
WS_OVERLAPPEDWINDOW, // Window风格
CW_USEDEFAULT, // Window起点的X坐标
CW_USEDEFAULT, // Window起点的Y坐标
CW_USEDEFAULT, // Window的宽度
CW_USEDEFAULT, // Window的高度
HWND_DESKTOP, // 父窗口的handle
NULL, // 菜单的handle
hInstance, // 应用程序instance的handle
NULL // window-creation数据的指针
);
// 以下两条语句用来显示Window
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
// 用while循环语句来检索并发送Messages
// 从Message Queue中检索Message,并将它放到变量msg中。
// 当收到"WM_QUIT"这个Message时,GetMessage函数就返回0,循环结束。而且WinMain函数也结束,程序终止。
while(GetMessage(&msg, NULL, 0, 0))
{
//函数功能:该函数将虚拟键消息转换为字符消息。字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出。
TranslateMessage(&msg); // 将Virtual-Key Messages转化为Character Messages
//该函数调度一个消息给窗口程序。通常调度从GetMessage取得的消息。
DispatchMessage(&msg); // 将Message发送到Window Procedure
}
return (int)msg.wParam;
}
/* 操作系统向应用程序发送一系列消息,如左键按下和左键抬起,应用程序将通过GetMessage等方法最终将消息提交到窗口过程 */
// MyWindowProcedure函数处理WM_PAINT和WM_DESTROY这两个Message,然后必须调用DefWindowProc去处理其他Message
LRESULT CALLBACK MyWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps; // 定义一个PAINTSTRUCT结构的变量,用来储存绘制Window的Client Area的信息
HDC hdc; // 定义一个HDC变量
LPCTSTR text=L"Welcome to windows!"; // 定义一个LPCTSTR类型的字符串指针
// 用switch语句来处理WM_PAINT和WM_DESTROY这两个Message
switch(message)
{
case WM_PAINT:
// 下面5条语句是用来在屏幕上输出文字的,我们在后面的章节会详细讨论这个问题的,这里就不多说了
/*
BeginPaint函数准备指定的窗口来重绘并将绘画相关的信息放到一个PAINTSTRUCT结构中。
HDC BeginPaint(HWND hwnd, // 窗口的HANDLE
LPPAINTSTRUCT lpPaint // 绘画信息
);
*/
hdc = BeginPaint(hwnd, &ps);
RECT rect;
GetClientRect(hwnd, &rect);
TextOut(hdc, (rect.right-rect.left)/2, (rect.bottom-rect.top)/2, text, lstrlen(text));//该函数用当前选择字符、背景颜色和正文颜色将一个字符串写到指定位置。
EndPaint(hwnd, &ps);
return 0;
// 处理退出消息
case WM_DESTROY:
/*
函数功能:该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息。
函数原型:VOID PostQuitMessage(int nExitCode);
参数: pExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的wParam参数
*/
PostQuitMessage(0);
return 0;
}
// 调用默认的Window Procedure,使所有Message都可以被处理
return DefWindowProc(hwnd, message, wParam, lParam);
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/OneOnce/archive/2010/03/05/5349719.aspx
4. WinMain函数的定义
5. 窗口的创建
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
[知识点] 在Windows.h中,以CS_开头的类样式(Class Style)标识符被定义为16位的常量,这些常量都只有某1位为1。在VC++开发环境中,用goto definition,可以看到CS_VREDRAW=0x0001,CS_HREDRAW=0x0002,CS_DBLCLKS =0x0008,CS_NOCLOSE=0x0200,可将这些16进制数转换为2进制数,就发现它们都只有1位为1,并且为1的位各不相同。用这种方式定义的标识符称为“位标志”,可以用位运算操作符来组合使用这些样式。
例如,要让窗口在水平和垂直尺寸发生变化时发生重绘,可以使用位或(|)如style=CS_HREDRAW | CS_VREDRAW。
例如,要去掉先前的style变量所具有的CS_VREDRAW样式,可以使用取反(~)符进行操作,再和这个变量进行与(&)操作即可实现。如style=style & ~ CS_VREDRAW。
第二个成员变量lpfnWndProc是一个函数指针,指向窗口过程函数,窗口过程函数是一个回调函数,一个Windows程序可以包含多个窗口过程函数,一个窗口过程总是与某一个特定的窗口类相关联(通过WNDCLASS结构体中的lpfnWndProc成员变量指定),基于该窗口过程。
6. 窗口的创建
父 窗 口
|
子 窗 口
|
销毁
|
在父窗口被销毁之前销毁
|
隐藏
|
在父窗口被隐藏之前隐藏,子窗口只有在父窗口可见时可见
|
移动
|
跟随父窗口客户区一起移动
|
显示
|
在父窗口显示之后显示
|