版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章
Windows应用程序对键盘与鼠标的响应
扫描码是依赖于具体设备的,为达到设备无关性的要求,往往使用与具体设备无关的虚拟码,虚拟码是由Windows系统定义的与设备无关的键的标识由于键盘的输入产生一条消息扫描码、虚拟码以及其他与击键有关的消息设备驱动程序截取键的扫描码翻译虚拟码它含键盘上的键对应一个唯一的标识值(扫描码)按下或释放某键时产生取出键盘消息进行处理消息设备驱动程序把消息放到系统的消息队列中Windows从系统消息队列中取出消息发送到相应的线程消息队列中窗口过程4.1键盘在应用程序中的应用
虚拟码是一种与设备无关的键盘编码,用以标识哪一个键被按下或释放,最常用的虚拟码已经在winuser.h中定义(“C:\ProgramFiles(x86)\WindowsKits\10\Include\10.0.19041.0\um\WinUser.h”),(Win11系统)符号常量名称等价的键盘键符号常量名称等价的键盘键VK_RETURN回车键VK_BACK退格键VK_SHIFTShift键VK_CONTROLCtrl键VK_MENUAlt键VK_PAUSEPause键VK_CAPITALCapsLock键VK_ESCAPEEsc键VK_PRIORPageUp键VK_NEXTPageDown键VK_ENDEnd键VK_HOMEHome键VK_LEFT左箭头键VK_RIGHT右箭头键VK_UP上箭头键VK_DOWN下箭头键VK_0~VK_9字符0~9键VK_A~VK_Z字符A~Z键VK_INSERTInsert键VK_DELETEDelete键VK_TAB制表键VK_SPACESPACE条VK_ADD+键VK_SUBTRACT-键VK_DECIMAL*键VK_DIVIDE/键操作系统在接收到键盘输入后把消息发送给具有“输入焦点(inputfocus)的窗口应用程序一般有几个窗口,但当按下某一个键时,只有一个窗口能接收到该键盘消息,接收这个键盘消息的窗口称为有“输入焦点”的窗口有“输入焦点”的窗口应是活动窗口或者活动窗口的子窗口窗口正在接收输入焦点
窗口函数通过捕获WM_SETFOCUS和WM_KILLFOCUS消息确定当前窗口是否具有输入焦点。窗口失去输入焦点键盘消息按键消息字符消息按下或松开一个键时就产生了一按键消息一个按键的组合产生了一个可以显示的字符时,就产生了一个字符消息系统按键消息非系统按键消息Alt键与相关输入键的组合产生的消息,这些键一般由Windows系统内部直接处理,应用程序不处理不使用Alt键组合的按键消息按键消息的两个变量wParamlParam32位的变量包含了识别按下的键的虚键码只有当键盘驱动程序把键盘字符映射成ASCII码后才能产生WM_CHAR这个字符消息字符消息系统非系统WM_KEYDOWN和WM_KEYUP的按键消息只能产生非系统消息WM_SYSKEYDOWN和WM_SYSKEYUP按键消息只能产生系统消息在某些非U.S.英语键盘上,有些键用於给字母加上音调。因为它们本身不产生字元,所以称之为「死键」。例如,使用德语键盘时,对於U.S.键盘上的+/=键,德语键盘的对应位置就是一个死键,未按下Shift键时它用於标识锐音,按下Shift键时则用於标识抑音。当使用者按下这个死键时,系统接收到wParam等於音调本身的ASCII或者Unicode代码的WM_DEADCHAR消息。当使用者再按下可以带有此音调的字母键(例如A键)时,系统会接收到WM_CHAR消息,其中wParam等於带有音调的字母「a」的ANSI代码。因此,用户不需要处理WM_DEADCHAR讯息,原因是WM_CHAR讯息已含有程序所需要的所有消息。Tip:关于死字符/en-us/library/windows/desktop/ms646277(v=vs.85).aspxWM_DEADCHAR
specifiesacharactercodegeneratedbyadeadkey.Adeadkeyisakeythatgeneratesacharacter,suchastheumlaut(double-dot),thatiscombinedwithanothercharactertoformacompositecharacter.Forexample,theumlaut-Ocharacter(Ö)isgeneratedbytypingthedeadkeyfortheumlautcharacter,andthentypingtheOkey.【4-1】设计一个窗口,在该窗口中练习键盘的响应,要求如下:(1)单击键盘上的向上箭头时,窗口中显示“Youhadpressedtheupkey”;(2)单击<Shift>键时,窗口中显示“YouhadpressedtheSHIFTkey”;(3)单击<Ctrl>键时,窗口中显示“YouhadpressedtheCTRLkey”;(4)单击<Ctrl+A>键时,窗口中显示“YouhadpressedtheCTRLAkey”;(5)单击<Shift+B>键时,窗口中显示“YouhadpressedtheSHIFTBkey”。对于这个问题,难点在于如何区分“单击Ctrl键”和“单击Ctrl+A键”以及“单击Shift键”和“单击Shift+B”键。nUpKeyDown:上箭头键是否按下nCtrlKeyDown:Ctrl键是否按下nCtrlAKeyDown:Ctrl+A键是否按下nShiftKeyDown:Shift键是否按下nShiftBKeyDown:Shift+B键是否按下
对于这个问题,难点在于如何区分“单击Ctrl键”和“单击Ctrl+A键”以及“单击Shift键”和“单击Shift+B”键。为此定义了变量:nUpKeyDown来标志上箭头键是否按下CtrlKeyDown变量来标志Ctrl键是否按下nCtrlAKeyDown来标志Ctrl+A键是否按下nShiftKeyDown来标志Shift键是否按下nShiftBKeyDown来标志Shift+B键是否按下由于我们这里执行的是按下键的操作,系统提供了按下键的消息响应方法,就是在类向导中响应WM_KEYDOWN消息,此时系统生成了如下一个函数:
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)nFlags是各位代表的意义如下:第0-7位:扫描码第8位:扩展键,比如说功能键(F1-12),或者数字区的键第9-10位:没有使用第11-12位:供Windows内部使用第13位:状态描述码(如果键按下时ATL键也是按下的,那么值为1,否则为0)第14位:前一个键的状态(如果是按下的,值为1,否则为0)第15位:变换状态(如果键是正在被按下,值为1,如果是正在放开,值为0)虚拟键码键被重击的次数16位的UINT型数据那么本例要判断nChar的值:当为向上箭头键的虚拟码时,nUpKeyDown为真;当为Ctrl键的虚拟码时,nCtrlKeyDown为真;当为Shift键时,nShiftKeyDown的值为真。
但此时还不能简单的输出结果,因为此时还不知是否按下了A或者B键。由于当我们按下A和B键时,系统会产生WM_CHAR消息,此时系统生成了如下字符响应函数:
OnChar(UINT
nChar,UINT
nRepCnt,UINT
nFlags)
OnChar函数的三个参数与前面的介绍的OnKeyDown函数的三个参数含义一样。由于“Ctrl+a”是组合键,WM_CHAR传入的nChar并不是a的键码,也不是a和Ctrl的与运算,而是1,若是其他键比如shift+a的话nChar传入的就是a的键码,所以ctrl+a应该是一个系统组合键,所以,这里对Ctrl+A的判断用的是“nChar==1”对于Shift+B的操作,则判断nChar,当是98和66时,表明B/b键按下,此时设置nShiftBKeyDown的值为“真”,同时将nShiftKeyDown的值设为“假”。同理处理nCtrlAKeyDown和nCtrlKeyDown的值。if(nChar==1){if(nCtrlKeyDown==TRUE){nCtrlAKeyDown=TRUE;nCtrlKeyDown=FALSE;}}else
if(nChar==98||nChar==66) //当按下b键时{if(nShiftKeyDown==TRUE) //检查shift键是否处于按下状态 {nShiftBKeyDown=TRUE; //当SHIFT键按下时,变量置为真 nShiftKeyDown=FALSE; }}抬起键时,系统发送WM_KEYUP消息,消息处理程序中调用Invalidate();产生WM_PAINT消息,调用OnPaint函数。1:创建基于对话框的工程文件4_1,并添加如下类的成员变量:
CDC*hDC; //定义设备环境句柄2:定义一系列BOOL型变量,用来表示相关键的状态,并定义一系列操作的响应信息字符串:BOOLnUpKeyDown=FALSE;BOOLnShiftKeyDown=FALSE;BOOLnCtrlKeyDown=FALSE;BOOLnCtrlAKeyDown=FALSE;BOOLnShiftBKeyDown=FALSE;LPCWSTRcUp=L"YouhadpressedtheUPkey";LPCWSTRcCtrl=L"YouhadpressedtheCtrlkey";LPCWSTRcShift=L"YouhadpressedtheSHIFTkey";LPCWSTRcCtrl_A=L"YouhadpressedtheCTRLAkey";LPCWSTRcShift_B=L"YouhadpressedtheSHIFTBkey";3:通过“类向导”,响应WM_KeyDown按键消息,并添加如下代码:voidCMy41Dlg::OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags){switch(nChar){caseVK_UP: //当按上箭头键时,变量置为真 nUpKeyDown=TRUE; break;caseVK_SHIFT: //当按shift键时,变量置为真 nShiftKeyDown=TRUE; nShiftBKeyDown=FALSE; break;caseVK_CONTROL: //当按control键时,变量置为真 nCtrlKeyDown=TRUE; nCtrlAKeyDown=FALSE; break;default: break;}CDialogEx::OnKeyDown(nChar,nRepCnt,nFlags);}4:通过“类向导”响应WM_KeyUp消息处理函数,并添加如下的代码:voidCMy41Dlg::OnKeyUp(UINTnChar,UINTnRepCnt,UINTnFlags){ Invalidate();//发送刷新请求,由OnPaint函数进行响应 CDialogEx::OnKeyUp(nChar,nRepCnt,nFlags);}5:通过“类向导”响应WM_CHAR消息,并添加如下斜体代码:voidCMy41Dlg::OnChar(UINTnChar,UINTnRepCnt,UINTnFlags){if(nChar==1) {if(nCtrlKeyDown==TRUE)//如果按下Ctrl键进 {nCtrlAKeyDown=TRUE; nCtrlKeyDown=FALSE; } }elseif(nChar==98||nChar==66) //当按下b键时 {if(nShiftKeyDown==TRUE) //检查shift键是否按下 {nShiftBKeyDown=TRUE;//当SHIFT键按下时,变量置为真 nShiftKeyDown=FALSE; }}CDialogEx::OnChar(nChar,nRepCnt,nFlags);}6:通过“类向导”,添加虚函数PreTranslateMessage,并添加如下斜体部分的代码:BOOLCMy41Dlg::PreTranslateMessage(MSG*pMsg){ SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam); returnCDialogEx::PreTranslateMessage(pMsg);}7:编写刷新函数OnPaint,并添加如下斜体加粗部分的代码:voidCMy41Dlg::OnPaint(){CPaintDCdc(this); //用于绘制的设备上下文hDC=GetDC();hDC->SetTextColor(RGB(255,0,0)); //设置字体颜色为红色//输出信息。if(nUpKeyDown==TRUE){hDC->Rectangle(0,0,300,200);//设置一个矩形区域用来输出文字hDC->TextOut(20,0,cUp,(int)wcslen(cUp));//输出文字nUpKeyDown=FALSE;}elseif(nCtrlAKeyDown==TRUE){hDC->Rectangle(0,0,300,200);hDC->TextOut(20,100,cCtrl_A,(int)wcslen(cCtrl_A));nCtrlAKeyDown=FALSE;nCtrlKeyDown=FALSE;}elseif((nCtrlKeyDown==TRUE)&&(nCtrlAKeyDown==FALSE)){hDC->Rectangle(0,0,300,200);hDC->TextOut(20,60,cCtrl,(int)wcslen(cCtrl));nCtrlKeyDown=FALSE;}elseif(nShiftBKeyDown==TRUE){hDC->Rectangle(0,0,300,200);hDC->TextOut(20,0,cShift_B,(int)wcslen(cShift_B));nShiftBKeyDown=FALSE;nShiftKeyDown=FALSE;}elseif((nShiftKeyDown==TRUE)&&(nShiftBKeyDown==FALSE)){hDC->Rectangle(0,0,300,200);hDC->TextOut(20,0,cShift,(int)wcslen(cShift));nShiftKeyDown=FALSE;}else;ReleaseDC(hDC);}用户窗口区输入“这是一个有关键盘操作的示例程序”的字符串程序中缓冲区大小只设30个字符,当缓冲区满时若再输入任何字符,就出现(1)号错误提示用户按下左箭头键直至光标到达本行起始位置时,就无法再往左移动,则出现(2)号错误信息若此时您按下Esc键,就出现(3)号错误提示信息若当前光标位置处于本行的起始位置,此时按下回退键(BackSpace),则出现编号为(4)的错误提示信息若字符缓冲区中已没有任何字符,此时按下了Delete键,则出现(5)号错误提示信息【例4-2】:本例演示键盘输入时所产生的消息序列并在窗口的客户区显示对应的字符1:创建基于对话框的应用程序4_2,并添加类成员变量: CDC*hDC; //定义DC TEXTMETRICtm; //定义文字结构的变量tm2:在cpp文件中添加如下变量及宏定义:#defineBufSize10 //设置存放字符的缓冲区大小
WCHARcCharBuf[BufSize];//字符数组,存放输入的字符,字符个数不能超出缓冲区大小intnNumChar=0; //现有字符个数intnArrayPos=0; //字符的位置intnLnHeight; //字符高度intnCharWidth; //字符宽度3:在初始化函数中获取字体信息并建立定时器: hDC=GetDC(); //获取当前DC hDC->GetTextMetrics(&tm); //获取字体信息 nLnHeight=tm.tmHeight+tm.tmExternalLeading; //获取字体高度 nCharWidth=tm.tmAveCharWidth; //获取字体宽度 SetTimer(1,500,NULL); //设置定时器 ReleaseDC(hDC);4:通过类向导,响应WM_CHAR这个字符消息,添加如下代码:voidCMy42Dlg::OnChar(UINTnChar,UINTnRepCnt,UINTnFlags){if(nChar==VK_BACK) //按回退键时的消息处理{if(nArrayPos==0)//若已在一行文字开始处,提示用户"不能回退"MessageBox(L"当前位置是文本的起始位置,不能回退",NULL,MB_OK);else{nArrayPos=nArrayPos-1;//每按一次回退键就回退一个字符位置nNumChar=nNumChar-1; //对现有字符总数进行计数for(inti=nArrayPos;i<nNumChar;i++) cCharBuf[i]=cCharBuf[i+1];//由于按回退键,回退位置的后续字符依次前移 Invalidate();}return;}else
if(nChar==VK_LEFT)//处理按下左方向键时的消息{if(nArrayPos>0)nArrayPos=nArrayPos-1;
//当前输入位置往前移一个位置,再输入字符时,等于插入字符else
//已经移到起始输入位置,不能再往前了MessageBox(L"您已经移动到起始位置,不能再往左移动了",NULL,MB_OK);return;}else
if(nChar==VK_RIGHT)//处理按下右方向键时的消息{if(nArrayPos<nNumChar)//如果当前位置没有到缓冲区的最后位置,还能向右移动 nArrayPos=nArrayPos+1;else
MessageBox(L"已经到缓冲区的末尾,不能再向右移动了",NULL,MB_OK);return;}CDialogEx::OnKeyDown(nChar,nRepCnt,nFlags);}if(nNumChar>=BufSize)//若写入的字符数超过缓冲区大小,则报警{MessageBox(L"缓冲区已满,不能再输入字符了\n若需要删除字符,请用BackSpace键",NULL,MB_OK);return;}for(intx=nNumChar;x>nArrayPos;x=x-1) cCharBuf[x]=cCharBuf[x-1];cCharBuf[nArrayPos]=(wchar_t)nChar;nArrayPos=nArrayPos+1;nNumChar=nNumChar+1;Invalidate();CDialogEx::OnChar(nChar,nRepCnt,nFlags);}5:通过类向导,响应按下键的WM_KEYDOWN消息,添加如下代码:voidCMy42Dlg::OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags){if(nChar==VK_END) //处理按下键为End时的消息{nArrayPos=nNumChar; //输入位置从本行的末尾开始return;}elseif(nChar==VK_ESCAPE) //处理按下Escape键消息{MessageBox(L"您现在不能按ESC键,请继续其它操作",NULL,MB_OK);return;}elseif(nChar==VK_HOME) //处理按下键为Home时的消息{nArrayPos=0; //输入位置为本行的起始位置return;}
elseif(nChar==VK_DELETE) //对Del键的操作{if(nArrayPos==nNumChar) //若输入位置处于本行的末尾MessageBox(L"缓冲区已空,没有字符可供删除",NULL,MB_OK);else{for(intx=nArrayPos;x<nNumChar;x=x+1) cCharBuf[x]=cCharBuf[x+1]; //每删除一个字符,缓冲区中总字符数减1 nNumChar=nNumChar-1; Invalidate(); //用户区刷新}return;}elseif(nChar==VK_LEFT) //处理按下左方向键时的消息{if(nArrayPos>0)nArrayPos=nArrayPos-1;//当前输入位置前移一个位置,再输入字符时,等于插入字符else //已经移到起始输入位置,不能再往前了
MessageBox(L"您已经移动到起始位置,不能再往左移动了",NULL,MB_OK);return;}elseif(nChar==VK_RIGHT) //处理按下右方向键时的消息{if(nArrayPos<nNumChar) //若当前位置没有到缓冲区的最后位置,还能向右移动nArrayPos=nArrayPos+1;else
MessageBox(L"已经到缓冲区的末尾,不能再向右移动了",NULL,MB_OK);return;}CDialogEx::OnKeyDown(nChar,nRepCnt,nFlags);}7:响应字符消息的预处理,添加如下的代码:BOOLCMy42Dlg::PreTranslateMessage(MSG*pMsg){ SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam); if(pMsg->message==WM_KEYDOWN&&pMsg->wParam==VK_ESCAPE)//添加这一段代码,使得按下Esc健时不会关闭窗口 { returnTRUE; } returnCDialogEx::PreTranslateMessage(pMsg);}
8:定时器消息处理函数,添加如下斜体加粗部分的代码:voidCMy42Dlg::OnTimer(UINT_PTRnIDEvent){ Invalidate(); CDialogEx::OnTimer(nIDEvent);}9:刷新函数,添加如下斜体加粗部分的代码voidCMy42Dlg::OnPaint(){CPaintDCdc(this); //用于绘制的设备上下文hDC=GetDC();hDC->TextOut(nCharWidth,nLnHeight,cCharBuf,nNumChar);//输出缓冲区中的文本ReleaseDC(hDC);}4.3鼠标在应用程序中的应用鼠标作为定位输入设备,通过鼠标单击、双击和拖动功能,用户可以很容易地操作基于Windows图形界面的应用程序。Windows中通过光标来指示当前鼠标的位置,在Windows操作系统中预定义了几种光标,并在afxwin.h头文件中加以定义,代表预定义光标的常量光标属性描述IDC_APPSTARTING标准箭头和小沙漏IDC_ARROW箭头光标IDC_CROSS十字光标IDC_HAND手形光标IDC_HELP箭头加问号IDC_IBEAMI形文本光标IDC_NO按下鼠标左键后,光标变成圆圈中带一斜线IDC_SIZEALL带东西南北箭头的十字光标IDC_SIZENESW带有指向东北方和西南方箭头的光标IDC_SIZENS带有上下箭头的光标IDC_SIZENWSE带有指向西北方和东南方箭头的光标ISC_SIZEWE带有左右箭头的光标IDC_UPARROW垂直向上箭头光标IDC_WAIT等待光标可调用LoadCursor函数改变光标形式,如加载等待光标LoadCursor(NULL,IDC_WAIT);用户自定义光标自定义光标保存在扩展名为.cur的文件中
光标名CURSOR光标文件(.cur)采用自定义光标时,需在资源文件中定义光标资源加载光标资源(常在定义窗口类时进行)
LoadCursor(NULL,lpszCursorname)当前光标鼠标消息lParam包含了鼠标位置低位包含鼠标位置的x坐标值高位包含鼠标位置的y坐标wParam包含了指示各种虚键状态的值相当于窗口的左上角为原点的坐标值在鼠标消息中,可以定义一个点的结构参数:POINTpt;可通过GetCursorPos(&pt);来获取当前光标的位置消息含义WM_LBUTTONDOWN用户区内单击鼠标左键WM_LBUTTONUP用户区内松开鼠标左键WM_LBUTTONDBLCLK用户区内双击鼠标左键WM_MBUTTONDOWN用户区内单击鼠标中键WM_MBUTTONUP用户区内松开鼠标中键WM_MBUTTONDBLCLK用户区内双击鼠标中键WM_RBUTTONDOWN用户区内单击鼠标右键WM_RBUTTONUP用户区内松开鼠标右键WM_RBUTTONDBLCLK用户区内双击鼠标右键WM_MOUSEMOVE鼠标在用户区内移动WM_MOUSEWHEEL鼠标滚轮转动WM_MOUSEACTIVATE鼠标指针在非激活窗口的时候按下了鼠标按钮WM_MOUSEHOVER鼠标的光标在窗口的客户区盘旋时发出的消息用户区鼠标消息对于鼠标消息的处理要对Shift和Ctrl键进行监测监测是否同时按下Ctrl键和Shift键:if(nFlags&MK_CONTROL)&&(nFlags&MK_SHIFT))
… //Shift和Ctrl键都被按下
不监测在按下鼠标左键的时候,系统会创建一个单击鼠标左键的消息响应函数,具体如下:OnLButtonDown(UINTnFlags,CPointpoint)Windows系统默认的时间间隔为0.5秒,也可以调用SetDoubleClickTime()重新设定间隔值若窗口不包含上述属性的定义,即使进行了双击操作,该窗口也只能接收到两条WM_BUTTONDOWN消息或两条WM_BUTTONUP消息。鼠标双击wndclass.style=CS_HEADRAW|CS_VERDRAW|CS_DBLCLKS;要使窗口函数能接收鼠标双击产生的消息在注册窗口类时必须具有CS_DBLCLKS属性
由于鼠标移动的随机性,如果要使某一个窗口能不间断地捕获鼠标消息,就必须对鼠标加以捕获调用SetCapture()函数一旦从窗口捕获了鼠标,系统的键盘功能就暂时失效,其它窗口也无法得到鼠标消息当该窗口不再需要捕获鼠标消息时,应及时调用ReleaseCapture()以释放鼠标,否则,其他窗口无法接收鼠标信息。菜单、滚动条工具条和标题条等处不由应用程序处理而是送往函数DefWindowProc用户区以外的地方产生的鼠标事件产生一个非用户区鼠标消息4.4鼠标应用程序实例【例4-3】设计一个鼠标程序,在按下Ctrl键的同时按下鼠标左键,在窗口中拖动鼠标,可画出一个圆;在按下Shift键的同时按下鼠标左键,在窗口中拖动鼠标,画出一个矩形。首先在窗口处理函数中加入两个静态BOOL变量:bCircle,bRect,此两个变量用来标志当前所绘的是圆形还是矩形,还要定义全局变量矩形结构体rect1用来记录圆形和矩形的信息。对于这个问应考虑如下几个方面:创建基于对话框的应用程序4_3,添加类成员变量如下:CDC*hDC;RECTrect1; //定义矩形结构体.记录了图形的信息intx,y; //定义鼠标的位置坐标BOOLbCircle=FALSE,bRect=FALSE;//设置绘制圆和矩形的标志变量(2)依次响应按下鼠标左键及鼠标移动的消息响应:voidCMy43Dlg::OnLButtonDown(UINTnFlags,CPointpoint){GetCursorPos(&point); //获取当前光标的位置ScreenToClient(&point); //将屏幕坐标转换为窗口坐标if(nFlags&MK_CONTROL) //同时按下Ctrl键时{bCircle=TRUE; //画圆bRect=FALSE;rect1.left=point.x; //圆的左上角坐标为当前鼠标位置rect1.top=point.y;}elseif(nFlags&MK_SHIFT) //同时按下shift键时{bRect=TRUE; //画矩形bCircle=FALSE;rect1.left=point.x;//矩形的左上角坐标为当前鼠标位置rect1.top=point.y;}else{ bRect=FALSE; bCircle=FALSE;}CDialogEx::OnLButtonDown(nFlags,point);}voidCMy43Dlg::OnLButtonUp(UINTnFlags,CPointpoint){ bRect=FALSE;
bCircle=FALSE; CDialogEx::OnLButtonUp(nFlags,point);}
在OnLButtonUp函数中,当鼠标左键抬起后,表征矩形的变量bRect和表征椭圆的变量bRect均设置为FALSE。voidCMy43Dlg::OnMouseMove(UINTnFlags,CPointpoint){
GetCursorPos(&point); //获取当前光标的位置ScreenToClient(&point); //将屏幕坐标转换为窗口坐标rect1.right=point.x;//图形的右下角坐标为当前鼠标位置
rect1.bottom=point.y;if(bRect==TRUE||bCircle==TRUE)//任一个参数为真就发送刷新请求 Invalidate(); //发出重绘信息CDialogEx::OnMouseMove(nFlags,point);}最后还需要响应刷新函数
voidCMy43Dlg::OnPaint(){CPaintDCdc(this); //用于绘制的设备上下文hDC=GetDC();if(bCircle==TRUE) //绘制圆形
hDC->Ellipse(rect1.left,rect1.top,rect1.right,rect1.bottom);if(bRect==TRUE) //绘制矩形
hDC->Rectangle(rect1.left,rect1.top,rect1.right,rect1.bottom);}【例4-4】编写一个应用程序,其中,要求鼠标的光标始终指向一个字符串的起始位置,随着鼠标的移动,字符串跟随移动,而且字符串的颜色在整个字符串中实现渐变。1:创建基于对话框的应用程序4_4,添加类成员变量如下:CDC*hDC;HFONThF; //定义字体句柄TCHARstr[20]=_T("VisualC++"); //输出的字符串inti=0;intx[11],y[11],color[11];//字符所在位置的坐标以及设置的颜色POINTpt; //记录鼠标所在的位置2:在对话框的4_4Dle.cpp文件中定义创建自定义字体的函数原型:HFONTCreateFont(intnCharHeight,BOOLbItalic);
这先定义函数原型,函数的完整实现,在程序的最后面。3:在初始化函数中进行如下操作:SetTimer(1000,500,NULL);//设置计时器ID为1000,每隔500毫秒发送一个TIMER消息GetCursorPos(&pt); //获取当前鼠标箭头的的位置ScreenToClient(&pt); //将屏幕坐标转换为窗口坐标for(i=1;i<11;i++) //初始化表示位置的数组和颜色{x[i]=pt.x+(i-1)*10;y[i]=pt.y;color[i]=25*(i-1);}这里需要获取鼠标箭头的位置,第一个字符就在鼠标箭头的位置,在for循环中,定义了数组元素所存放的字符的位置以及定义的颜色4:响应定时器函数,添加如下斜体加粗的代码如下:voidCMy44Dlg::OnTimer(UINT_PTRnIDEvent){if(nIDEvent==1000)Invalidate(); CDialogEx::OnTimer(nIDEvent);}5:编写自定义字体的函数,代码如下:HFONTCreateFont(intnCharHeight,BOOLbItalic){HFONThFont;hFont=CreateFont( //定义字体句柄 nCharHeight, //字体高度 0, //系统根据高宽比选取字体最佳宽度值 0, //文本倾斜度,表示水平 0, //字体倾斜度为 400, //字体粗度,为正常 bItalic, //是斜体字 0, //无下划线 0, //无删除线 ANSI_CHARSET, //ANSI_CHARSET字符集 OUT_DEFAULT_PRECIS, //删除精度为默认值 CLIP_DEFAULT_PRECIS, //裁剪精度为默认值 DEFAULT_QUALITY, //输出质量为默认值 DEFAULT_PITCH|FF_DONTCARE, //字间距 _T("Arial")); //字体名称 if(hFont==NULL)returnNULL; else returnhFont;}6:编写刷新函数,添加如下斜体加粗的代码:voidCMy44Dlg::OnPaint(){CPaintDCdc(this); //用于绘制的设备上下文hDC=GetDC(); //获得设备环境指针hF=CreateFont(30,0); //创建字体hDC->SelectObject(hF); //选入字体for(i=10;i>0;i--) //调整每个字的位置,后一个字的位置调整到前一个字的位置{x[i]=x[i-1]+30;y[i]=y[i-1];}GetCursorPos(&pt);ScreenToClient(&pt);x[0]=pt.x;y[0]=pt.y;//第一个字位置是当前鼠标的位置,这样所有的字就会跟随鼠标不断移动for(i=1;i<11;i++){hDC->SetTextColor(RGB(255-color[i],color[i],255));//字体颜色hDC->TextOut(x[i],y[i],&str[i],1);//输出从第1到第nChar个字符}
color[1]=color[10]; //把最后一个字符的颜色值赋给第一个字符for(i=10;i>1;i--) //调整颜色,使颜色不断循环变化 color[i]=color[i-1];DeleteObject(hF); //删除字体句柄ReleaseDC(hDC); //删除设备用户指针}为了实现颜色循环,上述代码中的语句“color[1]=color[10];”是重要的,如果不把最后一个字符的颜色值赋给第一个字符,那么久无法实现颜色循环。【例4-5】编写一个鼠标应用程序,按下鼠标左键在窗口中移动时,将按下左键时所在点和当前点所形成的矩形涂成灰色,此时光标为十字型。当抬起鼠标左键时,将前面所绘制的矩形拉伸到整个窗口,拉伸过程中将光标设置为等待光标。然后,若双击鼠标的左键,则灰色消失,窗口恢复到初始状态。1:添加如下类成员: CDC*hdc; //创建DC句柄 HBRUSHhBrush; //创建画刷2:在4_5Dlg.cpp文件中添加如下全局变量: BOOLoperate=FALSE,ready=TRUE;
//用来记录是否处于操作状态或准备操作状态 POINTBeginP,EndP; //记录矩形的起始点和终止点坐标 RECTrect={0,0,0,0}; //定义一个矩形区域3:由于要进行如题目要求的鼠标操作,因此需要通过“类向导”映射如下消息响应函数,他们分别是鼠标左键单击、鼠标移动、鼠标左键弹起和鼠标左键双击,此时在类的头文件中会出现以下的函数:afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);afx_msgvoidOnMouseMove(UINTnFlags,CPointpoint);afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);afx_msgvoidOnLButtonDblClk(UINTnFlags,CPointpoint);4:画图过程需要刷新,因此需要定义刷新处理函数,具体代码如下:voidCMy45Dlg::OnPaint(){CPaintDCdc(this);//用于绘制的设备上下文if(ready==FALSE) {hdc=GetDC();
hBrush=(HBR
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年西藏革吉县财政局招聘财会监督人员的备考题库及答案详解一套
- 2025年中国社会科学院公开招聘第一批专业技术人员169人备考题库及参考答案详解1套
- 2025年福清市人民法院关于公开招聘劳务派遣人员的备考题库及答案详解一套
- 2025年北京协和医院变态(过敏)反应科合同制科研助理招聘备考题库有答案详解
- 2024年河南安阳公安机关留置看护辅警招聘考试真题
- 鞍山台安县新公益性岗位招聘考试真题2024
- 2025河北秦皇岛市社会保险事业服务中心选调6人备考核心题库及答案解析
- 2025年12月杭州市公安局滨江区分局招聘警务辅助人员20人笔试重点题库及答案解析
- 2025年山西省脑瘫康复医院公开招聘编制外合同制工作人员备考题库及参考答案详解1套
- 2025中国有色金属工业昆明勘察设计研究院有限公司面向社会招聘5人考试重点试题及答案解析
- 2025医疗器械检测行业全面分析及质量监管与发展趋势报告
- 口腔诊所管理运营培训课件
- 中国葡萄膜炎临床诊断要点专家共识2025
- 受益所有人识别与风险管理培训
- 2025年国家开放大学(电大)《护理伦理学》期末考试复习题库及答案解析
- 幼儿园每日消毒及安全管理操作规范
- 11.1党和人民信赖的英雄军队课件-2025-2026学年统编版道德与法治八年级上册
- 2025年军队文职保管员题库及答案(可下载)
- 企业劳动用工风险防范操作指南
- DB37-T 5337-2025 建筑隔震减震装置检测技术规程
- 立德树人教育教学课件
评论
0/150
提交评论