您的位置:首页 > 其它

MFC基础知识

2012-03-07 19:17 274 查看
在Visual Studio操作环境中的左侧有三个选项,它们包含应用程序的不同视图,FileView(文件视图),ClassView(类视图),ResourceView(资源视图).

窗口的创建:①、设计一个窗口类;②、注册窗口;③、创建窗口;④、显示及更新窗口

Windows程序的入口函数:WinMain函数

int WINAPI WinMain( //WinMain是由操作系统调用
HINSTANCE bInstance,//应用程序的实例句柄,指示当前句柄
HINSTANCE bPrevInstance,//指示先前句柄
LPSTR IpCmdLine,//字符串类型,相当于char *类型;
int nCmdSbow
);

句柄是资源的标识,按照资源的类型可以分为:图标句柄(HICON),光标句柄(HCURSOR),窗口句柄(HWND),应用程序实例句柄(HINSTANCE).

设计窗口类:

typedef struct_WNDCLASS{   
UINT style;//相当于c语言中的unsigned int,无符号整形,style是指定类风格,例CS_VREDRAW: 当垂直长度改变或移动窗口时,重画整个窗口    
WNDPROC lpfnWndProc;//指向窗口过程,也称为回调函数   
int cbClsExtra;//指定紧随在WNDCLASS数据结构后分配的字节数,系统将其初始化为零   
int cbWndExtra;//指定紧随在窗口实例之后分配的字节数,系统将其初始化为零  
HANDLE hInstance;//标识了该窗口类的窗口过程所在的模块实例的句柄,不能为NULL   
HICON hIcon;//标识了该窗口类的图标.hIcon字段必须是一个图标的句柄;若hIcon字段为NULL,则无论何时用户把应用程序缩至最小时,应用程序必须画一个图标
HCURSOR hCursor;//标识该窗口类的光标,它是一个光标资源的句柄,若hCursor字段为NULL,则无论何时鼠标移到应用程序窗口时,应用程序必须显式设置光标形状
HBRUSH hbrBackground;//标识了该窗口类的背景画笔。 
LPCTSTR lpszMenuName;//指向NULL结束的字符串,该字符串描述菜单的资源名,如同在资源文件里显示的名字一样   
LPCTSTR lpszClassName;// 指向NULL结束的字符串,或者是一个原型(atom) 
}WNDCLASS;

窗口风格CS:

  CS_BYTEALIGNCLIENT: 在字节边界上(在x方向上)定位窗口的用户区域的位置

  CS_BYTEALIGNWINDOW: 在字节边界上(在x方向上)定位窗口的位置

  CS_CLASSDC: 该窗口类的所有窗口实例都共享一个窗口类DC

  CS_DBLCLKS: 允许向窗口发送双击鼠标键的消息

  CS_GLOBALCLASS: 当调用CreateWindow 或 CreateWindowEx 函数来创建窗口时允许它的hInstance参数和注册窗口类时传递给RegisterClass 的 hInstance参数不同。如果不指定该风格,则这两个hInstance 必须相同。

  CS_HREDRAW: 当水平长度改变或移动窗口时,重画整个窗口

  CS_NOCLOSE: 禁止系统菜单的关闭选项

  CS_OWNDC: 给予每个窗口实例它本身的DC。注意,尽管这样是很方便,但它必须慎重使用,因为每个DC大约要占800个字节的内存。

  CS_PARENTDC: 将子窗口的裁剪区域设置到父窗口的DC中去,这样子窗口便可以在父窗口上绘制自身。注意,这是子窗口还是从系统缓存中获取DC,而不是使用父窗口的DC。使用该风格可以提高系统性能。

  CS_SAVEBITS: 以位图形式保存被该窗口遮挡的屏幕部分,这样当给窗口移动以后,系统便可以用该保存的位图恢复屏幕移动的相应部分,从而系统不用向被该窗口遮挡的窗口发送 WM_PAINT 消息。该特性对于菜单类型的窗口比较合适,因为它通常是简短的显示一下之后便消失。设置该特性将增加显示该窗口的时间,因为它通常要先分配保存位图的内存。

  CS_VREDRAW: 当垂直长度改变或移动窗口时,重画整个窗口

下面为一个初始化实例:

WNDCLASS wndclass;//定义窗口类的变量

wndclass.style=CS_HREDRAW|CS_VREDRAW;/*其中CS_HREDRAW:当水平长度改变或移动窗口时,重画整个窗口,CS_VREDRAW:当垂直长度改变或移动窗口时,重画整个窗口,'|'是c语言中的或运算,如果我们希望某一变量既具有CS_HREDRAW和CS_VREDRAW特性我们可以用或运算,如果我们要去掉某一特性,可以用进行取反后再进行与运算,如:style&~CS_VREDRAW*/
wndclass.lpfnWndProc=WndProc; //定义窗口处理函数,WndProc是一个函数指针
wndclass.cbClsExtra=0; //设为0即可
wndclass.cbWndExtra=0; //设为0即可
wndclass.hInstance=hInstance; //当前实例句柄
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//窗口的最小化图标为缺省图标
/**********************
HICON LoadIcon{
HINSTANCE hInstance, //设为NULL,若要设置一个标准的图标则这个值必须附值为NULL
LPCTSTR lpIconName   //图标,可以更改,如IDI-ERROR(图标为一个红色的x)等~
};
**********************/
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW); //窗口采用箭头光标,可以更改,如:IDI_CROSS为十字形光标
/*********************
HCURSOR LoadCusor{
HINSTANCE hINstance,//同样若要设置一个标准的光标则这个值必须为NULL
LPCTSTR lpIconName//光标
};
*********************/
wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH)); //窗口背景为白色,HBRUSH为强制类型转换,可以更改如:BLACK_BRUSH的窗口背景为黑色
/********************
HGDIOBJ GetStockObject{
int fnObject
};
********************/
wndclass.lpszMenuName=NULL; //窗口无菜单
wndclass.lpszClassName=lpszClassName; //窗口类名,可以自己定义lpszclassName的名字,如wndclass.lpszClassName="xuzengqiang";

当我们设置完一个窗口类,我们就需要对这个窗口进行注册,我们可以理解为向操作系统注册,注册方法:需要用到RegisterClass 函数,该函数的模型为:

ATOM RegisterClass(
CONST WNDCLASS *lpWndClass//为窗口类的一个指针
);

对于上例中我们已经定义了一个WNDCLASS wndclass变量,所以注册的方法就是:

RegisterClass(&wndclass);

注册成功后我们得创建一个窗口了,用到CreateWindow函数:

HWND CreateWindow(   
LPCTSTR lpClassName, //注册的类名,这里一定要基于以前注册之后的一个类名去设定  
LPCTSTR lpWindowName,//窗口的名字,   
DWORD dwStyle, //窗口的类型,有很多的风格,如:WS_BORDER:创建一个单边框的窗口;WS_HSCROLL:创建一个有水平滚动条的窗口等~同样这个窗口要具有多种类型可以利用或运算   
int x,  //窗口的水平坐标,窗口的左上角坐标 
int y,  //窗口的垂直坐标, 
int nWidth,//窗口的宽度   
int nHeigh,//窗口的高度   
HWND hWndParent, //指示为副窗口句柄,若只有一个窗口,则赋为NULL  
HMENU hMenu, //菜单句柄,若没有菜单则设为NULL
HANDLE hlnstance, //当前实例的一个句柄  
LPVOID lpParam /*指向一个值的指针,该值传递给窗口WM_CREATE消息.该值通过在IParam参数中的CREATESTRUCT结构传递,如果应用程序调用CreateWindow创建 一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构.用不到设为NULL*/
);

窗口类型(Windows Style):

WS_BORDER 有边框窗口

WS_CAPTION 必须和WS_BORDER风格配合,但不能与WS_DLGFRAME风格一起使用。指示窗口包含标题要部分。

WS_CHILD 说明窗口为子窗口,不能应用于弹出式窗口风格(WS_POPUP)。

WS_CHILDWINDOW 同WS_CHILD。

WS_CLIPCHILDREN 绘制父窗口时,不绘制子窗口的裁剪区域。使用在建立父窗口时。

WS_CLIPSIBLINGS 剪裁相关的子窗口,这意味着,当一个特定的子窗口接收到重绘消息时,WS_CLIPSIBLINGS风格将在子窗口要重画的区域中去掉与其它子窗口重叠的部分。(如果没有指定WS_CLIPSIBLINGS风格,并且子窗口有重叠,当你在一个子窗口的客户区绘图时,它可能会画在相邻的子窗口的客户区中。)只与WS_CHILD风格一起使用。

WS_DISABLED 创建一个初始状态为禁止的窗口。

WS_DLGFRAME 创建一个窗口,具有双重边界,但是没有标题条。

