前面我們已經講過鍵盤事件的處理,這次聊聊鼠標事件處理。我們從隊列里獲取到事件以后,可以檢測事件的類型,鼠標事件有兩個:鼠標鍵(按下、松開)和鼠標移動。一般的檢測代碼如下:
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個按鈕的左上角坐標,寬和高是固定的,計算完了就進行位塊傳輸的指定位置。
鼠標按鍵松開和鼠標移動處理情況類似。這里不過多講述了,需要源代碼請點擊這兒下載。


