鼠標事件處理


  前面我們已經講過鍵盤事件的處理,這次聊聊鼠標事件處理。我們從隊列里獲取到事件以后,可以檢測事件的類型,鼠標事件有兩個:鼠標鍵(按下、松開)和鼠標移動。一般的檢測代碼如下:

 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個按鈕的左上角坐標,寬和高是固定的,計算完了就進行位塊傳輸的指定位置。

  鼠標按鍵松開和鼠標移動處理情況類似。這里不過多講述了,需要源代碼請點擊這兒下載。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM