【争鸣】浅谈《程序规范》中的时间表写作问题

本文探讨了在Delphi编程环境下如何有效利用时间表来实现动画和其他动态交互功能。重点介绍了时间表的设计原理,包括如何通过ontimer事件实现动画的逐帧播放,并提供了具体的编程实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浅谈《程序规范》中的时间表写作问题


keywords:Timer,frame,event,function,procedure,project

 

1. 时间表的目的

编写代码的指标:省程序存储器(等于编译后的汇编语言代码要短),省RAM。

delphi编写的绝大多数代码,都是动态显示的。我们似乎可以保持一种习性,就是在一个事件,比如onclick等等,等到一进入,一气演示完之后,从这个事件的函数出来,回到等候响应的状态,这时虽然程序未被终止,但对用户而言已经剧终了,用户除了点击右上角之外不能做任何事。这是basic用惯的人与VCL编程达成的妥协。但是如果这个程序有互动呢?如果它可以识别用户按下键盘上的某个键,那就必须有按键响应函数。尽管如此,也可以达到一个程序只有一个响应函数的境界,这个事件就是onkeydown,什么onclick都不要。但显然,PC不可能只进入一次这个函数了,因为用户不可能只按一次键,这又不像basic,有inkey函数。于是,天真的“单响应”信念破产了。

其实就算整个工程没有互动,单响应也难以为继。比如说我想在Tform1,button1click函数(它的对应事件是button1.onclick)内设这些命令:

shape1.Top:=30;
delay(60);
shape1.Top:=60;
delay(90);
shape1.Top:=90;


实验残酷的证明,运行效果,只是动画结束后定格的样子,没有过程。如果说在BASIC,每语句都像薄薄的一张时间片,那么在delphi,每进入一次函数都可以看成一个时间片。刚才那片太厚了,还要等180个时间单位怎么办?今后编写时,就应该注意“切薄片”——像内部计算什么的,都在一个函数内搞定,实时性强的活动,一定要分多次完成,如果猴爬山一共7帧动画,那就让PC进7次函数完成它。

大概一旦见到了shape、image这些控件,我们看到的程序运行顺序,就与代码顺序出入太大。以上代码在机内可以转换为是一系列canvas有关的语句,其间还有一些函数,比如开发者刚才根本没写的onpaint函数。

所以,要发展动画,非多次进入一个事件不可。这就是ontimer。

2、时间表写法范例

2.1 画表格

程序猿在写程序时,需要画“矩菱”流程图。矩形是已经发生的行为,菱形则代表PC的驿站,等候下一个刺激,让它知道自己该选择哪条路。

但框图的表示能力也有限。特别是

如图(本来应该是如表),H、M、S与现实中的时分秒并不相等。一个S相当于50ms(这取决于你设定timer-interval是多少)。"What happen”意为这个结点要完成的活动。"blocked by”意为这一节点的行动结束后,定时器被中断。只有按下"blocked by”中规定的按键,time frame才会恢复前进。"Other button"意为阻塞阶段还有些按键具有别的功能,比如在3:2:36时按下confirm,就会进入5:0:0。在2::2:3按up,会使程序中某个变量+1。这些是表格里表示不出来的。

 

 

台湾而过

2.2 写代码

2.2.1 混合写法

procedure TForm2.tmr1Timer(Sender: TObject);//注意:该段代码仅仅是格式,与上面表格无关
begin
caption:=Format('Manipulator %d-%d-%d',[tim_hou,tim_min,tim_sec]);


   if Tim_Hou=0 then {也可 tim_hou=0 and tim_sec<60}
   begin
     lbl1.top:=lbl1.top-8;
     Tim_sec:=tim_sec+1;
     if Tim_sec=60 then tmr1.Enabled:=False;
   end;

   if Tim_Min=2 then
   begin
     imgsdo.Canvas.Rectangle(0,0,1000,1000);
     print3Dbrick(5,800,200);
     print3Dbrick(3,800,50+10*tim_sec);
     img1.Picture.Bitmap:=imgsdo.Picture.Bitmap;
     tim_sec:=Tim_sec+1;
   if Tim_sec=12 then begin Tim_Min:=3;Tim_sec:=0;end;
   end;

   if Tim_Min=3 then
   begin
     imgsdo.Canvas.Rectangle(0,0,1000,1000);
     print3Dbrick(5,800,200);
     print3Dbrick(3,800,170);
     print3Dbrick(1,800,50+10*tim_sec);
     img1.Picture.Bitmap:=imgsdo.Picture.Bitmap;
     tim_sec:=Tim_sec+1;
   if Tim_sec=10 then begin Tim_Min:=4;Tim_sec:=0;end;   {不能是9,因为190被200补,160被170补,130没140补}
   end;

 if Tim_Min=4 then
 begin
     if Tim_sec=0 then begin
     
     img2.width:=185;img2.Height:=90;
     img2.Canvas.StretchDraw(img2.ClientRect,hand);
     img2.Left:=900;
     img2.top:=70;
     end;

     img2.Left:=img2.Left-5;
     
     tim_sec:=tim_sec+1;

     if Tim_sec=30 then begin
     tim_min:=5;tim_sec:=1;
     end;
 end;

 end;



end;

procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word;   Shift: TShiftState); begin if Key=69 then Form2.hide;

if (TIM_Hou=0) and (TIM_MIN=0) and (Tim_sec=60) then begin lbl1.Caption:='f**k you';TIM_HOU:=1;TIM_MIN:=1;TIM_SEC:=0;tmr1.Enabled:=true;end;

 

 

end;

2.2.2 分明写法

 

这样写,分层的,先H,然后M,最内一层是S。不难发现sec++这个语句写得太多了,这个,应该说每次进入ontimer都会做的事,为什么要在if语句之中呢?

于是将条件判定语句分为两大块。怎么分?前面是条件判定如何跳转的语句,后面是条件判定其他功能的语句。

 

procedure TForm2.tmr1Timer(Sender: TObject);
begin
tim_sec:=tim_sec+1;
if tim_sec=60 then begin tim_sec=0;tim_min:=tim_min+1;end;
if tim_min=60 then begin tim_min=0;tim_hou:=tim_hou+1;end;

{time frame的变化都集中在以上语句。根据what happen、blocked by写成的判定语句从略}

end;


是的,电子表就是这么干的。但在我们的程序中绝对不行。看了表格也不难发现,每一S是等长的,可每一M、每一H呢?换算率都不固定,三条语句哪里会够?

3:1:48、3:2:36、4:0:0这样的重要转折点必须标出来。

上面的表格也是很不完美的。比如4H,只有一个节点,不分什么M、S,就把四件事一起做了。还有,像2H,里面有三个M,没有S,在2H里sec++的固定操作是失效的,应该暂时改成min++。这是因为老习惯——一开始时间表本来就是只有H的,不存在什么M、S。只是后来处理问题越来越多,为了计算方便,才设了这两个量。于是布置时间表时就喜欢从顶到底。

3、其余阻塞方法

我的章节排列规律是不符合真正的教科书标准的。比如一个话题一共分为三章,那么1、2、3应该覆盖内容互斥,如果第二章分为三节,那么2.1、2.2、2.3之间必须互补。但我的日志可能有:第二章某节谈论过的一个话题,第三章又将其置于放大镜下,详细谈论一遍了。或者在标题3和3.1之间还会隔一段文字,种种与线性阅读严重不符的习惯,所以会给网友带来很多不便。

之间到了阻塞点, 通常我们的做法是:将timer停下来。当用户做好选择后,按键,在按键函数中恢复计时,于是时间继续前行。但有时候是不行的。比如选择画面中有些光标会闪动,怎么办?这时候我的办法时,时间不会停。为了抵消不断增长的sec,于是我加入sec--。至于加在什么位置,如果你是编程的,应该能明白,如果只是翻阅而已,那看不懂这段无所谓,不影响全文中心思想。

当然了,如果内存宽裕,可以再将一个定时器拖进窗体。双表齐下。不,应该三表,做时针、分针、秒针……我没尝试过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值