- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我需要一个通用函数/过程,该函数/过程将根据提供的数据计算出我的淡入淡出时间和值,如下所示:
我将字节值保存在字节数组中:这些是起始值。然后,我在其他数组中存储了一些值:这些将是新值。然后我有时间要提供,这是开始值达到新值所需的时间。
每当值更改时,我都需要获取值的更新(精确到0.1秒)。我知道,如果同时将值A更改为10,将值B更改为100,则假设是1秒钟,我将使值A更新10次,而将值B更新100次。
到目前为止,我一直在计划使用一个定时器,其间隔可以说是50毫秒,它会根据更改的值和所需的时间不断计算差异,例如:change step := (Difference between start and new value / {divided by} (fade time / timer interval) )
。
但是考虑到值变化是不同的,淡入淡出时间也是如此,而且我可以在第一次淡入淡出之前执行另一次淡入淡出的事实,这一切使我感到困惑和困难。
因此,我需要的是一个选项,假设给定索引1、2、3、4、5、6和7的值,并在30秒内将其更改为新值,然后在可以命令索引11、13和17的值在9秒内更改为新值,依此类推...
另外,如果值A会逐渐向值B褪色,并且会命令从A到C的另一次淡入,我希望将其添加到队列列表中,以便在第一次淡入完成后立即执行。那时,第一个命令的B值将成为第二个命令的A值。这是由于以下事实造成的:上面示例中的A应该始终在淡入淡出开始时就被读取。这样,无论在淡入淡出之前还是在淡入淡出命令和淡入淡出执行之间进行了什么操作,它都是一个初始值。因此,我可以将Fade1设置为Current-> B @ 10s,然后将Fade2排队等待Current-> C @ 10s,而第二种情况下的Current实际上是值,否则另存为B,并假设Fade1中的Current与值保存为C。这样,该值将处于回送状态,每10秒更改一次。因此,基本上,添加淡入淡出的命令应仅具有SetNewFade之类的内容:Dest:= B;时间:= 10 ;。
因此,我可以添加-> B @ 10s,-> C @ 10s,-> B @ 10s,-> C @ 10s,它只会从B循环到C,然后反向循环直到队列列表为空。我希望我已经弄清楚了,让您理解。我真的无法更好地描述我需要实现的目标。
另外,由于所有的渐变都会在列表框中提供,因此我希望能够根据需要删除队列中的渐变。但是,如果删除了当前正在运行的淡入淡出,则该值应跳到一个新值,好像淡入淡出已经完成一样,然后通常在队列列表(如果有)中开始新的淡入淡出。
这将是最容易创建的吗?以固定间隔使用Timer是个好主意吗?如果许多值要等待淡入淡出,是否会导致任何延迟?使用动态数组来获取值和时间(并在StartFade事件中填充它们并在褪色完成后释放它们)是在黑暗中拍摄还是很好的猜测?
我希望通过以下示例可以使它更清楚:
A: array [0..20] of Byte;
B: array [0..20] of Byte;
C: array [0..20] of Byte;
Current: array [0..20] of Byte;
StoredVals: array of record;
,
Index: array of Integer
(值的索引;这是用来告诉该记录中存储了哪些值)和
Value: array of Byte;
(这些是褪色的实际值,例如,基于
Current[StoredVals[0].Index[0]]
。Current保留所有值的数据,同时A,B,C等的记录仅保留在该记录内被索引的那些值。
最佳答案
我正在执行一般功能/程序...
实际上,您似乎在追求一个完整的程序。您正在考虑从整体上解决它,而这却是一片白云,这就是为什么您有这么多问题的原因。您需要学习将这项任务分解为较小的部分,并更清楚地总结需求。当前形式的问题已接近主题,可能更适合SE Programmers。但是,由于这正好适合我的小巷,所以我想逐步引导您。
要求
存在一组长度为N的值X。
可以为该集合中的一个或多个值分配一个新值。
从旧值到新值的修改应在特定持续时间内逐步执行。
这导致在此过渡期间产生中间值。
此转换是特定于值/索引的,即X [0]的持续时间可能与X [1]的持续时间不同。
必须先完全完成转换,然后才能分配另一个新值。
在过渡过程中,可能会要求分配新值。
得出的结论是,新请求应存储在队列中,以便在完成转换后,可以从队列中提取新值请求,从而导致新的转换。
我很确定这是您问题的正确摘要。
转场
您建议使用计时器在每个间隔上执行总过渡的一部分是合理的。现在,有两种方法可以计算这些片段:
将总转换划分为固定数量的小转换,将定时器的间隔设置为总持续时间除以该数字,然后处理每个间隔上所有已处理的小转换的总和。这是您在更改步骤的计算中提出的建议。这种方法的缺点是双重的:
计时器的间隔是一个近似值,由于各种原因,它不是精确的,其中一个原因取决于Windows消息传递模型,该模型的计时受许多过程(包括您的,
因此,可能会出现粗糙或不平稳的进度。
在每个间隔重新计算已处理过渡的一部分。这样,无论下一个间隔是否花费两倍以上的时间,进度始终将保持平稳。
首选第二种解决方案,它可以转换为您要寻找的以下常规例程。让我们从假设一个项目开始简单:
function InBetweenValue(BeginValue, EndValue: Byte; Duration,
StartTick: Cardinal): Byte
var
Done: Single;
begin
Done := (GetTickCount - StartTick) / Duration;
if Done >= 1.0 then
Result := EndValue
else
Result := Round(BeginValue + (EndValue - BeginValue) * Done);
end;
InBetweenValue
的结果都是正确的。计时器唯一需要的是驱动进度。如果要67 Hz刷新率,则将其间隔设置为15毫秒。如果您希望刷新频率为20 Hz,则将间隔设置为50毫秒。
TList
。
unit Modulation;
interface
uses
System.SysUtils, System.Classes, System.Generics.Collections, WinAPI.Windows,
VCL.ExtCtrls;
type
TTransition = record
EndValue: Byte;
Duration: Cardinal;
end;
TTransitions = class(TQueue<TTransition>);
TByte = class(TObject)
private
FBeginValue: Byte;
FCurrentValue: Byte;
FEndValue: Byte;
FDuration: Cardinal;
FStartTick: Cardinal;
FTransitions: TTransitions;
procedure PopTransition;
public
procedure AddTransition(ATransition: TTransition);
constructor Create;
destructor Destroy; override;
function HasTransition: Boolean;
function InTransition: Boolean;
procedure Recalculate;
property CurrentValue: Byte read FCurrentValue;
end;
TBytes = class(TObjectList<TByte>);
TByteModulator = class(TObject)
private
FItems: TBytes;
FOnProgress: TNotifyEvent;
FTimer: TTimer;
function Finished: Boolean;
function GetCurrentValue(Index: Integer): Byte;
function GetItemCount: Integer;
procedure SetItemCount(Value: Integer);
procedure Proceed(Sender: TObject);
protected
procedure DoProgress;
public
procedure AddTransition(Index: Integer; ATransition: TTransition);
constructor Create;
destructor Destroy; override;
property CurrentValues[Index: Integer]: Byte read GetCurrentValue; default;
property ItemCount: Integer read GetItemCount write SetItemCount;
property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
end;
implementation
{ TByte }
procedure TByte.AddTransition(ATransition: TTransition);
begin
if ATransition.Duration < 1 then
ATransition.Duration := 1;
FTransitions.Enqueue(ATransition);
Recalculate;
end;
constructor TByte.Create;
begin
inherited Create;
FTransitions := TTransitions.Create;
FDuration := 1;
end;
destructor TByte.Destroy;
begin
FTransitions.Free;
inherited Destroy;
end;
function TByte.HasTransition: Boolean;
begin
Result := FTransitions.Count > 0;
end;
function TByte.InTransition: Boolean;
begin
Result := FCurrentValue <> FEndValue;
end;
procedure TByte.PopTransition;
var
Transition: TTransition;
begin
Transition := FTransitions.Dequeue;
FBeginValue := FCurrentValue;
FEndValue := Transition.EndValue;
FDuration := Transition.Duration;
FStartTick := GetTickCount;
end;
procedure TByte.Recalculate;
var
Done: Single;
begin
Done := (GetTickCount - FStartTick) / FDuration;
if Done >= 1.0 then
begin
FCurrentValue := FEndValue;
if HasTransition then
PopTransition;
end
else
FCurrentValue := Round(FBeginValue + (FEndValue - FBeginValue) * Done);
end;
{ TByteModulator }
const
RefreshFrequency = 25;
procedure TByteModulator.AddTransition(Index: Integer;
ATransition: TTransition);
begin
FItems[Index].AddTransition(ATransition);
FTimer.Enabled := True;
end;
constructor TByteModulator.Create;
begin
inherited Create;
FItems := TBytes.Create(True);
FTimer := TTimer.Create(nil);
FTimer.Enabled := False;
FTimer.Interval := MSecsPerSec div RefreshFrequency;
FTimer.OnTimer := Proceed;
end;
destructor TByteModulator.Destroy;
begin
FTimer.Free;
FItems.Free;
inherited Destroy;
end;
procedure TByteModulator.DoProgress;
begin
if Assigned(FOnProgress) then
FOnProgress(Self);
end;
function TByteModulator.Finished: Boolean;
var
Item: TByte;
begin
Result := True;
for Item in FItems do
if Item.InTransition or Item.HasTransition then
begin
Result := False;
Break;
end;
end;
function TByteModulator.GetCurrentValue(Index: Integer): Byte;
begin
Result := FItems[Index].CurrentValue;
end;
function TByteModulator.GetItemCount: Integer;
begin
Result := FItems.Count;
end;
procedure TByteModulator.Proceed(Sender: TObject);
var
Item: TByte;
begin
for Item in FItems do
Item.Recalculate;
DoProgress;
FTimer.Enabled := not Finished;
end;
procedure TByteModulator.SetItemCount(Value: Integer);
var
I: Integer;
begin
for I := FItems.Count to Value - 1 do
FItems.Add(TByte.Create);
FItems.DeleteRange(Value, FItems.Count - Value);
end;
end.
unit Unit2;
interface
uses
System.SysUtils, System.Classes, Vcl.Controls, Vcl.Forms,
VCL.ComCtrls, VCL.StdCtrls, Modulation;
type
TForm2 = class(TForm)
private
FBars: array of TProgressBar;
FLabels: array of TLabel;
FByteModulator: TByteModulator;
procedure FormClick(Sender: TObject);
procedure Progress(Sender: TObject);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
{ TForm2 }
const
Count = 10;
constructor TForm2.Create(AOwner: TComponent);
var
I: Integer;
begin
inherited Create(AOwner);
FByteModulator := TByteModulator.Create;
FByteModulator.ItemCount := Count;
FByteModulator.OnProgress := Progress;
SetLength(FBars, Count);
SetLength(FLabels, Count);
for I := 0 to Count - 1 do
begin
FBars[I] := TProgressBar.Create(Self);
FBars[I].SetBounds(10, 10 + 30 * I, 250, 25);
FBars[I].Smooth := True;
FBars[I].Max := High(Byte);
FBars[I].Parent := Self;
FLabels[I] := TLabel.Create(Self);
FLabels[I].SetBounds(270, 15 + 30 * I, 50, 25);
FLabels[I].Parent := Self;
end;
OnClick := FormClick;
end;
destructor TForm2.Destroy;
begin
FByteModulator.Free;
inherited Destroy;
end;
procedure TForm2.FormClick(Sender: TObject);
var
Transition: TTransition;
Index: Integer;
begin
Transition.EndValue := Random(High(Byte) + 1);
Transition.Duration := Random(3000);
Index := Random(Count);
FLabels[Index].Caption := Format('%d > %d @ %f',
[FByteModulator.CurrentValues[Index], Transition.EndValue,
Transition.Duration / MSecsPerSec]);
FByteModulator.AddTransition(Index, Transition);
end;
procedure TForm2.Progress(Sender: TObject);
var
I: Integer;
begin
for I := 0 to Count - 1 do
FBars[I].Position := FByteModulator.CurrentValues[I];
end;
initialization
Randomize;
end.
关于delphi - 衰落值常规功能/过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27114481/
我是一名优秀的程序员,十分优秀!