暑假花了一个多月的时间,和另一个同学合作完成了《实用英语语音教程》一书的配套辅助学习系统的开发,以下是我完成这一项目后的一些总结,记录实际项目编程中的一些知识。
项目实际需求介绍
(1)题目:听录音,标出被朗读的单词。
(2)说明:每小题有四个选项,随机朗读其中的两项,一个界面放5小题,播放完自动显示下5题内容。如下图所示:
(3)要求:播放每题的两个选项(单词)之间,每小题之间及每页切换间隔为0.3~2.5秒(这个时间可调),关键是能及时响应学习者点击选中的选项。这个延时及响应在切换页时尤为重要,如果延时不够及界面假死,则学习者不能勾中第5题的的选项。
播放指定组的MP3音频,中间需短暂停顿(0.5~2.5秒),如果采用线程调用API播放估计重复创建启动线程比较耗费资源和时间,而采用TMediaPlayer多媒体播放控件加定时器TTimer控件比较容易实现。TMediaPlayer和TTimer都开辟了子线程来处理任务,如何使主线程(主界面线程)在响应定时器“到时(即MediaPlayer中一首MP3播放完)”处理事件中使主线程延时短暂的时间后接着处理任务(即更新界面)?如果使用Sleep函数将挂起程序使界面出现短暂的假死,这对在播放MP3期间还需“及时”响应界面操作是不允许的。而用下面的Delay函数替换Sleep函数可以很好的解决这类问题。
//*********************************************** //功能:延时函数 //参数:dwMilliseconds,微秒,1000=1秒 // //*********************************************** procedure Delay(dwMilliseconds:DWORD); var nowTick:DWORD; dt:DWORD; begin Timer1.Enabled:=False;//关闭定时器,延时期间不产生到时消息 nowTick:=GetTickCount; dt:=0; while(dt<dwMilliseconds)do begin Application.ProcessMessages;//分发消息以使及时程序响应 dt:=GetTickCount-nowTick; end; Timer1.Enabled:=True;//打开定时器,重新响应到时消息 end;
另:上述Delay函数虽然很好解决实际项目中的问题,但它也有一个致命的弱点:由于采用了循环查询致使CPU占用率过高,达到了50%。但对于这个实际项目是没有多大问题的,因为它维持这个高占用率的时间很短(最多2.5秒),所以在做个练习题时CPU占用率是一会1%,一会50%,不会一直50%的占用率。
解决CPU高占用率的问题有两种方案,一是可以在循环检测中加入一个稍微耗时而不怎么占用CPU的无用操作,如I/O读写等;第二种方案是改进Delay函数,具体留待下一节介绍。