Windows程序设计_17_鼠标_1

  老长时间没有更新Windows程序设计的内容了,今天看了一段Windows程序设计文件操作的内容,同时想起鼠标操作还没有更新过

文字,这里先就写一点关于鼠标文字吧。

一、鼠标

(1)

  Windows支持单键、双键和三键鼠标,还可以使用操纵杆或者光笔模拟鼠标。

  1、判断系统是否存在鼠标

  在使用鼠标之前必须判断系统中是否存在鼠标,可通过函数GetSystemMetrics来判断鼠标是否存在。

      bMouse=GetSystemMetrics(SM_MOUSEPRESENT);

  若安装了鼠标,则bMouse将返回TRUE,否则就返回0.

  要点:

    Windows98中无论是否安装鼠标,这个函数都将返回TRUE。

  2、判断鼠标的键数

  通过GetSystemMetrics函数还可以确定安装的鼠标的键鼠,只要将传递给函数是参数改为:SM_CMOUSEBUTTONS 即可判断

系统中鼠标的键;如果没有安装鼠标,那么函数将返回0;在Windows98中,无论有没有安装鼠标,这个函数都将返回2.

  3、判断鼠标是否切换过左右手

  通过向GetSystemMetrics函数传递SM_SWAPBUTTON是否进行了这种切换;

(2) windows预定义

  当Windows用户移动鼠标时,在屏幕上将有一个“鼠标光标”的小位图,随着用户的移动而移动。鼠标光标上有一个指向屏幕上精确

位置的单象素“热点”。

  Windows支持预定义的鼠标光标:IDC_ARROW(箭头光标)、IDC_CROSS(十字光标)、IDC_WAIT(光标);箭头光标的热点在

箭头的顶端,十字光标的热点在中心。

  Windows支持用户自定义鼠标光标;在定义窗口类的时候,我们可以指定预定义的鼠标光标为窗口默认鼠标。

  通过下面的语句指定窗口默认光标:

          wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);

  鼠标操作术语:

    单击:按下并松开一个鼠标键

    双击:快速按下并松开鼠标键两次

    拖曳:按住鼠标键并移动鼠标

  鼠标键名:

    左键:LBUTTON

    中键:MBUTTON

    右键:RBUTTON

  双键鼠标只有左键与右键,单键鼠标只有一个左键。

(3)客户区鼠标消息

  鼠标在用户窗口移动、按键窗口都会收到消息;这一点与键盘消息不一样:只有拥有输入焦点的窗口才能接收键盘消息。

  Windows一共定义了21种鼠标消息,其中10种是客户去消息,而有11中是非客户去消息,用户程序经常忽略非客户区消息。当鼠标从窗口移动

时,窗口会接收到WM_MOUSEMOVE消息;当用户在窗口客户去按下鼠标键的时候会接受到如下鼠标消息:

  只有三键鼠标才会接收到中键鼠标消息,只有双键、三键鼠标才能接收到右键消息;仅当定义的窗口类能接收DBLCLK双击消息之后,窗口

才能接收到这些消息。

  对于窗口接收到的鼠标消息,lParam参数的值均含有鼠标的位置:低位字为x坐标,高位字为y坐标,lParam参数为32位,字定义为16位;

当要处理鼠标消息时可以通过:

        x=LOWORD(lParam);

        y=HIWORD(lParam);

  获取当前鼠标消息的热点坐标,x、y的值均是相对于窗口客户区左上角顶点而言;这与通常使用的坐标有点不一样。

  Windows定义wParam参数指示鼠标键及Shift和Ctrl键的状态,在程序中,可以使用WINUSER.H定义的位旗标来测试wParam参数。

  MK代表鼠标消息,可以利用下面的语句测试按键的状态:

        if(wParam&MK_SHIFT)

          statement;

    如果接收到WM_LBUTTONDOWN消息的时候,上面的statement语句能执行,则表示按下左键的时候同时按下了shift键。

  Windows不能在鼠标移动过程中,为热点经过的每个像素都发送WM_MOUSEMOVE消息,窗口接收到消息的速度取决于鼠标移动的速度

以及窗口过程处理移动消息的速度;即Windows不能用未处理的WM_MOUSEMOVE消息来填充消息队列,(为了验证这个特性,可以利用spy

程序来监控鼠标消息和窗口处理消息的情况)

  窗口处理鼠标消息的过程如下:

    非活动窗口——>按下鼠标——》窗口变成活动窗口——》发送鼠标消息到窗口过程,

    活动窗口——》按下鼠标——》发送鼠标消息到窗口过程

  上述过程是一般的过程,但是这个过程有时候会变成其他样子,当有模态窗口存在时,这个过程可能变得不一样,需要

注意。

  窗口接收到的消息也不一定是按下左键/按下右键为接收到第一个鼠标消息;例如我们在第一个窗口按下鼠标左键,而

后将鼠标移动到第二个窗口释放;那么第二个窗口接收到鼠标消息将会先是WM_MOUSEMOVE,然后是WM_LBUTTONUP消息,

因此在处理的时候需要注意。

  例外情况:

(4)处理shift和Ctrl键与鼠标组合消息

  前面说过,可以通过wParam参数和位旗标的与运算来查看是否按下了鼠标和shift/ctrl这样的组合消息。

  在鼠标消息中可以通过下面的语句来确定是否按下了shift和Ctrl键

    if(wParam & MK_SHIFT)

    {

        if(wParam & MK_CONTROL)

          {鼠标消息的同时按下了shift和ctrl键}

        else

          {鼠标键的同时按下shift键}

    }

    else

    {

        if(wParam & MK_CONTROL)

          {鼠标消息的同时按下了ctrl键}

        else

          {仅有鼠标消息}

    }

  在用户程序中可以通过利用鼠标和键盘的组合消息来模拟鼠标消息,这样在单键鼠标的情况下就可以实现右键鼠标消息的处理。具体

我们就不用实例代码说明了。

  Windows使用函数GetKeyState通过虚拟键码VK_LBUTTON、VK_RBUTTON、VK_MBUTTON、VK_SHIFT、VK_CONTROL来返回

鼠标键与shift键的状态。如果GetKeySate返回负值,则说明按下了鼠标键或者shift键。因为GetKeyState返回当前正在处理的鼠标键或者shift

键的状态,所以全部状态消息都与相应的消息时同步的。

(5)双击鼠标键

  双击鼠标键是指在短时间内单击两次。

  双击条件:   1、两次单击发生时鼠标光标热点的距离必须在系统规定的方位之内

        2、两次单击发生的时间间隔在指定的时间范围内;可以在系统控制面板中改变鼠标双击时间间隔。

  如果要使得窗口能接收双击鼠标消息,那么窗口的风格必须有CS_DBLCLKS位旗标。如下所示:

    wndclass.style=CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

  如果没有设置窗口风格,那么双击时窗口将接收下面一系列的消息:

      

  如果设置了窗口风格将接收到:

  

  如上所示,这两个消息队列,仅是第三个消息发生了变化。

  如果双击中的第一个单击操作完成某个单击功能,则处理双击消息很容易,那么第二次单击消息则用来完成第一次单击以外的事情;

这里如:

  Windows资源管理器的鼠标的单击选定,而双击打开; 当然可以在系统中设计指向选定而单击打开,不过这不符合大多数人的操

作习惯。

(6)非客户区鼠标消息

  如果鼠标在窗口之内,但是在客户区之外,那么窗口将会接收系统发送的非客户区鼠标消息;窗口的非客户区包括标题栏、菜单栏和

窗口滚动条,一般情况下,用户程序不需要处理非窗口鼠标消息,而将这些消息由DefWindowProc函数处理。

  Windows用“NC” 表示非客户区消息,如果鼠标在窗口的非客户区中移动,那么窗口过程接收到WM_NCMOUSEMOVE消息。非客

户区消息如下所示:

  因为非客户区有几个区域,因此我们在处理非客户区消息的时候,还需要分辨是在标题栏、菜单栏还是滚动条的鼠标消息。

  为了实现分辨区域:可以借助wParam、lParam参数来分辨。客户区的鼠标消息和非客户区鼠标消息的wParam、lParam参数是不一样的,wParam

参数指明发送鼠标消息的非客户区位置。当有非客户区鼠标消息时,wParam设定为一HT开始的宏标识符(HT表示命中测试)

  当有非客户区鼠标消息时,lParam参数返回鼠标消息发生时热点的坐标,但是此时的坐标为屏幕坐标,而不是客户区坐标。屏幕坐标以屏幕的左上角顶

点为坐标原点(0,0);当鼠标往右移动时x增加,鼠标往下移动时y增加。

  可以利用Windows函数在屏幕坐标和客户区坐标进行转换:

      ScreenToClient(hwnd,&pt);

      ClientToScreen(hwnd,&pt);

  

(8)命中测试消息

  在Windows中设置了命中测试消息WM_NCHITTEST,此消息优先于所有其他的客户区和非客户区鼠标消息,lParam参数含有鼠标位置的

x和y屏幕坐标,wParam参数没有用。

  Windows应用程序通常把这个消息传递给DefWindowProc,然后Windows用WM_NCHITTEST消息产生基于鼠标位置的其他鼠标消息;

对于非客户区鼠标消息,当处理WM_NCHITTEST消息时,从DefWindowProc返回的值域将成为鼠标消息中的wParam参数,这个值可以是任

意非客户区鼠标消息的wParam值再加上以下内容:

  HTCLIENT:  客户区

  HTNOWHERE:不在窗口中

  HTTRANSPARENT:窗口由另一个窗口覆盖

  HTERROR:使DefWindowProc产生蜂鸣声

  如果DefWindowProc在处理WM_NCHITTEST消息后返回HTCLIENT,那么Windows将把屏幕坐标转换为客户区坐标,并产生客户区鼠标消息。

因为WM_NCHITTEST消息在所有的鼠标消息前处理,因此我们可以利用这一点来禁用所有的鼠标消息:

  在窗口过程函数中我们可以这样做:

    case  WM_NCHITTEST:

      return (LRESULT)WM_NCHITTEST;

   这样就可以禁用所有的窗口鼠标消息。

  利用命中测试消息,Windows程序设计了一个消息产生消息的机制,我们可以利用窗口的系统菜单的鼠标双击来分析这个过程:

  

    鼠标双击窗口系统菜单——》WM_NCHITTEST消息——》DefWindowProc处理WM_NCHITTEST消息,后返回——》DefWindowProc将

WM_NCLBUTTONDBLCLK消息放到消息队列,并把wParam设置为HTSYSMENU——》通常用户程序不会处理WM_NCLBUTTONDBLCLK

消息,而把消息交给DefwindowProc函数处理——》DefwindowProc接收到wParam=HTSYSMENU的WM_NCLBUTTONDBLCLK

消息后;将WM_SYSCOMMAND消息放入消息队列中,并设置wParam=SC_CLOSE参数——》窗口过程把这个WM_SYSCOMMAND消息

传给DefWindowProc函数处理——》DefwindowProc通过给窗口发送WM_CLOSE消息。

  如果用户程序不处理WM_CLOSE消息,那么DefWindowProc将处理这个消息;DefwindowProc函数接收到WM_CLOSE消息后,将调用

DestroyWindow函数来处理WM_CLOSE,除了其他处理,DestroyWindow还给窗口过程发送WM_DESTROY消息,窗口过程通常用下列

代码来处理WM_DESTROY消息:

    case WM_DESTROY:

        PostQiutMessage(0);

        retrun 0;

  PostQiutMessage使Windows把WM_QUIT消息放入消息队列中,这个消息永远不会经由窗口过程处理,因为WM_DESTROY消息将

是GetMessage函数返回0,终止消息循环,从而退出程序。

  

(9)捕获鼠标

  有时候,可能在鼠标离开窗口后还想获得鼠标消息,这时候我们就需要捕获鼠标。

  例如:  

    在画图程序中,需要画矩形,我们按下鼠表左键,然后拖曳鼠标到适合大小,接下来释放鼠标,就可以绘出矩形;但是假如在拖曳的过程

中鼠标离开了窗口的客户区,那么原来的窗口就不能接受鼠标释放的消息,这时没有办法确定矩形的大小,就不知道如何绘制矩形了,

  为了处理上面的问题,可以通过鼠标捕获功能来实现。

  Windows提供了函数捕获鼠标,如下所示:

    SetCapture(hwnd);

  在调用这个函数后,Windows会将以后的所有鼠标消息发送给窗口句柄为hwnd的窗口过程,并且鼠标消息都将是客户区消息,即使鼠标在非客户区;

lParam参数将指示鼠标在坐标中的位置。不过LOWORD(lParam)和HIORD(lParam)返回的值可能为正也为负,这与鼠标发送消息的位置有关。

  当要释放鼠标时,调用

    ReleaseCapture(hwnd);

  就可以使消息恢复到捕获前的状态。

  我们知道在窗口1按下鼠标键,并且窗口1鼠标被捕获,然后移动到窗口2,接下来释放鼠标键,那么窗口1将不能接收到鼠标释放消息,而窗口2将接收

鼠标消息,这时将不是捕获鼠标的那个窗口接收鼠标消息,而是由光标下面的窗口来接收鼠标消息;

  为了防止捕获产生的异常状态,只有当鼠标键在窗口的客户区中被按下时才捕获鼠标,当键被释放时才释放鼠标捕获。

原文地址:https://www.cnblogs.com/volcanol/p/3021121.html