zoukankan      html  css  js  c++  java
  • 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将接收

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

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

  • 相关阅读:
    Java实现 蓝桥杯VIP 算法训练 黑色星期五
    Java实现 蓝桥杯VIP 算法训练 比赛安排
    Java实现 蓝桥杯VIP 算法训练 比赛安排
    Java实现 蓝桥杯VIP 算法训练 斜率计算
    Java实现 蓝桥杯VIP 算法训练 斜率计算
    Java实现 蓝桥杯VIP 算法训练 整数平均值
    Java实现 蓝桥杯VIP 算法训练 整数平均值
    控件动态产生器(使用RegisterClasses提前进行注册)
    Delphi编写自定义控件以及接口的使用(做了一个TpgDbEdit)
    Log4delphi使用心得
  • 原文地址:https://www.cnblogs.com/volcanol/p/3021121.html
Copyright © 2011-2022 走看看