在Lazarus下的Free Pascal编程教程——在Lazarus中使用计时器组件TTimer

news/2024/12/26 15:29:10/文章来源:https://www.cnblogs.com/lexyao/p/18632986

0.前言

我想通过编写一个完整的游戏程序方式引导读者体验程序设计的全过程。我将采用多种方式编写具有相同效果的应用程序,并通过不同方式形成的代码和实现方法的对比来理解程序开发更深层的知识。

了解我编写教程的思路,请参阅体现我最初想法的那篇文章中的“1.编程计划”和“2.已经编写完成的文章(目录)”:

学习编程从游戏开始——编程计划(目录) - lexyao - 博客园

我已经在下面这篇文章中介绍了使用LCL和FCL组件构建一个项目(pTetris)的过程,后续的使用Lazarus的文章中使用的例子都是以向这个项目添加新功能的方式表述的:

在Lazarus下的Free Pascal编程教程——用向导创建一个使用使用LCL和FCL组件的项目(pTetris) - lexyao - 博客园

在上一篇文章中我们介绍了使用布局组件构建应用程序界面。在界面中用到的组件都是可以看得见的,所以叫做可是组件。在这一篇文章中,我们将会用到另一类组件,一种看不到却在背后默默工作的组件,也叫做非可视组件。

俄罗斯方块游戏中的方块除了游戏玩家有鼠标或者键盘操作的移动、旋转之外,还有有一个不断下落的动作。这个下落的动作是用计时器操作的。在pTetris项目中,有一个叫做TTimer的非可视组件,这就是计时器组件。

在这篇文章里,我主要讲述以下几个方面的内容:

  1. 计时器组件TTimer简介
  2. 向pTetris项目添加一个计时器组件
  3. 计时器组件使用示例
  4. 结束语

了解不同方式实现同样效果的差异,请阅读以下文章:

 

1.计时器组件TTimer简介

每个操作系统都有计时器组件。在Lazarus中计时器组件是TTimer。
TTimer ttimer.png 是 Component Palette 的 System 选项卡上的组件,它提供通常具有毫秒分辨率的计时器。它从 TCustomTimer 继承其大部分属性。它在 ExtCtrls 单元中定义。
以下是Lazarus Wiki和帮助文件中介绍TTimer的网址链接。在看本文下面的内容之前,希望能先看一看Lazarus的介绍。

  • TTimer:帮助文件中的TTimer组件
  • TCustomTimer:TTimer组件的父类
  • TTimer - Free Pascal wiki:wiki中TTimer的示例

从TTimer的帮助文件中,我们看到它定义了以下成员:

属性 Enabled: Boolean; 指示计时器是否已准备好启动。
属性 Interval: Cardinal; 计时器通知的时间间隔 (以毫秒为单位)。
事件 OnTimer: TNotifyEvent;

事件处理程序在计时器的 Interval 已过时发出信号。

事件 OnStartTimer: TNotifyEvent; 事件处理程序在计时器启动时发出信号。
事件 OnStopTimer: TNotifyEvent; 用于停止计时器的事件处理程序。

 

2.向pTetris项目添加一个计时器组件

在Lazaus中向应用程序添加计时器,跟添加其他的可视组件一样,只要在组件面板中双击TTimer图标,一个计时器组件就添加添加到窗体设计器的应用程序的界面中了。
TTimer虽然在运行时看不到,但设计时在窗体设计器中还是能看到它的图标的。这个图标只是表示计时器的存在,它的位置不影响它的使用。通常我们只是为了使用方便把它放到一个自己认为合适的地方。比如:在pTetris项目中我们是用它来控制pnBox中移动的方块的,我们就把它拖放到pnBox上。
在pTetris项目中,我们添加一个TTimer组件,Name属性自动命名为Timer1。记住这个名字,在以后的文章中还会用到。

3.计时器组件使用示例

为了演示计时器的使用,我们添加一个使用计时器事件移动方块的代码。
首先,打开pTetris项目,向主窗口的pnBox中添加一个TPanel组件,Name属性自动设置为Panel1。在属性列表中设置Panel1的属性:

  • 设置Color为clRed,面板表面变为红色
  • 设置Height、Width为17,变成一个17x17的小方块

然后,为计时器组件Timer1添加事件处理代码。在组件列表或窗体设计器中双击Timer1,会看到代码编辑器中添加给TfrmMain添加了一个成员函数。在定义中添加了以下代码:

procedure Timer1Timer(Sender: TObject); 

在实现区域添加了以下代码:

procedure TfrmMain.Timer1Timer(Sender: TObject);
beginend;   

我只需要在实现区域添加定时器动作需要的代码就行了。作为一个演示,在这里我们添加的代码是让小方块Panel1在pnBox中移动,与宝玉道边框后反弹。代码如下:

procedure TfrmMain.Timer1Timer(Sender: TObject);
varxx,yy:integer;
beginif dx=0 then dx:=1;if dy=0 then dy:=1;xx:=Panel1.Left+Panel1.Width*dx;yy:=Panel1.Top+Panel1.Height*dy;if xx<0 thenbegindx:=-dx;xx:=0;endelse if xx>=pnBox.Width-Panel1.Width thenbegindx:=-dx;xx:=pnBox.Width-Panel1.Width;end;if yy<0 thenbegindy:=-dy;yy:=0;endelse if yy>=pnBox.Height-Panel1.Height thenbegindy:=-dy;yy:=pnBox.Height-Panel1.Height;end;Panel1.Left:=xx;Panel1.Top:=yy;
end; 

编译运行pTetris项目,查看运行的效果。这时我们看到pnBox中有一个红色的小方块一直不停地跳动,每隔1秒跳动一次,沿着斜线前进,遇到边框就按45°夹角反弹后继续移动。只要程序不关闭窗口,它会一直跳动。

关闭pTetris项目的运行窗口,在设计器中选中Timer1,在属性列表中修改属性Interval的值,然后重新编译运行,查看有什么变化。
Interval是计时器通知的时间间隔,也就是方块跳动的时间间隔。它是以毫秒计算的。把这个值设置的越小,方块跳动得就越快。

现在看到了方块跳动,也有了改变方块跳动速度的方法,美中不足的是方块一直跳动,就是不停下来。
下面我添加一个新的功能:通过点击pnBox下面的“暂停”按钮,让方块按着我们的意愿停止跳动或者继续跳动。为此,我需要添加一个事件处理程序。
在窗体设计器中双击“暂停”按钮,代码窗口中添加了点击在暂停按钮的事件处理程序,我们添加如下代码:

procedure TfrmMain.btnPauseClick(Sender: TObject);
beginTimer1.Enabled:=not Timer1.Enabled;
end;  

在代码中我们设置Timer1的Enabled属性,让程序运行时,如果方块移动时点击暂停按钮,方块就停止跳动,方块静止时点击暂停按钮,方块又开始跳动。
虽然编译运行后看到了预期的效果,但总是感觉有些别扭:点击“暂停”让方块动起来。如果在方块静止的时候暂停按钮的文字变成“恢复”,我们点击“恢复”让方块恢复跳动,这样是不是更好呢?
为了达到这样的效果,我们再给Timer1添加两个事件处理程序。
在组件列表或窗体设计器中选中Timer1,再点击属性列表中的“事件”,显示出Timer1可用的事件列表。双击前两个事件,在代码中添加两个事件处理函数,然后再添加如下代码:

procedure TfrmMain.Timer1StartTimer(Sender: TObject);
beginbtnPause.Caption:='暂停' ;
end;procedure TfrmMain.Timer1StopTimer(Sender: TObject);
beginbtnPause.Caption:='恢复';
end; 

编译运行,这时我们看到:方块开始跳动时btnPause按钮的标题是“暂停”,方块静止时btnPause按钮的标题是“恢复”。这样用起来就没有困惑了。

在这里也看到了添加事件处理程序的操作方法的不同:
添加Timer1Timer、btnPauseClick时我们时通过双击组件添加的,这是因为他们是组件的默认事件。
添加Timer1StartTimer、Timer1StopTimer是我们是在事件列表中添加的,添加非默认事件都是要这样操作。


4.结束语

在这一篇文章里,我们了解了在Lazarus中使用计时器组件的方法,也了解了添加默认事件和非默认事件处理程序的差别。
编写事件处理程序是图形界面操作系统编程的一个重要的内容。在编写事件处理程序的时候要记住一点:需要长时间操作的事件处理会导致程序停止动作,等待事件处理程序执行完成。在此期间程序就像卡死了一样。为了避免这种假死现象,让操作着感到困惑,通常有两种方案:

  • 显示一个能显示动作进度的界面提示,让操作者指导事情还没有做完,请耐心等待
  • 把耗时很长的操作放入另一个线程中去完成,这样界面就不会卡死了

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/859326.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VMware ESXi 8.0U3c macOS Unlocker OEM BIOS ConnectX-3 网卡定制版 (集成驱动版)

VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS ConnectX-3 网卡定制版 (集成驱动版)VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS ConnectX-3 网卡定制版 (集成驱动版) VMware ESXi 8.0U3c macOS Unlocker & OEM BIOS 集成网卡驱动和 NVMe 驱动 (集成驱动版) 发…

springboot项目启动和部署: 自带tomcat

springboot项目启动: springboot内部嵌入了tomcat,在spring-boot-starter-web里可以找到,在这里插入图片描述这样在研发过程中就不在需要tomcat服务器,并且springboot项目在打完jar之后,可以直接启动也不需要另外的本地tomcat。也就是说拿到springboot项目jar之后,完全可…

python脚本定期删除EFK日志索引

使用pyhon脚本删除50天前的日志pip install Elasticsearch pip install datetime !/usr/bin/python3 from elasticsearch import Elasticsearch from datetime import datetime, timedelta Elasticsearch服务器地址,默认本地为localhost,可按需替换 es_host = "localhos…

私有化部署视频平台EasyCVR小知识:如何测试网络设置对RTSP流效率的影响?

在现代视频监控系统中,RTSP流的效率和在Web端的播放能力是衡量系统性能的关键指标。本文将探讨如何测试网络设置对RTSP流效率的影响,并介绍如何使用EasyCVR平台解决RTSP流在Web端的播放问题,以确保视频监控系统的高效运行和用户体验的优化。一、如何测试网络设置对RTSP流效率…

HTML画布canvas绘制图形,解决拖影问题

在使用HTMl画面 canvas 绘制矩形,圆等图形时,总是出现拖影。 解决这个问题有很多中方法: 方法一:鼠标移动过程中中不画上去,在释放鼠标的时候绘制上去,这样就看不到拖影,但是看不到绘制过程 方法二:在鼠标移动的时候,清除上一次绘制的矩形,然后在画,这样就没有拖影了…

【消息中间件】稳定性建设之SLA浅述

最近参与了部门消息服务的架构升级和稳定性保障,以此文简单总结下当建设和负责维护中间件稳定性时必备的SLA基础知识,一并调研了目前国内外商业化的云消息中间件产品SLA相关情况,最后附上个人在维护消息中间件和支持不同业务场景时的一些通用性粗浅思考,有不恰当的地方欢迎…

以旧换新政策中的数字化协作路径探索

政府发布的《汽车以旧换新补贴政策》为促进汽车消费、优化车辆结构提供了强有力的支持。然而,这一政策的落地实施,涉及多方协同,包括政策文件解读、销售渠道配合、消费者补贴申请等复杂流程。为了应对这些流程的高效管理,企业需要借助数字化协同工具,提升内部及外部的工作…

DataGrip2024.3完整版的安装教程(附激活,常见问题处理)

卸载老版本 DataGrip 首先,如果小伙伴的电脑上有安装老版本的DataGrip , 需要将其彻底卸载掉,如下所示(没有安装则不用管,直接安装即可): TIP:如果你之前使用过本站提供的 激活到 2025 年版本脚本,需要执行对应卸载脚本 /适用2024版本/JetBrains 2023 最新全家桶/jetbra…

HDFS操作02(遇到的问题和解决)

编程实现一个类“MyFSDataInputStream”,该类继承“org.apache.hadoop.fs.FSDataInputStream”,要求如下:实现按行读取HDFS中指定文件的方法“readLine()”,如果读到文件末尾,则返回空,否则返回文件一行的文本。查看Java帮助手册或其它资料,用“java.net.URL”和“org.a…

3083. 字符串及其反转中是否存在同一子字符串

给你一个字符串 s ,请你判断字符串 s 是否存在一个长度为 2 的子字符串,在其反转后的字符串中也出现。 如果存在这样的子字符串,返回 true;如果不存在,返回 false 。 示例 1: 输入:s = "leetcode" 输出:true 解释:子字符串 "ee" 的长度为 2,它也…

19款顶级测试用例管理工具全面解析

在当今数字化飞速发展的时代,软件测试的重要性日益凸显,而一款优秀的测试用例管理工具能够极大地提升测试效率与质量,帮助团队更高效地发现软件中的问题,确保产品的稳定性和可靠性。本文将为您全面解析19款顶级的测试用例管理工具,带您深入了解它们的特点与优势,助您在众…