WS_GROUP 指定一组控件中的第一个,用户可以用箭头键在这组控件中移动。在第一个控件后面把WS_GROUP风格设置为FALSE的控件都属于这一组。下一个具有WS_GROUP风格的控件将开始下一组(这意味着一个组在下一组的开始处结束)。

WS_HSCROLL 创建一个具有水平滚动条的窗口。

WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。

WS_MAXIMIZE 创建一个最大化的窗口。

WS_MAXIMIZEBOX 创建一个具有最大化按钮的窗口。

WS_MINIMIZE 创建一个初始状态为最小化的窗口。仅与WS_OVERLAPPED风格一起使用。

WS_MINIMIZEBOX 创建一个具有最小化按钮的窗口。

WS_OVERLAPPED 创建一个重叠窗口。重叠窗口通常具有标题条和边界。

WS_OVERLAPPEDWINDOW 创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX和WS_MAXIMIZEBOX风格的重叠式窗口。

WS_POPUP 创建一个弹出式窗口,不能与WS_CHILD风格一起使用。

WS_POPUPWINDOW 创建一个具有WS_BORDER,WS_POPUP和WS_SYSMENU风格的弹出窗口。为了使控制菜单可见,必须与WS_POPUPWINDOW一起使用WS_CAPTION风格。

WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。

WS_SYSMENU 创建一个在标题条上具有控制菜单的窗口。仅对带标题条的窗口使用。

WS_TABSTOP 指定了一些控件中的一个,用户可以通过TAB键来移过它。TAB键使用户移动到下一个用WS_TABSTOP风格定义的控件。

WS_THICKFRAME 创建一个具有厚边框的窗口,可以通过厚边框来改变窗口大小。

WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。

WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,MS_THICKFRAME风格的窗口。

WS_VISIBLE 创建一个最初可见的窗口。

WS_VSCROLL 创建一个具有垂直滚动条的窗口。

当然我们在创建一个窗口时得先创建一个句柄:

HWND hwnd;
hWnd=CreateWindow("xuzengqiang","许增强",WS_SYSMENU|WS_VISIBLE,CW_USEDEFAULT,CW_USEDEFAULT,400,300,NULL,NULL,0,NULL);

窗口创建完成后我们得将窗口显示出来,用到ShowWindow函数

BOOL ShowWindow(
HWND hWnd,
int nCmdShow//显示的状态,例如:SW_MAXIMIZE:最大化指定的窗口,SW_SHOWMAXIMIZED:激活窗口并将其最大化
);

例如:

ShowWindow(hwnd,SW_SHOWMAXIZED);

显示窗口后我们还得做一个更新窗口的函数:UpdateWindow函数 //其实这个函数可有可无

BOOL UpdateWindow(  
 HWND hWnd // 窗口的句柄   
);

例如:UpdateWindow(hwnd);

消息循环:

MSG msg;
while(GetMessage(&msg,NULL,0,0))  //消息循环
{   TranslateMessage(&msg);       //转化虚拟按键到字符消息,对取到的消息队进行转换,生成字符消息WM_CHAR
DispatchMessage(&msg);        //分派消息调用回调函数,将消息路由给操作系统
}

Getmessage函数

BOOL GetMessage(
LPMSG lpMsg,//指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。
HWND hWnd,//取得其消息的窗口的句柄,这是一个有特殊含义的值(NULL),GetMessage为任何属于调用线程的窗口检索消息,线程消息通过PostThreadMessage寄送给调用线程。
UINT wMsgFilterMin,//指定被检索的最小消息值的整数
UINT wMsgFilterMax //指定被检索的最大消息值的整数
);

MSG结构体:

typedef struct tagMSG {   
HWND hwnd;   
UINT message;   
WPARAM wParam;   
LPARAM lParam;   
DWORD time;   
POINT pt;   
} MSG;

现在主要分析下窗口类中的回调函数(WNDPROC lpfnWndProc;)

LRESULT CALLBACK WndProc( //WndProc名称可自由定义,参数的类型不能更改   
HWND hwnd,   
UINT uMsg,   
WPARAM wParam,   
LPARAM lParam   
);

MessageBox函数:弹出一个窗口,创建、显示、和操作一个消息框。消息框含有应用程序定义的消息和标题,加上预定义图标与Push(下按)按钮的任何组合。

