• 鼠标事件处理


      前面我们已经讲过键盘事件的处理,这次聊聊鼠标事件处理。我们从队列里获取到事件以后,可以检测事件的类型,鼠标事件有两个:鼠标键(按下、松开)和鼠标移动。一般的检测代码如下:

     1 SDL_Event myEvent;//事件
     2 int quit=0;
     3 
     4 while (!quit)
     5 {
     6     while (SDL_PollEvent(&myEvent))
     7     {
     8         switch (myEvent.type)//检测事件类型
     9         {
    10         case SDL_QUIT:
    11             quit = 1;
    12             break;
    13         case SDL_MOUSEBUTTONDOWN://鼠标按下
    14             //to do
    15             break;
    16         case SDL_MOUSEBUTTONUP://鼠标键松开
    17             //to do
    18             break;
    19         case SDL_MOUSEMOTION://鼠标移动
    20             //to do            
    21             break;
    22         }            
    23     }
    24 }

       在SDL_MOUSEBUTTONDOWN、SDL_MOUSEBUTTONUP事件中,我们可以检测鼠标按键信息,然后加以处理。鼠标按键事件的结构:  

    typedef struct SDL_MouseButtonEvent {
        Uint8 type;    /* SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP */
        Uint8 which;    /* The mouse device index */
        Uint8 button;    /* 鼠标按键,左、右、中三个键*/
        Uint8 state;    /* SDL_PRESSED按下 or SDL_RELEASED松开 */
        Uint16 x, y;    /* 鼠标按下时的坐标 */
    } SDL_MouseButtonEvent;

       鼠标移动事件的结构为:

    typedef struct SDL_MouseMotionEvent {
        Uint8 type;    /* SDL_MOUSEMOTION */
        Uint8 which;    /* The mouse device index */
        Uint8 state;    /* 鼠标状态 */
        Uint16 x, y;    /* 鼠标当前坐标 */
        Sint16 xrel;    /* 鼠标在x方向的位移 */
        Sint16 yrel;    /* 鼠标在y方向的位移*/
    } SDL_MouseMotionEvent;

      当检测出是那个鼠标事件后,我们可以根据事件结构采取相应的处理,下面以一个登录界面上两个按钮为例,说明如何处理鼠标事件。

      

       界面如左图所示,有两个按钮登录和注册,每个按钮都有三种状态,鼠标不在按钮上是第一种状态,鼠标移动到按钮上是第二种状态,按下鼠标时第三种状态。其相应图片做成了一个精灵图(右图)。代码如下:

      1 /*
      2   功能:演示SDL鼠标事件
      3   作者:csl
      4   日期:2012-5-14
      5 */
      6 #include <stdio.h> 
      7 #include <stdlib.h> 
      8 #include "SDL.h"
      9 
     10 typedef enum {LEFT,RIGHT}BUTTONPOS;//枚举按钮在精灵图中的编号
     11 typedef enum {LOGIN,REGISTER,OTHER}BUTTONFLAG;//枚举按钮
     12 
     13 //屏幕尺寸
     14 #define SCREENWIDTH  432
     15 #define SCREENHEIGH  287
     16 #define BPP  32
     17 
     18 //按钮尺寸
     19 #define  BUTTONWIDTH 81
     20 #define  BUTTONHEIGH 22
     21 
     22 //定义各个按钮的位置
     23 SDL_Rect position[2] = {{123,206,81,22},{215,206,81,22}};
     24 SDL_Surface *gpScreen = NULL;//显示表面
     25 SDL_Surface *gpBackground = NULL;//背景
     26 SDL_Surface *gpButton = NULL;
     27 SDL_Event myEvent;//事件
     28 
     29 
     30 SDL_Surface *loadImage(char *aFilename);
     31 void cleanUp();//程序退出时清理内存
     32 int isOnButton(int aX,int aY,int aIndex);
     33 void changeButton(BUTTONPOS aPos,int aNo,SDL_Rect *aDst);
     34 
     35 int main(int argc,char *argv[])
     36 {
     37     int quit = 0;
     38     int x,y;
     39     SDL_Rect src,dst;
     40     BUTTONFLAG selected = OTHER;//按钮选中标志
     41     int current=-1;
     42 
     43     if((SDL_Init(SDL_INIT_VIDEO)==-1)) //初始化视频子系统
     44     {
     45         printf("Unable to init SDL: %s\n", SDL_GetError());
     46         exit(-1);
     47     }
     48     atexit(cleanUp);// 注册cleanUp,当退出时调用,使得退出时程序自动清理
     49 
     50     //创建32位窗口
     51     gpScreen = SDL_SetVideoMode(SCREENWIDTH,SCREENHEIGH, BPP, SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF );
     52     if(!gpScreen) 
     53     { 
     54         exit(1);
     55     }
     56 
     57     //载入各个图片
     58     gpBackground = loadImage("jpg\\register.jpg");
     59     gpButton = loadImage("jpg\\button.jpg");
     60     if (!gpBackground||!gpButton)
     61     {
     62         exit(0);
     63     }
     64 
     65     //显示背景图
     66     SDL_BlitSurface(gpBackground,NULL,gpScreen,NULL);
     67     SDL_Flip(gpScreen);
     68 
     69     //事件处理
     70     while (!quit)
     71     {
     72         while (SDL_PollEvent(&myEvent))
     73         {
     74             switch (myEvent.type)//检测事件类型
     75             {
     76             case SDL_QUIT:
     77                 quit = 1;
     78                 break;
     79             case SDL_MOUSEBUTTONDOWN://鼠标按下
     80                 switch(myEvent.button.button)
     81                 {
     82                 case SDL_BUTTON_LEFT:
     83                     x = myEvent.button.x;//得到当前鼠标的坐标
     84                     y = myEvent.button.y;                    
     85 
     86                     //判断鼠标是否落在登录按钮里
     87                     if (isOnButton(x,y,0)==1)
     88                     {
     89                         selected=LOGIN;    
     90                         changeButton(LEFT,2,&position[0]);
     91                         SDL_Flip(gpScreen);
     92                     }
     93                     else if (isOnButton(x,y,1)==1)//判断鼠标是否落在注册按钮里
     94                     {
     95                         selected=REGISTER;
     96                         changeButton(RIGHT,2,&position[1]);
     97                         SDL_Flip(gpScreen);
     98                     }                    
     99                     break;                
    100                 }
    101                 break;
    102             case SDL_MOUSEBUTTONUP:
    103                 switch(myEvent.button.button)
    104                 {
    105                 case SDL_BUTTON_LEFT:
    106                     x = myEvent.button.x;//得到当前鼠标的坐标
    107                     y = myEvent.button.y;                    
    108 
    109                     //判断鼠标是否落在登录按钮里
    110                     if (selected==LOGIN)
    111                     {
    112                         changeButton(LEFT,1,&position[0]);
    113                         SDL_Flip(gpScreen);
    114                     }
    115                     else if (selected==REGISTER)//判断鼠标是否落在注册按钮里
    116                     {
    117                         changeButton(RIGHT,1,&position[1]);
    118                         SDL_Flip(gpScreen);
    119                     }    
    120                     selected = OTHER;
    121                     break;
    122                 }
    123                 break;
    124             case SDL_MOUSEMOTION://鼠标移动
    125                 x = myEvent.button.x;//得到当前鼠标的坐标
    126                 y = myEvent.button.y;
    127 
    128                 //判断鼠标是否落在登录按钮里
    129                 if (isOnButton(x,y,0))
    130                 {
    131                     changeButton(LEFT,1,&position[0]);
    132                     changeButton(RIGHT,0,&position[1]);    
    133                     SDL_Flip(gpScreen);
    134                 }
    135                 else if(isOnButton(x,y,1))
    136                 {
    137                     changeButton(LEFT,0,&position[0]);
    138                     changeButton(RIGHT,1,&position[1]);    
    139                     SDL_Flip(gpScreen);
    140                 }
    141                 else 
    142                 {
    143                     changeButton(LEFT,0,&position[0]);
    144                     changeButton(RIGHT,0,&position[1]);    
    145                     SDL_Flip(gpScreen);
    146                 }                
    147                 break;
    148             }            
    149         }
    150     }
    151     
    152     system("pause"); 
    153     return 0; 
    154 }
    155 
    156 
    157 /*--------------------------------------------------------------------
    158     函数名:    loadImage
    159     参  数:    char *filename  图像文件的名字
    160     返回值: SDL_Surface * 返回指向图像表面的指针
    161     功  能:    载入图像
    162     备  注:
    163 ----------------------------------------------------------------------*/
    164 SDL_Surface *loadImage(char *aFilename)
    165 {
    166     SDL_Surface* loadedImage = NULL;
    167     SDL_Surface* optimizedImage = NULL;
    168 
    169     //载入图像
    170     loadedImage = IMG_Load( aFilename);
    171 
    172     if( NULL != loadedImage )//If the image loaded
    173     {
    174         //创建优化图像
    175         optimizedImage = SDL_DisplayFormat( loadedImage );
    176 
    177         //释放loadImage
    178         SDL_FreeSurface( loadedImage );
    179     }
    180     return optimizedImage;
    181 }
    182 
    183 /*--------------------------------------------------------------------
    184     函数名:    cleanUp
    185     参  数:    无
    186     返回值: 无
    187     功  能:    程序退出时,清理内存
    188     备  注:
    189 ----------------------------------------------------------------------*/
    190 void cleanUp()
    191 {
    192     if (gpBackground)
    193     {
    194         SDL_FreeSurface(gpBackground);
    195     }    
    196     if (gpButton)
    197     {
    198         SDL_FreeSurface(gpButton);
    199     }
    200 
    201     SDL_FreeSurface(gpScreen);
    202     SDL_Quit();
    203 }
    204 
    205 /*--------------------------------------------------------------------
    206     函数名:    isOnButton
    207     参  数:    (x,y)鼠标当前坐标;
    208             index要判断的那个按钮,0表示登录按钮,1表示注册按钮
    209     返回值: 如果落在指定按钮上返回1,否则返回0
    210     功  能:    判断鼠标是否落在指定按钮上面
    211     备  注:
    212 ----------------------------------------------------------------------*/
    213 int isOnButton(int aX,int aY, int aIndex)
    214 {
    215     return aX>=position[aIndex].x && aX<=(position[aIndex].x+position[aIndex].w)&&
    216         aY>=position[aIndex].y && aY<=(position[aIndex].y + position[aIndex].h);
    217 }
    218 
    219 /*--------------------------------------------------------------------
    220     函数名:    changeButton
    221     参  数:    aPos表示要取精灵图左边还是右边的按钮;
    222             aNO要取的那个按钮,从上往下依次为0,1,2
    223     返回值: 无
    224     功  能:    将指定按钮表面传输到显示表面
    225     备  注:
    226 ----------------------------------------------------------------------*/
    227 void changeButton(BUTTONPOS aPos,int aNo,SDL_Rect *aDst)
    228 {
    229     SDL_Rect src;
    230 
    231     switch(aPos)
    232     {
    233     case LEFT:
    234         src.x = 0;
    235         break;
    236     case RIGHT:
    237         src.x = BUTTONWIDTH + 1;
    238         break;
    239     }
    240     src.y =aNo? (aNo * BUTTONHEIGH + 1):(aNo * BUTTONHEIGH);
    241     src.w = BUTTONWIDTH;
    242     src.h = BUTTONHEIGH;
    243     SDL_BlitSurface(gpButton,&src,gpScreen,aDst);
    244 }

      程序中定义了两个枚举类型,第一个BUTTONPOS,用于表示从精灵如上提取图片,LEFT表示左边那一列,RIGHT表示右边那一列。position数组保存了登录和注册按钮在显示表面上的位置;第二个枚举表示是否选中指定按钮,LOGIN表示选中登录、REGISTER表示选中注册、OTHER表示未选中。

      第74行检测事件类型,第79行检测是否是鼠标按下事件,如果是,则要检测按下的是那个键,如果是左键按下,要将更换按钮图片,检测代码是:

                    switch(myEvent.button.button)
                    {
                    case SDL_BUTTON_LEFT:
                        x = myEvent.button.x;//得到当前鼠标的坐标
                        y = myEvent.button.y;                    
    
                        //判断鼠标是否落在登录按钮里
                        if (isOnButton(x,y,0)==1)
                        {
                            selected=LOGIN;    
                            changeButton(LEFT,2,&position[0]);
                            SDL_Flip(gpScreen);
                        }
                        else if (isOnButton(x,y,1)==1)//判断鼠标是否落在注册按钮里
                        {
                            selected=REGISTER;
                            changeButton(RIGHT,2,&position[1]);
                            SDL_Flip(gpScreen);
                        }                    
                        break;                
                    }

      switch的判断表达myEvent.button.button用于检测是那个鼠标按键,如果是左键,首先得到鼠标坐标,然后调用isOnButton判断是否落在指定按钮上,如果落在按钮上,首先将选中标志selected置值,然后调用changeButton函数修改按钮显示的图片。

      判断鼠标是否落在按钮上的函数isOnButton有三个参数,前两个是鼠标坐标,第三个是按钮编号,0是登录,1是注册,只要判断鼠标的坐标(x,y)落在按钮区域内就可以。

      改变按钮图片,思路比较简单,比如说当按下登录按钮时我们需要把精灵图中左边的第3个按钮显示出来,所以传LEFT,2和显示的位置,在函数里首先计算左边第3个按钮的位置,主要是计算第3个按钮的左上角坐标,宽和高是固定的,计算完了就进行位块传输的指定位置。

      鼠标按键松开和鼠标移动处理情况类似。这里不过多讲述了,需要源代码请点击这儿下载。

  • 相关阅读:
    Jabref安装及使用教程
    均方误差与均方根误差
    费马大定理
    JabRef设置
    申请内存时底层发生了什么?
    什么是Pipeline?
    基于三维点云场景的语义及实例分割
    华为 MateView 系列显示器新品
    C#-WinForm跨线程修改UI界面
    C# 代码生成二维码方法及代码示例(QRCoder)
  • 原文地址:https://www.cnblogs.com/landmark/p/2499699.html
Copyright © 2020-2023  润新知