鼠标事件处理

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

 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个按钮的左上角坐标,宽和高是固定的,计算完了就进行位块传输的指定位置。

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

 

posted @ 2012-05-17 22:03  成少雷  阅读(4500)  评论(1编辑  收藏  举报