int MessageBox(
HWND hWnd,
LPCTSTR lpText,//指向一个以NULL结尾的、含有将被显示的消息的字符串的指针,即显示在窗口的内容
LPCTSTR lpCaption,//指向一个以NULL结尾的、用于对话框标题的字符串的指针.窗口的标题
UINT UType//指定一个决定对话框的内容和行为的位标志集,例如:MB_OKCANCEL:消息框含有两个按钮:OK和Cancel。它是消息框的一个类型,有很多~例:MB_YES,会出现一个OK的button.
);

下面是一个完整的编译过程,打开VC/新建/Win32 Application/设置位置和工程名字后按确定,新建/c++ source File后敲入代码即可.

#include<windows.h>
#include<stdio.h>

LRESULT CALLBACK WndProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
);

int WINAPI WinMain(
HINSTANCE bInstance,
HINSTANCE bPrevInstance,
LPSTR IpCmdLine,
int nCmdShow
)
{
WNDCLASS wndclass;

char lpszClassName[]="xuzengqiang";
wndclass.style=CS_HREDRAW|CS_VREDRAW;
wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=0;
wndclass.hIcon=LoadIcon(NULL,IDI_ERROR);
wndclass.hCursor=LoadCursor(NULL,IDC_CROSS);
wndclass.hbrBackground=(HBRUSH)(GetStockObject(WHITE_BRUSH));
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=lpszClassName;

RegisterClass(&wndclass);//一定要记得注册一个窗口

HWND hwnd;
hwnd=CreateWindow("xuzengqiang","许增强",WS_SYSMENU|WS_VISIBLE|WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_SIZEBOX,CW_USEDEFAULT,CW_USEDEFAULT,400,200,NULL,NULL,0,NULL);

ShowWindow(hwnd,nCmdShow);//这里的nCmdShow得与WinMain中设置的参数一致
UpdateWindow(hwnd);

MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}

LRESULT CALLBACK WndProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
HDC hdc;//HDC是一个DC句柄,类似于一个指针的类型,DC全称为Device Contexts,设备上下文。
PAINTSTRUCT ps;
switch(message)//下面是针对不同的消息作出响应
{
case WM_CHAR: //用户按下了键盘上的某个键
char szchar[20];
sprintf(szchar,"char is %d",wParam);
MessageBox(hwnd,szchar,"xuzengqiang",0);
break;
case WM_LBUTTONDOWN: //当用户在window客户区域点击鼠标左键的时候发送
MessageBox(hwnd,"mouse click","xuzengqiang",0);//若是只需要一个确定按钮,可以直接设为0-转换为16进制就代表MB_OK
hdc=GetDC(hwnd);//获取DC的句柄
TextOut(hdc,0,20,"许增强",strlen("许增强"));
ReleaseDC(hwnd,hdc);
//释放DC,由于DC是系统内部维护的一个数据结构,也会占内存,所以一定要注意,当我们的到一个DC的时候,如果我们忘了释放DC的话就会造成内存的泄漏
break;
case WM_PAINT://要求一个窗口重绘自己
hdc=BeginPaint(hwnd,&ps);//获取DC的句柄,它会填充一个PAINTSTRUT的结构体
TextOut(hdc,0,0,"许增强",strlen("许增强"));//文本输出函数,往窗口上输出一串文本
/***********************************
BOOL TextOut(
HDC hdc,      // 设备描述表句柄  
     int nXStart,       // 字符串的开始位置 x坐标  
     int nYStart,       // 字符串的开始位置 y坐标   
LPCTSTR lpString,  // 字符串  
int cbString       // 字符串中字符的个数   
);
***********************************/
EndPaint(hwnd,&ps);//释放DC
break;
case WM_CLOSE://当一个程序和应用程序要关闭是发出一个信号
if(IDYES==MessageBox(hwnd,"是否退出程序?","xuzengqiang",MB_YESNO))
//消息框包含两个按钮,YES和NO,Message具有返回值,IDYES是返回值,当点击YES时返回YES,若是点击NO,则返回IDNO
{
DestroyWindow(hwnd);//销毁窗口,它会返回一个WM_DESTORY消息,下面的一个case语句
}
break;
case WM_DESTROY://一个窗口被销毁
PostQuitMessage(0);//通知系统线程请求终止
break;
default://不能删~~~
return DefWindowProc(hwnd,message,wParam,lParam);//返回一个缺省的窗口过程,对不感兴趣的消息提供一个缺省处理
}
return 0;
}

效果图:点击鼠标左键:



关闭时:



当然还有很多东西没有列上来,建议下个MSDN library,里面的东西很全~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: