定时器的使用

  如果我们在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)移除定时器。

  例子的完整代码请点击这儿下载。  

  各位看官,如果你觉得那里不清楚请给回复,如果你觉得还可以请加关注,加粉丝,谢谢!总之有点反映。

posted @ 2012-05-25 16:48  成少雷  阅读(3284)  评论(3编辑  收藏  举报