定時器的使用


  如果我們在SDL程序中需要每個一個固定時間去處理一件事情,那么我們需要一個定時器,就像生活中鍾表一樣可以整點報時,這個功能就是SDL的定時器子系統,你要使用SDL的定時器必須初始化定時器子系統,請看《SDL起動與退出》,SDL定時器比較簡單就是一個間隔固定時間的函數調用,如果你要添加一個定時器可以使用函數SDL_AddTimer,其原型為:

SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param);

其中:函數的返回值SDL_TimerID是一個結構體指針,SDL文檔中並沒有給出其結構,所以我們只要知道這是一個指向添加的定時器的指針就可以了。

   函數的第一個參數interval是定時器間隔的時間,以毫秒(1秒=1000毫秒)為單位;第二個參數是要執行的函數,也稱回調函數,是定時器每個interval時間段調用的函數,不是我們自己調用的,SDL_NewTimerCallback是一個函數指針類型,指明了要調用的函數原型:

typedef Uint32 (SDLCALL *SDL_NewTimerCallback)(Uint32 interval, void *param);

  要調用的函數的原型滿足返回值是Uint32,函數的第一個參數是定時器的時間間隔(一般和SDL_AddTimer的interval一樣),第二個參數是需要給函數傳遞的參數,不需要傳參的話可以寫NULL。SDL_AddTimer第三個參數也是同樣的。

  下面我們做一個SDL電子表,顯示當前時間,所需圖片如下圖所示:

所需圖片 程序效果

   程序代碼如下:

 1 /*
 2   功能:Timer的用法
 3   作者:csl
 4   日期:2012-5-24
 5 */
 6 #include <stdio.h> 
 7 #include <stdlib.h> 
 8 #include <time.h>
 9 #include <string.h>
10 #include <SDL.h>
11 
12 //窗口長和寬
13 #define SCREENWIDTH  280
14 #define SCREENHEIGH  40
15 #define BPP 32
16 
17 //圖片長和寬
18 #define DIGITALWIDTH 13
19 #define DIGITALHEIGH 23
20 
21 SDL_Surface *gpScreen;//顯示表面
22 SDL_Surface *gpDigitals;//數字的精靈圖
23 SDL_Event myEvent;//事件
24 
25 //時間定時器
26 SDL_TimerID myTime;
27 const unsigned int INTERVALS = 1000;//1秒 
28 
29 SDL_Surface *loadImage(char *aFilename);
30 void cleanUp();
31 int cToD(char ch);
32 SDL_Rect locatePosition(char ch);
33 Uint32 displayTime(Uint32 interval, void *param);
34 
35 int main(int argc,char *argv[])
36 {
37     int quit = 0;
38     SDL_Rect src,dst;
39     
40     if((SDL_Init(SDL_INIT_EVERYTHING)==-1)) //初始化視頻子系統
41     {
42         printf("Unable to init SDL: %s\n", SDL_GetError());
43         exit(-1);
44     }
45     atexit(cleanUp);// 注冊cleanUp,當退出時調用,使得退出時程序自動清理
46 
47     //創建32位600*480窗口
48     gpScreen = SDL_SetVideoMode(SCREENWIDTH,SCREENHEIGH, BPP, SDL_HWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF ||SDL_NOFRAME );
49     if(!gpScreen) 
50     { 
51         exit(1);
52     }
53     gpDigitals = loadImage("jpg\\digitals.jpg");
54     //displayTime(1000,0);
55 
56     myTime = SDL_AddTimer(INTERVALS,displayTime,NULL);
57     if (!myTime)
58     {
59         exit(0);
60     }
61 
62     while (!quit)
63     {
64         while (SDL_PollEvent(&myEvent))
65         {
66             switch (myEvent.type)
67             {
68             case SDL_QUIT:
69                 quit = 1;
70                 break;
71             }
72         }
73     }
74     
75     system("pause"); 
76     return 0; 
77 }

  要使用定時器,我們首先要定義一個SDL_TimerID myTime;值得注意的是myTime是一個指針,在主函數里初始化子系統的時候要初始化定時器子系統,所以我們的初始化SDL_Init(SDL_INIT_EVERYTHING),是初始化所有的SDL子系統,然后要首先添加一個定時器,在56行我們添加了定時器,如果不成功則要結束程序。添加以后每隔1秒也就是1000毫秒就會調用回調函數displayTime來顯示時間。displayTime代碼如下:

/*--------------------------------------------------------------------
	函數名:	displayTime
	參  數:	interval定時器的時間間隔;
		param需要傳遞給displayTime函數的參數
	返回值: 下一次要調用該函數的時間間隔
	功  能:	定時器回調函數,每隔interval時間段被系統調用
	備  注:
----------------------------------------------------------------------*/
Uint32 displayTime(Uint32 interval, void *param)
{
	struct tm *currentTime;
	SDL_Rect src;
	SDL_Rect dst = {(SCREENWIDTH-19*DIGITALWIDTH)/2,(SCREENHEIGH-DIGITALHEIGH)/2,DIGITALWIDTH,DIGITALHEIGH};
	char strTime[20];
	int i,len;
	time_t t = time(NULL);//取得當前系統時間


	//取得當前時間,並按格式轉換成字符串
	currentTime = localtime(&t);//將t轉換成當地時間
	strftime(strTime,20,"%Y-%m-%d %H:%M:%S",currentTime);

	//在屏幕中央顯示系統時間
	for (i = 0;strTime[i]!='\0';i++)
	{
		src = locatePosition(strTime[i]);
		SDL_BlitSurface(gpDigitals,&src,gpScreen,&dst);
		dst.x+=DIGITALWIDTH;
	}
	SDL_Flip(gpScreen);
	
	return INTERVALS;
}

   在函數里,我們首先要取得當前系統時間,其中time_t是c語言標准庫里定義的,是一個整型類型,C語言里用這個類型的變量保存系統時間,實際上保存的是按unix時間格式保存自1970年1月1日0時0分0秒起至現在的總秒數,這個我們很難看懂,所以我們使用了另外一種描述時間的結構struct tm:

 

 

struct tm {   
    int tm_sec; /* 秒–取值區間為[0,59] */   
    int tm_min; /* 分 - 取值區間為[0,59] */   
    int tm_hour; /* 時 - 取值區間為[0,23] */   
    int tm_mday; /* 一個月中的日期 - 取值區間為[1,31] */   
    int tm_mon; /* 月份(從一月開始,0代表一月) - 取值區間為[0,11] */   
    int tm_year; /* 年份,其值從1900開始 */   
    int tm_wday; /* 星期–取值區間為[0,6],其中0代表星期天,1代表星期一,以此類推 */   
    int tm_yday; /* 從每年的1月1日開始的天數–取值區間為[0,365],其中0代表1月1日,1代表1月2日,以此類推 */   
    int tm_isdst; /* 夏令時標識符,實行夏令時的時候,tm_isdst為正。不實行夏令時的進候,tm_isdst為0;不了解情況時,tm_isdst()為負。*/   
}; 

  我們需要把time_t格式的時間轉換成struct tm表示的時間,這個轉換函數就是localtime,轉換完成后我們就可以得到當前時間了,strftime函數可以將strcut tm時間轉換成一個字符串,並且可以指定轉換格式:

%a

星期的縮略形式

%A

星期的完整形式

%b

月份的縮略形式

%B

月份的完整形式

%c

月份的縮略形式

%d

月中的第幾天(1-31)

%H

小時, 24小時格式 (0-23)

%I

小時, 12小時格式  (1-12)

%j

年中的第幾天(1-366)

%m

月份 (1-12). Note: 某些版本的Microsoft Visual C++ 可能使用取值范圍0-11.

%M

分鍾(0-59)

%p

本地時間的上午或下午(AM or PM)

%S

秒鍾(0-59)

%U

年中的第幾周,星期天是一周的第一天

%w

星期幾的數字表示(0-6, 星期天=0)

%W

一年中的第幾周,星期天是一周的第一天

%x

標准日期字符串

%X

標准時間字符串

%y

年(0-99)

%Y

用CCYY表示的年(如:2004)

%Z

時區名

%%

百分號

 

   轉換完成后我們得到一個字符格式的當前日期,比如說:2012-05-24 7:47:23,這個串里的每一個字符對對應精靈圖里的一個精靈,所以我們就可以根據字符取得它在精靈圖里的位置,然后將它顯示在窗口上,我們是通過locatePosition函數取得位置的,它的代碼如下:

/*--------------------------------------------------------------------
    函數名:    locatePosition
    參  數:    ch需要確定位置的字符
    返回值: 字符在精靈圖中的位置
    功  能:    計算字符在精靈圖中的位置
    備  注:
----------------------------------------------------------------------*/
SDL_Rect locatePosition(char ch)
{
    int y;
    SDL_Rect tmp;

    switch(ch)
    {
    case '-':
        tmp.y=0;
        break;
    case ' ':
        tmp.y=DIGITALHEIGH;
        break;
    case ':':
        tmp.y = 2 * DIGITALHEIGH ;
        break;
    default:
        tmp.y=(12-cToD(ch))*DIGITALHEIGH;
    }

    tmp.x = 0;
    tmp.w = DIGITALWIDTH;
    tmp.h = DIGITALHEIGH;

    return tmp;
}

  每一副精靈圖其x坐標都是0,y坐標可以分門別類加以列舉,每一副精靈圖的長和寬固定,最后返回一個矩形變量(SDL_Rect)就可以了 。

  我們取得了字符的精靈圖,在計算它應該顯示在屏幕的位置就可以了,然后將其傳輸到顯示表面上顯示就可以了,顯示完一副圖片后將dst的x坐標加上圖片寬度就是下一副圖片的位置。

  這樣我們就可以每隔1秒鍾顯示下當前的系統時間了。最后不要忘記調用SDL_RemoveTimer(myTime)移除定時器。

  例子的完整代碼請點擊這兒下載。  

  各位看官,如果你覺得那里不清楚請給回復,如果你覺得還可以請加關注,加粉絲,謝謝!總之有點反映。


免責聲明!

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



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