MFC基础知识

在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,里面的东西很全~~ 

你可能感兴趣的:(数据结构,null,mfc,callback,border,winapi)