VC++培训教程草稿(2000年撰写) 张孝祥、袁龙友著 网址:http://www.it315.org
一个空的工程,其他一切采用默认设置。
? 第二步:添加一个C++源文件到工程中。
1) 选择菜单Project|Add to project|New,弹出新建对话框。
2) 在新建对话框左边选择C++ Source File,右边工程选择为EX05_01,源文件的
文件名写入EX05_01,同工程名保持一致。
? 第三步:在代码编辑区中添加WinMain函数,并填写画线代码。
1) 定义两个全局变量用于记录鼠标按下的(x,y)坐标。
int nOrginX; int nOrginY;
2) 创建一个窗口,具体操作在第二章有详细的讲述。
3) 添加回调函数,在该函数的Swich-Case语句段中响应鼠标按下的消息。在鼠
标按下时,用先前定义的两个变量记录鼠标按下的(x,y)坐标,查MSDN得知触发WM_LBUTTONDOWN消息而由系统传递过来的lParam参数,其低16位存放着x坐标,高16位存放着y坐标,将其取出存入nOrginX,nOrginY。
case WM_LBUTTONDOWN:
nOrginX=lParam & 0x0000ffff;
nOrginY=lParam >> 16 & 0x0000ffff; break;
4) 在回调函数的Swich-Case语句段中响应鼠标抬起WM_LBUTTONUP的消息。该消
息处理代码中用到的LOWORD(lParam)和HIWORD(lParam),同上一个响应WM_LBUTTONDOWN消息处理代码中的意思相同,就是分别取出lParam的低16位和高16位,以确定点的坐标。
case WM_LBUTTONUP: HDC hdc;
hdc=GetDC(hwnd);
::MoveToEx(hdc,nOrginX,nOrginY,NULL);
::LineTo(hdc,LOWORD(lParam),HIWORD(lParam) ); ::ReleaseDC(hwnd,hdc); break;
5) 完成回调函数Swich-Case语句段中其他消息的响应,如WM_CLOSE、
WM_DESTROY等等。
6) 最后别忘了在源文件的最头部包含一些必要的头文件。
#include
实际上,该例子在很大程度上类似于第二章所讲过的创建窗口及响应一些鼠标键盘消息的工程。只不过,该例子中在WinMain函数前多定义了两个全局变量用来保存点的坐标,以及在响应鼠标消息时添加的代码不同而已,该工程源文件EX05_01的完整代码如清单5-00中所示。如果读者掌握了第二章所讲的例子,本节的这个例子简直就是小菜一碟!
清单5-00 工程EX05_01中添加的源文件EX05_01的代码 #include
VC++培训教程草稿(2000年撰写) 张孝祥、袁龙友著 网址:http://www.it315.org
#include
//定义两个全局变量用于记录鼠标按下的(x,y)坐标 int nOrginX; int nOrginY;
//在WinMain函数前声明回调函数 LRESULT CALLBACK mywndproc(
HWND hwnd, // handle to window UINT uMsg, // message identifier
WPARAM wParam, // first message parameter LPARAM lParam // second message parameter );
//WinMain函数
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) {
//设计一个窗口类 WNDCLASS wndCls;
wndCls.style=CS_HREDRAW|CS_VREDRAW; wndCls.lpfnWndProc=(WNDPROC)mywndproc; wndCls.cbClsExtra=0; wndCls.cbWndExtra=0;
wndCls.hInstance=hInstance;
wndCls.hIcon=LoadIcon(NULL,IDI_QUESTION); wndCls.hCursor=LoadCursor(NULL,IDC_ARROW);
wndCls.hbrBackground=(HBRUSH)GetStockObject(DKGRAY_BRUSH); wndCls.lpszMenuName=NULL;
wndCls.lpszClassName=\教学\ //注册该窗口类
RegisterClass(&wndCls); //创建窗口
//首先先定义一个窗口句柄用来接收创建窗口成功所返回的句柄 HWND hWnd;
hWnd=CreateWindow(\教学\软件工程师\ CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL, NULL,hInstance,NULL); //显示及刷新窗口
ShowWindow(hWnd,SW_NORMAL); UpdateWindow(hWnd);
//定义消息结构体进行消息循环
VC++培训教程草稿(2000年撰写) 张孝祥、袁龙友著 网址:http://www.it315.org
MSG msg;
while(GetMessage(&msg,NULL,0,0)) {
TranslateMessage(&msg); DispatchMessage(&msg); }
return true; }
//完成回调函数
LRESULT CALLBACK mywndproc(
HWND hwnd, // handle to window UINT uMsg, // message identifier
WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) {
switch(uMsg) {
//响应鼠标左键按下 case WM_LBUTTONDOWN:
nOrginX=lParam & 0x0000ffff; //取低16位x坐标
nOrginY=lParam >> 16 & 0x0000ffff; //取高16位y坐标 break; case WM_CLOSE:
if(IDOK==MessageBox(NULL,\退出?\确认\ {
DestroyWindow(hwnd); }
break;
//响应鼠标左键抬起 case WM_LBUTTONUP: HDC hdc;
hdc=GetDC(hwnd);
::MoveToEx(hdc,nOrginX,nOrginY,NULL);
::LineTo(hdc,LOWORD(lParam),HIWORD(lParam) ); ::ReleaseDC(hwnd,hdc); break;
case WM_DESTROY:
PostQuitMessage(0); break; default:
return(DefWindowProc(hwnd,uMsg, wParam,lParam )); }
VC++培训教程草稿(2000年撰写) 张孝祥、袁龙友著 网址:http://www.it315.org
return 0; }
5.5.1.3 实现橡皮筋功能
有的读者可能还不理解橡皮筋功能是怎样一个功能。再次运行上面讲过的两个画线的程序,会发现,当我们画一条线时,如果鼠标不抬起,我们是看不到那条线的,只有当鼠标抬起后,才可以看到画的线。而橡皮筋功能,就是当我们画线时,鼠标按下之后,只要一拖动鼠标就可以实时的看到画出的线,而且线条始终随着你的鼠标走,看起来好像很有弹性,因此,称之为橡皮筋功能。
与前两个画线程序不同的是,因为我们要实时的看到画的线,因此,画线的代码应该在鼠标移动的过程中响应,而不是在鼠标抬起时,而且,代码也不能像前两个程序那样只是简单在鼠标移动过程中一个MoveTo一个LineTo就可以了,那样只会造成鼠标每到一处,就有一条线出来,会形成杂乱无章的扇型,那么解决的办法就是当鼠标移到另一个点时,如何将已经画出来的上一条线擦除,换句话说,永远只让从起点到鼠标最后所在的点的那一条线显示在屏幕上。这样引出的结果是,我们不得不还要再额外的定义一个变量用来保存上一条线的终点。完整例程请参见光盘中的例子代码EX05-02。
? 第一步:新建一个MFC应用程序工程。
1) 启动Visual C++,选择File|New,弹出新建对话框。
2) 在新建对话框左边选择MFC AppWizard(exe),右边工程名为EX05_02或用户
自定义工程名,文件存放位置用户自定义。
3) 单击OK按钮,弹出MFC AppWizard对话框,选择新建Single document单文
档应用程序,其他一切采用默认设置。
? 第二步:在工程的CEX05_02View类中添加成员变量CPoint m_ptOrigin,用于记录
用户鼠标左键按下时的点坐标。还要再多定义一个变量CPoint m_ptEnd用于记录鼠标移动到最终的点之前的上一个点,以便擦线。
1) 在工作台中,点击EX05_02 classes结点旁的加号,展开工程中的类。
2) 选中CEX05_02View类,右击CEX05_02View,在弹出的快捷方式菜单中选择
Add Member Variable.
3) 在Add Member Variable对话框的Variable Type文本框中输入添加的变量的
类型CPoint,在Variable Name文本框中输入要添加的变量的变量名称m_ptOrigin,访问类型选择public,单击OK。 4) 用同样方法添加另一个变量CPoint m_ptEnd。
? 第三步:打开ClassWizard,在工程的CEX05_02View类中添加鼠标左键按下和鼠标
移动的消息响应,分别为WM_LBUTTONDOWN和WM_MOUSEMOVE。
1) 打开Class Wizard对话框,选择Class name下拉列表框为CEX05_02View,
在Object IDs下面列表框中选中CEX05_02View,然后在右边的Messages列表框中选中WM_LBUTTONDOWN消息,双击该消息或者单击Add Function按钮,将消息添加进工程中。该消息对应的消息函数为OnLButtonDown。
2) 用同样的方法,将WM_MOUSEMOVE消息添加入工程中,或通过工作台加入该消
息映射。
? 第四步:完成WM_LBUTTONDOWN消息执行代码,当鼠标左键按下时,将定义的两个
点全部都初始化为鼠标刚刚按下的点。
1) 在工作台CEX05_02View类下面找到OnLButtonDown函数,双击它,在左边的
VC++培训教程草稿(2000年撰写) 张孝祥、袁龙友著 网址:http://www.it315.org
代码编辑区中显示该函数体。 2) 在该函数中填写如下代码:
void CEX05_02View::OnLButtonDown(UINT nFlags, CPoint point) {
// TODO: Add your message handler code here and/or call default m_ptOrigin =m_ptEnd=point;
CView::OnLButtonDown(nFlags, point); }
? 第五步:完成WM_MOUSEMOVE消息执行代码,当鼠标移动时画线,并且在画线的过
程中不断的擦除上一条画过的线。
1) 在工作台CEX05_02View类下面找到OnMouseMove函数,双击它,在左边的
代码编辑区中显示该函数体。 2) 获取一个设备描述表。
CClientDC dc(this);
3) 设置逆转当前屏幕颜色的绘图模式。
dc.SetROP2(R2_NOT);
4) 重画上一条。如果是第一次画线的话,由于起点和终点初始化为一个点,不会
有任何反应,也没有任何影响。如果不是第一次画线,请读者注意下面第6)所示的,已经将上一条线的终点保存下来,就是说又重画了上一条线。 dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd);
5) 画当前鼠标移动到最后的点的这条线。
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
6) 将上一条线的终点保存下来。
m_ptEnd=point;
也许读者可能不理解,我们只是在鼠标移动过程中画线,那么如果没有添加鼠标抬起消息时,如何来判断已经鼠标抬起,画线结束了呢。这需要我们在OnMouseMove中加一条判断语句if (MK_LBUTTON & nFlags) ,该语句判断鼠标左鍵是否按下。在调用OnMouseMove时,不仅为用户传来了坐标信息,还把鼠标左鍵是否按下,Shift鍵是否按下(详细信息可查MSDN)等信息放在UINT nFlags中传入OnMouseMove,用户可以检查相应位是否为1来判断相应键是否按下。OnMouseMove的完整代码如下: void CEX05_02View::OnMouseMove(UINT nFlags, CPoint point)
{ // TODO: Add your message handler code here and/or call default if (MK_LBUTTON & nFlags) { CClientDC dc(this); dc.SetROP2(R2_NOT); dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd); dc.MoveTo(m_ptOrigin);
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库第5章(3)在线全文阅读。
相关推荐: