返回文章列表

FireMonkey圖形動畫與互動設計

本文探討 Delphi FireMonkey 框架的圖形繪製、動畫實作和互動設計技巧。涵蓋了類別輔助方法簡化繪圖、TTimer 與 TStopwatch

Delphi UI/UX設計

FireMonkey 框架為 Delphi 開發者提供了強大的圖形和動畫功能,本文將逐步講解如何運用這些功能開發更具互動性的應用程式。首先,利用類別輔助方法可以簡化繪圖程式碼,提高程式碼的可讀性和維護性。接著,使用 TTimer 元件可以實作基本的動畫效果,而對於需要更高精確度的計時,則可以選擇 TStopwatch。FireMonkey 的父子關係設計簡化了 UI 佈局,形狀元件則提供了豐富的繪圖元素,方便開發者快速構建視覺化介面。此外,動畫元件的屬性設定和插值調整,可以更精細地控制動畫效果。最後,透過處理觸控事件和手勢,可以讓應用程式更具互動性,提升使用者經驗。

FireMonkey 圖形繪製與動畫實作

在 Delphi 的 FireMonkey 框架中,圖形繪製和動畫實作是非常重要的功能。本文將探討如何使用 FireMonkey 進行圖形繪製和動畫實作,並提供詳細的程式碼範例和解析。

使用類別輔助方法簡化繪圖程式碼

首先,我們可以透過建立類別輔助方法(Class Helper)來簡化 FireMonkey 中的繪圖程式碼。以下是一個範例:

TFmxCanvasHelper = class helper for TCanvas
public
  procedure SolidRect(ARect: TRectF; AColor: TColor);
  procedure Line(A, B: TPointF; AColor: TColor; AThickness: Single);
  procedure SolidCircle(A: TPointF; R: Double; AColor: TColor);
end;

procedure TFmxCanvasHelper.SolidRect(ARect: TRectF; AColor: TColor);
begin
  Fill.Color := AColor;
  FillRect(ARect, 0, 0, [], DEFAULT_OPACITY);
end;

procedure TFmxCanvasHelper.Line(A, B: TPointF; AColor: TColor; AThickness: Single);
begin
  Stroke.Color := AColor;
  Stroke.Kind := TBrushKind.bkSolid;
  Stroke.Thickness := AThickness;
  DrawLine(A, B, DEFAULT_OPACITY);
end;

procedure TFmxCanvasHelper.SolidCircle(A: TPointF; R: Double; AColor: TColor);
begin
  var ARect := RectF(A.X-R, A.Y-R, A.X+R, A.Y+R);
  Fill.Color := AColor;
  Fill.Kind := TBrushKind.Solid;
  FillEllipse(ARect, DEFAULT_OPACITY);
end;

程式碼解析:

  • SolidRect 方法用於繪製一個實心矩形。
  • Line 方法用於繪製一條直線。
  • SolidCircle 方法用於繪製一個實心圓。

這些方法簡化了在 FireMonkey 中進行基本圖形繪製的程式碼,使得開發者可以更輕鬆地建立複雜的圖形效果。

使用 TTimer 元件實作動畫效果

為了實作動畫效果,我們可以使用 TTimer 元件。以下是一個範例,展示瞭如何使用 TTimer 元件來模擬日出效果:

TFormSunCodeAnim = class(TForm)
  PaintBox1: TPaintBox;
  Timer1: TTimer;
  procedure PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
  procedure Timer1Timer(Sender: TObject);
  procedure FormCreate(Sender: TObject);
private
  FSunPosY: Double;
end;

procedure TFormSunCodeAnim.FormCreate(Sender: TObject);
begin
  FSunPosY := self.Height + 150;
end;

procedure TFormSunCodeAnim.Timer1Timer(Sender: TObject);
begin
  if FSunPosY > END_SUN_POS_Y then
    FSunPosY := FSunPosY - 10;
  Invalidate;
end;

procedure TFormSunCodeAnim.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
  Canvas.BeginScene;
  try
    Canvas.SolidRect(PaintBox1.BoundsRect, TAlphaColorRec.Skyblue);
    var X := POS_X;
    var Y := FSunPosY;
    Canvas.SolidCircle(PointF(X, Y), SUN_RADIUS, TAlphaColorRec.Yellow);
    for var I := 0 to RAY_COUNT-1 do
    begin
      var Angle := I * Pi * 2 / RAY_COUNT;
      var A := PointF(X, Y);
      var B := PointF(x + RAY_LENGTH * Cos(Angle), y + RAY_LENGTH * Sin(Angle));
      Canvas.Line(A, B, TAlphaColorRec.Yellow, 5);
    end;
  finally
    Canvas.EndScene;
  end;
end;

程式碼解析:

  • FormCreate 事件初始化太陽的初始位置。
  • Timer1Timer 事件處理程式更新太陽的位置並使畫布無效以觸發重繪。
  • PaintBox1Paint 事件處理程式根據當前太陽的位置繪製天空、太陽和太陽的光芒。

精確計時與動畫控制

雖然 TTimer 元件可以滿足大部分的動畫需求,但在某些需要精確計時的場合,例如物理引擎模擬,我們需要使用更精確的計時方法。TStopwatch 是 Delphi 提供的一個用於精確計時的結構。以下是一個範例:

TFormTiming = class(TForm)
  Timer1: TTimer;
  procedure FormCreate(Sender: TObject);
  procedure Timer1Timer(Sender: TObject);
private
  FLastTime: Double;
end;

procedure TFormTiming.FormCreate(Sender: TObject);
begin
  TStopwatch.StartNew;
  Log('Stopwatch Frequency = ' + TStopwatch.Frequency.ToString);
end;

function TFormTiming.GetRawReferenceTime: Double;
begin
  Result := TStopwatch.GetTimeStamp / TStopwatch.Frequency;
end;

procedure TFormTiming.Timer1Timer(Sender: TObject);
var
  T, Elapsed: Double;
begin
  T := GetRawReferenceTime;
  Elapsed := T - FLastTime;
  FLastTime := T;
  Log('T=' + T.ToString + ' Elapsed=' + Elapsed.ToString);
end;

程式碼解析:

  • GetRawReferenceTime 方法傳回自 TStopwatch 開始以來經過的時間(以秒為單位)。
  • Timer1Timer 事件處理程式計算每次觸發之間的時間間隔,並記錄下來。

透過使用 TStopwatch,我們可以獲得比 TTimer 更精確的時間控制,從而滿足對時間敏感的應用需求。

使用FireMonkey進行精確計時與視覺化設計

精確計時範例解析

在開發高效能應用程式時,精確的計時功能至關重要。透過FireMonkey框架,我們可以輕鬆實作毫秒級的計時精確度。即使在一個幾乎空的應用程式中,計時器的準確度也可以達到幾毫秒。在更複雜的應用程式中,差異可能會更大。

FireMonkey的父子關係威力

FireMonkey的架構設計中,父子關係(Parenting)是一個非常強大的特性。任何FireMonkey元件都可以包含其他元件,這種包含關係使得子元件繼承父元件的屬性,如位置、縮放比例和旋轉角度。這種特性為建立複雜的使用者介面提供了極大的靈活性,因為我們可以建立組合控制項而無需宣告全新的類別。

使用形狀元件進行繪圖

FireMonkey提供了豐富的形狀(Shape)元件,如直線、圓形、橢圓、矩形等,這些元件封裝了畫布上的繪圖功能,大大減少了低階繪圖程式碼的撰寫。

重建太陽視覺化範例

  1. 新增一個Form HD元素到專案中。
  2. 放置一個TRectangle元件在表單上,並將其與客戶區域對齊。將其Name屬性設為RectSky,並將其Fill.Color設為天空藍色。
  3. 放置一個TCircle元件在表單上,命名為CircleSun。調整其WidthHeight屬性為100,將其位置設在畫面的左上角。
  4. 變更CircleSunFill.ColorStroke.Color為黃色。

新增太陽光芒

  1. 選取太陽的圓形元件,然後在其上放置一個TLine元件,命名為LineRay01
  2. 設定LineRay01LineType為Top,使其成為水平線。調整其WidthHeightStroke.ColorThickness屬性。
  3. 確保TLine元件是TCircle的子元件,這樣其屬性會相對於父元件。

旋轉太陽光芒

  1. 複製LineRay01並貼上到CircleSun下,調整新線條的RotationAngle屬性以實作旋轉效果。
  2. 變更RotationCenter屬性以控制旋轉中心。
  3. 重複此過程以建立多條太陽光芒,最終實作具有12條光芒的太陽視覺效果。

動畫設計

FireMonkey提供了強大的動畫元件,可以輕鬆實作屬性的動態變更。無需撰寫計時器相關程式碼,即可實作背景執行緒中的動畫效果。

新增動畫至太陽圓形元件

  1. 在Object Inspector中展開CircleSunPosition.Y屬性。
  2. 選擇「Create New TFloatAnimation」以建立一個新的浮點數動畫元件。
  3. 這樣就實作了對CircleSun位置的動態變更,從而實作了太陽升起的動畫效果。

程式碼解析

// 無需手動撰寫動畫相關程式碼,FireMonkey的視覺化設計工具已經處理了大部分工作。
// 以下是一個簡單的範例,展示如何以程式設計方式控制動畫:
// 假設FloatAnimation1是繫結到CircleSun的Position.Y屬性的動畫元件
FloatAnimation1.StartValue := 200; // 起始值
FloatAnimation1.StopValue := 50;   // 結束值
FloatAnimation1.Duration := 5;     // 動畫持續時間(秒)
FloatAnimation1.Start;             // 啟動動畫

內容解密:

  • FloatAnimation1.StartValueStopValue定義了動畫的起始和結束值。
  • Duration屬性控制動畫的持續時間。
  • Start方法用於啟動動畫。

強化 FireMonkey 應用程式的互動性

FireMonkey 為開發者提供了豐富的工具和元件,讓我們能夠輕鬆建立動態且互動性強的應用程式。在本章中,我們將探討如何利用 FireMonkey 的動畫元件和觸控事件,來創造更具吸引力和使用者友好的應用程式。

使用動畫元件

動畫是提升應用程式視覺吸引力的關鍵元素。FireMonkey 提供了 TFloatAnimation 這樣的動畫元件,讓我們能夠輕鬆地為應用程式新增動畫效果。讓我們透過一個簡單的例子來瞭解如何使用動畫元件。

設定動畫屬性

在設計階段,我們可以使用 Object Inspector 來設定動畫元件的屬性。例如,對於一個 TFloatAnimation 元件,我們可以設定其 DurationEnabledStopValueStartValue 等屬性。

  • Duration 設定為 2 秒,控制動畫的播放時間。
  • Enabled 設定為 True,使動畫在應用程式啟動時自動開始。
  • 設定 StopValue 為 100 和 StartValue 為 600,定義動畫的起始和結束值。

我們也可以在程式碼中動態設定 StartValue,以適應不同的螢幕高度。例如:

procedure TFormSunCompAnim.FormCreate(Sender: TObject);
begin
  FloatAnimation1.StartValue := RectSky.Height + 150;
end;

調整插值方式

動畫的插值方式(Interpolation)決定了動畫值的變化方式。預設情況下,TFloatAnimation 使用線性插值(Linear)。我們可以將其更改為正弦插值(Sinusoidal),以獲得更自然的動畫效果。

處理觸控事件

FireMonkey 表單支援處理簡單觸控、多點觸控和手勢事件。這些功能使我們能夠建立更具互動性的應用程式。

觸控事件處理

在 FireMonkey 中,表單和控制元件都支援觸控事件。當使用者觸控螢幕時,會觸發 OnMouseDown 事件;當觸控點改變或結束時,分別會觸發 OnMouseMoveOnMouseUp 事件。

讓我們透過修改 Sun 應用程式來示範如何處理觸控事件,以允許使用者改變太陽的位置。

  1. 宣告必要的欄位:在表單類別中宣告私有欄位 FReadyFDownFMoving,以追蹤太陽的移動狀態和初始觸控點。
type
  TFormSunMove = class(TForm)
    // ...
  private
    FReady: Boolean;
    FDown: TPointF;
    FMoving: Boolean;
  end;
  1. 初始化和完成事件:在 OnCreate 事件中初始化 FReady 為 False,並在動畫的 OnFinish 事件中將其設定為 True,以確保使用者只能在動畫完成後移動太陽。
procedure TFormSunMove.FormCreate(Sender: TObject);
begin
  FReady := False;
  FloatAnimation1.StartValue := RectSky.Height + 150;
end;

procedure TFormSunMove.FloatAnimation1Finish(Sender: TObject);
begin
  FReady := True;
end;
  1. 處理滑鼠事件:實作 OnMouseDownOnMouseUp 事件,以控制太陽的移動。
procedure TFormSunMove.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  if FReady then
  begin
    FDown := PointF(X, Y);
    FMoving := True;
  end;
end;

procedure TFormSunMove.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  if FMoving then
  begin
    CircleSun.Position.X := CircleSun.Position.X + (X - FDown.X);
    CircleSun.Position.Y := CircleSun.Position.Y + (Y - FDown.Y);
    FMoving := False;
  end;
end;

圖表翻譯:

此圖示描述瞭如何在 Object Inspector 中設定互動式手勢。 此圖示呈現了在 FireMonkey 中設定旋轉手勢的過程,使用者可以透過這個手勢對應用程式中的物件進行旋轉操作。

使用手勢

FireMonkey 支援處理標準和互動式手勢。讓我們為 Sun 演示應用程式新增旋轉手勢支援。

  1. 啟用旋轉手勢:在 Object Inspector 中選擇表單,並展開其 Touch 屬性。勾選 Rotate 手勢下的 Interactive Gestures 子屬性。

  2. 處理手勢事件:雙擊表單的 OnGesture 事件,並實作事件處理函式,以回應旋轉手勢。

// OnGesture 事件處理範例
procedure TFormSunMove.FormGesture(Sender: TObject; const EventInfo: TGestureEventInfo; var Handled: Boolean);
begin
  // 處理旋轉手勢
  if EventInfo.GestureID = igiRotate then
  begin
    // 在此新增旋轉邏輯
  end;
end;

圖表翻譯:

此圖示顯示瞭如何在 FireMonkey 中組態互動式手勢。 透過此圖示,使用者可以瞭解如何為應用程式新增旋轉手勢,從而實作更豐富的互動體驗。