VC精华讲义最新Word格式文档下载.docx
- 文档编号:22153389
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:95
- 大小:104.74KB
VC精华讲义最新Word格式文档下载.docx
《VC精华讲义最新Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《VC精华讲义最新Word格式文档下载.docx(95页珍藏版)》请在冰豆网上搜索。
可见菜单本身不是一个窗口,同图标、光标一样,是窗口的一个元素。
不少的人和书都错以为菜单也是一个窗口,其实我们用Spy++实用工具的FindWindow功能就能够区分出桌面上的哪些元素为窗口,哪些不是。
lpszMenuName是LPCTSTR类型,需用MAKEINTRESOURCE这个宏把资源ID标识符转换为lpszMenuName需要的LPCTSTR类型。
lpszClassName成员指定了这一类型窗口的名称,是字符串变量。
与设计一辆新型汽车后,要为该汽车型号指定名称一样,设计了一种新型窗口后,也要为这种新型窗口起个名称。
我们先将这里的名称指定成"
http:
//www.it315.org"
,等会我们将看到如何使用这个名称。
设计完WNDCLASS后,需调用RegisterClass函数对其进行注册,以后便可以用CreateWindow函数产生这种类型的窗口窗口了。
CreateWindow函数的定义如下:
HWNDCreateWindow(
LPCTSTRlpClassName,//pointertoregisteredclassname
LPCTSTRlpWindowName,//pointertowindowname
DWORDdwStyle,//windowstyle
intx,//horizontalpositionofwindow
inty,//verticalpositionofwindow
intnWidth,//windowwidth
intnHeight,//windowheight
HWNDhWndParent,//handletoparentorownerwindow
HMENUhMenu,//handletomenuorchild-windowidentifier
HANDLEhInstance,//handletoapplicationinstance
LPVOIDlpParam//pointertowindow-creationdata
);
参数lpClassName即我们刚才在WNDCLASS的lpszClassName成员指定的名称,在这里应该为"
,表示要产生"
这一类型的窗口。
产生窗口的过程是由操作系统完成的,如果在调用CreateWindow函数之前,还没有用RegisterClass函数注册过名称为"
的窗口类型,操作系统无法得知这种窗口类型的配置信息,窗口产生过程失败。
参数lpWindowName指定产生的窗口实例上显示的标题文字。
参数dwStyle指定产生的窗口实例的样式,就象同一型号的汽车可以有不同的颜色一样,同一型号的窗口也可以有不同的外观样式。
要注意区别WNDCLASS中的style成员与参数dwStyle,前者是针对一个大类,后者是针对个别。
参数x,y,nWidth,nHeight指定了窗口左上角的x,y坐标,窗口的宽度,高度。
如果x被设置成CW_USEDEFAULT,系统将窗口的左上角设置为确省值,参数y将被忽略。
如果nWidth被设置成CW_USEDEFAULT,系统将窗口的大小设置为确省值,参数nHeight将被忽略。
参数lpWindowName指定了窗口的父窗口句柄。
窗口之间可以组合成父子关系,子窗口必须具有WS_CHILD样式,当父窗口被破坏,隐藏,移动,显示时,也会破坏,隐藏,移动,显示子窗口。
当lpWindowName为NULL时,桌面就成为当前窗口的父窗口。
参数lpWindowName指定了窗口的菜单或子窗口句柄。
参数hInstance指定了窗口所属的应用程序的句柄。
参数lpParam可以为窗口附加补充信息。
如果窗口创建成功,函数将返回系统为该窗口分配的句柄,否则,返回NULL。
6.消息循环
通常的消息循环代码如下:
MSGmsg;
while(GetMessage(&
msg,NULL,0,0))
{
TranslateMessage(&
msg);
DispatchMessage(&
}
GetMessage函数从应用程序消息队列中取走一条消息,该函数的原型如下:
BOOLGetMessage(
LPMSGlpMsg,//addressofstructurewithmessage
HWNDhWnd,//handleofwindow
UINTwMsgFilterMin,//firstmessage
UINTwMsgFilterMax//lastmessage
参数lpMsg是接受消息的变量的指针。
参数hWnd指定了接收属于哪个窗口的消息。
参数wMsgFilterMin,wMsgFilterMax指定了接受某一范围内的消息。
如果队列中没有满足条件的消息,该函数将一直等待,不会返回。
除了WM_QUIT消息外,该函数返回非零值,对WM_QUIT消息,该函数返回零。
也就是说,只有收到WM_QUIT消息,上述代码才能退出while循环,程序才有可能结束运行。
TranslateMessage函数对取道的消息进行转换。
用户按动一下某个键,系统将发出WM_KEYDOWN,WM_KEYUP,并且参数中提供的是该键的虚拟扫描码。
但有时用户按动一下某个键,我们想得到一条表示用户输入了某个字符的消息,并在消息补充参数中提供字符的编码。
TranslateMessage能将可行的WM_KEYDOWN,WM_KEYUP消息对转换成一条WM_CHAR消息,将可行的WM_SYSKEYDOWN,orWM_SYSKEYUP消息对转换成一条WM_SYSCHAR消息,并将转换后得到的新消息投递到程序的消息队列中。
转换过程不会影响原来的消息,只在消息队列中增加新消息。
DispatchMessage函数将取道的消息传递到窗口的回调函数中去处理。
可以理解成该函数通知操作系统,让操作系统去调用窗口的回调函数来处理收到的消息。
所有Windows程序的消息处理代码基本上都是相同的,如没特殊需要,可以照搬照抄上述代码。
从队列中取消息还有PeekMessage函数,PeekMessage函数有两种取消息的方式,第一种与GetMessage一样,从队列中直接取走消息,第二种是只取消息的一个副本,并不将消息从队列中取走。
无论哪种方式,PeekMessage都不会因队列中没有满足条件的消息而阻塞,当取到满足条件的消息,该函数返回非零值反之,返回零。
向队列中发送消息有PostMessage和SendMessage,PostMessage函数发送消息后立即返回,而SendMessage需等到发送的消息被处理完后才能返回。
还有一个PostThreadMessage用于向线程发送消息,关于线程,请在以后的章节再学,但我们也因此想到消息不一定总是与窗口相关的,也就是说,对于某些消息,其对应的MSG结构中的hwnd可以为NULL。
7.回调函数
回调函数的原型为:
LRESULTCALLBACKWindowProc(
HWNDhwnd,//handletowindow
UINTuMsg,//messageidentifier
WPARAMwParam,//firstmessageparameter
LPARAMlParam//secondmessageparameter
我们可以将函数名WindowProc改为我们喜欢的名称,如DefWndProc,该函数的四个参数对应消息的窗口句柄,消息码,消息码的两个补充参数。
在该函数内部是一个庞大的switch语句,用于对各种感兴趣的消息进行处理。
我们分析程序中的代码。
LRESULTCALLBACKDefWndProc(HWNDhWnd,UINTMsg,WPARAMwParam,LPARAMlParam)
{
HDChDC;
switch(Msg)
caseWM_CHAR:
charstr[20];
sprintf(str,"
thecharcodeis%d"
wParam);
MessageBox(hWnd,str,"
www.it315.org"
MB_OKCANCEL);
break;
caseWM_LBUTTONDOWN:
MessageBox(hWnd,"
mouseclick"
"
MB_OK);
hDC=GetDC(hWnd);
TextOut(hDC,LOWORD(lParam),HIWORD(lParam),
"
strlen("
));
ReleaseDC(hWnd,hDC);
caseWM_CLOSE:
if(IDOK==MessageBox(NULL,"
真的要要退出吗?
"
"
MB_OKCANCEL|MB_ICONQUESTION))
{
DestroyWindow(hWnd);
}
caseWM_PAINT:
PAINTSTRUCTps;
hDC=BeginPaint(hWnd,&
ps);
//在WM_PAINT里必须用这个函数
TextOut(hDC,0,0,"
EndPaint(hWnd,&
caseWM_DESTROY:
PostQuitMessage(0);
default:
return(DefWindowProc(hWnd,Msg,wParam,lParam));
return(0);
}
当用户在窗口上按下一个字符键,程序将得到一条WM_CHAR消息,参看msdn,在其wParam参数中含有字符的码值。
使用程序中的代码,我们可以随时获得某个字符的码值,不用为此去专门查找书籍。
MessageBox函数可以弹出一个显示信息的对话框,如果我们按下BackSpace键,在这里将弹出"
thecharcodeis8"
消息。
当用户在窗口上按下鼠标左按钮时,程序弹出一条消息框对收到的WM_LBUTTONDOWN进行响应,以证明按下鼠标左按钮动作与WM_LBUTTONDOWN消息的这种对应关系,另外程序还将在窗口上鼠标所按下的位置写上一串文字。
当我们要在窗口上写字、绘图,并不直接在这些设备上操作,而是在一个称为设备描述表(DeviceContexts,简称DC)的资源上操作的。
使用DC,程序不用为图形的显示与打印输出分别单独处理了。
无论是打印还是显示,我们都是在DC上操作,然后由DC映射到这些设备上。
使用DC,我们不用担心程序在不同的硬件上执行的差异性,DC能够为我们装载合适的设备驱动程序,实现程序的图形操作与底层设备无关。
GetDC函数能够返回同窗口相关连的DC的句柄。
TextOut函数在当前DC上指定的位置输出一个字符串,当按下鼠标左按钮,消息WM_LBUTTONDOWN的补充参数lParam中含有鼠标位置的x,y坐标,其中的低16位含有x坐标,高16位含有y坐标,可以分别通过LOWORD,HIWORD宏获得。
对于每次成功调用GetDC返回的DC句柄,在执行完所有的图形操作后,必须调用ReleaseDC释放该句柄所占用的资源。
否则,会造成内存泄露。
我曾经帮助一个叫王健的学员调试他的On-job项目程序,他发现他的程序所占用的内存总是以4k的增量向上增长,每运行几小时后,程序便因内存不足而崩溃了。
后来发现就是因为程序在定时器中反复使用GetDC而没有使用ReleaseDC释放造成的。
读者可以将例子程序中的ReleaseDC一句注释掉,编译后运行,在NT4.0/win2000下启动任务管理器,切换到进程标签,查看你的程序所使用的内存量,在程序中不断点击鼠标左按钮,程序将不断调用GetDC函数,你将发现你的程序占用的内存量不断向上增长,我们通常使用这样的方式来检测程序的内存泄露的。
当用户点击窗口上的关闭按钮时,系统将给应用程序发送一条WM_CLOSE消息,如果程序不做进一步处理,窗口是不会关闭的。
我们在程序中利用一个选择对话框,如果用户确认真的要退出,程序调用DestroyWindow函数将窗口关闭。
窗口关闭后,系统将给应用程序发送一条WM_DESTROY消息,需要注意的是,主窗口的关闭,不代表应用程序结束,在WinMain函数中的消息循环代码中,GetMessage函数必须取到一条WM_QUIT,消息循环才能结束。
要让程序正常退出,必须在WM_DESTROY消息响应代码中,调用PostQuitMessage函数向程序的消息队列中发送一条WM_QUIT消息,PostQuitMessage函数的参数值传递给WM_QUIT消息的wParam参数,通常用作WinMain函数的返回值。
当窗口第一次产生,移动,改变大小,从其他窗口后面切换到前面等情况都会导致窗口的重画。
重画时将使用设计窗口类时指定的刷子粉刷窗口的背景,窗口上原有的文字和图形都将被擦除掉。
要想让图形和文字总显示在窗口的表面,只能是在这些图形和文字被擦除后,立即又将它们画上去。
这个过程对用户来说,是感觉不到的,他们只能感觉到这些图形和文字永远都和窗口一并存在。
当系统粉刷完窗口的背景后,都会发送一条WM_PAINT消息,以便通知应用程序原有的图形和文字已被擦除,如果还想保留哪些图形和文字,请在此处加入处理代码。
也就是说,我们在WM_PAINT消息响应中作出的图形和文字是“永远”存在的。
对于WM_PAINT消息响应代码中要获得窗口的DC,只能使用BeginPaint函数,除此之外的消息响应代码中必须用GetDC获得窗口的DC,BeginPaint获得的DC最后必须用EndPaint释放。
提醒:
水平或垂直改变窗口的大小时,窗口是否重画,取决于WNDCLASS结构中style成员的设置中是否包含CS_VREDRAW与CS_HREDRAW。
DefWindowProc函数提供了对所有消息的缺省处理方式,对于大多数不想特殊处理的消息,程序都可以调用这个函数来处理,所以程序在switch的default语句中调用此函数进行处理。
8.程序编写操作步骤与实验。
1)首先启动VC++,在菜单中选择File->
New,在弹出的窗体中选择Projects标签,然后在左侧选择WindowsApplication,在右侧的Projectname:
文本框中为新建的工程起一个名字,VC++会为新建的工程在硬盘上建一个与工程同名的文件夹,这个文件夹放在Location:
指定的路径下,你可以点击Location旁边的"
..."
按钮来改变路径。
接下来一定要选择Createnewworkspace单选按钮,并勾选Platforms:
中的Win32复选框。
完成后的界面如图1-1所示:
2)这一课对第一次接触Windows编程的读者来说,新的东西太多。
但只要你把这些知识基本理解和掌握,学好VC++的日子离你就不太遥远了。
惟有如此,你才可能精通VC++编程。
第二课:
C++经典知识回顾
一、类的定义与应用
在C语言中,我们学过结构体,用于将描述某一对象的若干变量包装成一个整体使用,但没有但没有将与该对象相关的函数包含进来。
C语言中的结构体只能描述一个对象的特征(属性),不能描述一个对象的动作(方法)。
在C++中,我们是通过类的定义来解决这个问题的,在类的定义中,不仅可以包含变量,还可以包含函数。
我们通过一段程序来讲解类的使用。
#include"
iostream.h"
classCPoint
public:
intx1;
inty1;
voidOutput();
CPoint();
CPoint(intx2,inty2)
~CPoint();
private:
intx2;
inty2;
int*pCount;
};
//注意类和结构定义完后,一定要用"
;
号结尾,忘记"
是许多人常犯的错误。
//在c++中,//......用于注释一行,/*......*/可以注释多行。
voidCPoint:
:
Output()
if(pCount)
(*pCount)++;
else
pCount=newint;
*pCount=1;
cout<
<
thefirstpointis("
x1<
'
'
y1<
)'
endl;
thesecondpointis("
x2<
y2<
CPoint:
CPoint()
pCount=0;
thefirstconstructoriscalling"
CPoint(intx2,inty2)
this->
x2=x2;
y2=y2;
thesecondconstructoriscalling"
~CPoint()
cout<
你调用了Output成员函数共"
*pCount<
次"
deletepCount;
你还没有调用过Output成员函数"
thedeconstructoriscalling"
voidOutput(CPointpt)
pt.x1<
pt.y1<
//cout<
pt.x2<
pt.y2<
//上面被注释的语句会造成编译错误,因为不能从类的外部访问类中的私有成员。
voidmain()
if(1==1)//限定pt变量的有效范围
CPiontpt;
请输入两个整数"
cin>
>
pt.x1>
pt.y1;
//pt.x2=10;
//pt.y2=10;
pt.Output();
//故意演示Output被调用多次的情况。
Output(pt);
CPointpt(10,10);
pt.Output();
上面的代码定义了一个类CPoint,其中包含有变量,称之为成员变量,也包含有函数的声明,称之为成员函数。
在类定义之外,我们必须对成员函数进行实现,成员函数的实现格式为:
返回类型 类名:
函数名(参数列表)
函数体代码
上面的代码也编写了一个名为Output的全局函数,注意与类CPoint中的Output成员函数区别。
上面的代码还编写了
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- VC 精华 讲义 最新