我正在尝试为我的主要表单编写一个单独的单元来调用,除了使用TTimer
的单元之外,我的所有其他单元都在工作。
基本上该函数应该做的是主要表单uDataReceived
调用BlinkRect(Gateway)
,它以rRectControl
为单位处理,相应的Rectangle将以主窗体闪烁。 / p>
以下是代码:
unit uRectControl;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes,
System.Variants, System.IOUtils, FMX.Graphics, FMX.Types, FMX.Objects;
var
Blinks: array [0 .. 2] of record Rectangle: TRectangle;
Timer: TTimer;
end;
type
TMyClass = Class(TObject)
private
Timer1: TTimer;
procedure Timer1Timer(Sender: TObject);
public
procedure BlinkRect(Gateway: integer);
end;
procedure AssignRectangles;
implementation
uses uDataReceived;
// Error shows "Cannot resolve unit name 'uDataReceived'
{ TMyClass }
procedure AssignRectangles;
var
i: integer;
begin
Blinks[0].Rectangle := TC_Theft_Detection.rect1;
// Error shows Undeclared Identifier TC_Theft_Detection (which is the name of the main form)
Blinks[0].Timer := nil;
Blinks[1].Rectangle := TC_Theft_Detection.rect2;
Blinks[1].Timer := nil;
Blinks[2].Rectangle := TC_Theft_Detection.rect3;
Blinks[2].Timer := nil;
for i := 0 to 2 do
Blinks[i].Rectangle.Fill.Color := TAlphacolors.blue;
end;
procedure TMyClass.BlinkRect(Gateway: integer);
begin
Blinks[Gateway].Rectangle.Fill.Color := TAlphacolors.Red;
Blinks[Gateway].Rectangle.Fill.Kind := TBrushKind.Solid;
Blinks[Gateway].Rectangle.Stroke.Thickness := 0.3;
Blinks[Gateway].Rectangle.Stroke.Color := TAlphacolors.Black;
if Blinks[Gateway].Timer = nil then
begin
Blinks[Gateway].Timer := TTimer.Create(nil);
Blinks[Gateway].Timer.OnTimer := Timer1Timer;
Blinks[Gateway].Timer.Interval := 500;
Blinks[Gateway].Timer.Tag := Gateway;
Blinks[Gateway].Timer.Enabled := True;
end;
end;
procedure TMyClass.Timer1Timer(Sender: TObject);
var
Timer: TTimer;
begin
Timer := TTimer(Sender);
Blinks[Timer.Tag].Rectangle.Visible := not Blinks[Timer.Tag]
.Rectangle.Visible;
end;
end.
我知道上面显示的单位一定有问题,我的问题是:
如何在单独的单元中使用TTimer
以及如何在主表单上调用过程BlinkRect(Gateway)
。
非常感谢!!
答案 0 :(得分:4)
uRectControl中的代码在您尝试调用BlinkRect之前调用了AssignRectangles。但是,有许多问题需要解决。
1)单位的交叉依赖
表单(uDataReceived)显然使用uRectControl,这很好。编写uRectControl的方式需要在表单中使用(在实现中使用uDataReceived),这并不好。 此错误很容易纠正,因为AssignRectangles过程是引用表单的唯一位置。 AssignRectangles也可以在表单中,因为Blinks []数组是全局的(在uRectControl的接口中),因此可以通过表单访问。
2)全局变量
应尽可能避免全局变量。您已将Blinks []数组和Timer定义为全局,因此您可能只是通过将uRectControl添加到uses子句中而错误地从程序中的任何位置访问和修改它们。在将来的开发中,您可能会添加具有您想要闪烁的指示符的新表单,并向Blinks []数组添加TRectangles,可能会覆盖已经存在的值,并最终导致混乱。我将在下面的建议中解决这个问题。
3)硬编码实体
在概念验证代码中,硬编码常数,数组大小等是可接受的(或不是),但在生产代码中则不行。只需考虑所有需要做的更改,只需向表单添加一个闪烁的矩形即可。动态阵列或更好的TList及其衍生物等来到这里拯救。你也只限于TRectangles。如果您希望在表单中添加循环指标,该怎么办?
4)未同步闪烁
当指示灯在整个地方闪烁时,它看起来很酷(不是真的),但实际上它只是让人分心。我猜你试图用TMyClass中的计时器来改变它,但是你仍然将个别计时器留在Blinks记录中。我将在下面的建议中解决这个问题。
这是一个建议
unit ShapeBlinker;
interface
uses
System.SysUtils, System.UITypes, System.Classes, System.Generics.Collections,
FMX.Graphics, FMX.Types, FMX.Objects;
type
TBlinkState = (bsOff, bsBlinking, bsSteady);
我有火灾报警系统的背景,通常有三种状态;关闭,闪烁和稳定点亮。 TBlinkState代表了这些。
然后是一个代表UI中指标的类。指标可以是任何TShape衍生物,如TRectangle,TCircle,TPath等。每个州都有自己的颜色。
type
[...]
TBlinkingShape = class
private
FShape: TShape;
FState: TBlinkState;
FOffColor: TAlphaColor;
FBlinkColor: TAlphaColor;
FSteadyColor: TAlphaColor;
public
constructor Create(AShape: TShape);
procedure SetBlinkState(NewState: TBlinkState);
end;
字段FShape包含对TShape衍生物的引用。通过此引用,我们可以访问UI表单上的实际组件,并可以更改其颜色。稍后我们将看到如何将TShape传递给构造函数。
然后是第二个类,它管理表格上指标的TBlinkingShape集合,时间和实际颜色变化。
type
[...]
TShapeBlinker = class
private
FBlinkingShapes: TObjectList<TBlinkingShape>;
FBlinkPhase: integer;
FTimer: TTimer;
public
constructor Create;
destructor Destroy; override;
procedure RegisterShape(Shape: TShape; OffColor, BlinkColor, SteadyColor: TAlphaColor);
procedure UnRegisterShape(Shape: TShape);
procedure BlinkTimer(Sender: TObject);
procedure SetBlinkState(Shape: TShape; NewState: TBlinkState);
function GetBlinkState(Shape: TShape): TBlinkState;
end;
FBlinkingShapes是保存TBlinkingShapes实例的对象列表。 FBlinkPhase同步闪烁指示灯,使所有闪烁指示灯同时变为BlinkColor。 FTimer在所有指标中都很常见。 过程当UI想要向列表添加指示符时,将调用RegisterShape。当要从列表中删除指示符时,将调用UnRegister。 SetBlinkState用于更改状态,GetBlinkState用于检索指标的状态。
该设备可以通过任意数量的形式使用,同步闪烁所有形式。这要求TShapeBlinker是单例。因此,它在单元的初始化部分中创建,并在完成时释放。 实例由实现中的var保存,因此无法直接从任何其他单元访问。访问由声明为单元界面中最后一项的函数提供:
function ShapeBlinker: TShapeBlinker;
这有效地防止了错误地意外调用ShapeBlinker.Create。
我只是在这里复制实现,而不是评论每个方法:
implementation
var
SShapeBlinker: TShapeBlinker;
function ShapeBlinker: TShapeBlinker;
begin
result := SShapeBlinker;
end;
{ TBlinkingShape }
constructor TBlinkingShape.Create(AShape: TShape);
begin
FShape := AShape;
FState := bsOff;
end;
procedure TBlinkingShape.SetBlinkState(NewState: TBlinkState);
begin
FState := NewState;
case NewState of
bsOff: begin
FShape.Fill.Color := FOffColor;
end;
bsBlinking: begin
FShape.Fill.Color := FBlinkColor;
end;
bsSteady: begin
FShape.Fill.Color := FSteadyColor;
end;
end;
end;
{ TShapeBlinker }
constructor TShapeBlinker.Create;
begin
FBlinkingShapes := TObjectList<TBlinkingShape>.Create;
FTimer := TTimer.Create(nil);
FTimer.OnTimer := BlinkTimer;
FTimer.Interval := 500;
FTimer.Enabled := False;
end;
destructor TShapeBlinker.Destroy;
begin
FTimer.Enabled := False;
FTimer.Free;
FBlinkingShapes.Free;
inherited;
end;
function TShapeBlinker.GetBlinkState(Shape: TShape): TBlinkState;
var
RegShape: TBlinkingShape;
begin
result := bsOff;
for RegShape in FBlinkingShapes do
if Shape = RegShape.FShape then result := RegShape.FState;
end;
procedure TShapeBlinker.SetBlinkState(Shape: TShape; NewState: TBlinkState);
var
RegShape: TBlinkingShape;
begin
for RegShape in FBlinkingShapes do
if Shape = RegShape.FShape then RegShape.SetBlinkState(NewState);
self.FTimer.Enabled := True;
end;
procedure TShapeBlinker.BlinkTimer(Sender: TObject);
var
i: integer;
begin
FTimer.Enabled := False;
FBlinkPhase := (FBlinkPhase + 1) mod 2;
for i := 0 to FBlinkingShapes.Count-1 do
with FBlinkingShapes[i] do
begin
case FState of
bsOff: begin
FShape.Fill.Color := FOffColor;
end;
bsBlinking: begin
if FBlinkPhase = 1 then
FShape.Fill.Color := FOffColor // alt. FSteadyColor
else
FShape.Fill.Color := FBlinkColor;
FTimer.Enabled := True;
end;
bsSteady: begin
FShape.Fill.Color := FSteadyColor;
end;
end;
end;
end;
procedure TShapeBlinker.RegisterShape(Shape: TShape; OffColor, BlinkColor, SteadyColor: TAlphaColor);
begin
with FBlinkingShapes[FBlinkingShapes.Add(TBlinkingShape.Create(Shape))] do
begin
FOffColor := OffColor; //TAlphaColors.Silver;
FBlinkColor := BlinkColor; //TAlphaColors.Red;
FSteadyColor := SteadyColor; //TAlphaColors.Yellow;
end;
end;
procedure TShapeBlinker.UnRegisterShape(Shape: TShape);
var
i: integer;
begin
for i := FBlinkingShapes.Count-1 downto 0 do
if FBlinkingShapes[i].FShape = Shape then
FBlinkingShapes.Delete(i);
end;
initialization
SShapeBlinker := TShapeBlinker.Create;
finalization
SShapeBlinker.Free;
end.
最后谈谈用法。考虑一个表格,比如TAlarmView,有2个TRectangle和1个TCircle。 在FormCreate中,您可以将这些注册为闪烁,如下所示
procedure TAlarmView.FormCreate(Sender: TObject);
begin
ShapeBlinker.RegisterShape(Rect1, TAlphaColors.Silver, TAlphaColors.Red, TAlphaColors.Yellow);
ShapeBlinker.RegisterShape(Circle1, TAlphaColors.Silver, TAlphaColors.Red, TAlphaColors.Yellow);
ShapeBlinker.RegisterShape(Rect3, TAlphaColors.Silver, TAlphaColors.Red, TAlphaColors.Yellow);
end;
然后点按
按钮进行测试procedure TAlarmView.Button1Click(Sender: TObject);
begin
case ShapeBlinker.GetBlinkState(Rect1) of
bsOff: ShapeBlinker.SetBlinkState(Rect1, bsBlinking);
bsBlinking: ShapeBlinker.SetBlinkState(Rect1, bsSteady);
else ShapeBlinker.SetBlinkState(Rect1, bsOff);
end;
end;
如您所见,我每次点击都会经历不同的状态。