Delphi 平行程式函式庫(PPL)賦予開發者有效管理非同步操作的能力,藉由 Task 和 Future 機制,提升應用程式回應速度與效能。FireMonkey 作為跨平臺 UI 解決方案,提供強大的 2D 和 3D 繪圖功能。在 PPL 中,Task 代表可平行執行的作業單元,Future 則能傳回計算結果,有效運用多核心處理器。FireMonkey 的 TCanvas 則負責跨平臺圖形繪製,本文將示範如何在 TPaintBox 的 OnPaint 事件中使用 TCanvas 繪製圖形,包含藍天、太陽和光芒等元素。為了簡化繪圖程式碼,我們將運用類別輔助器擴充 TCanvas 的功能,提供更直覺的繪圖方法,提升程式碼可讀性和維護性,並利用流程圖清晰展示繪圖步驟和邏輯。

Delphi平行程式設計與FireMonkey繪圖技術解析

Delphi的平行程式函式庫(PPL)為開發者提供了高效能的多執行緒程式設計能力,透過Task和Future機制,能夠有效地管理非同步操作,提升應用程式的回應速度和整體效能。同時,FireMonkey框架作為Delphi的跨平臺UI解決方案,提供了強大的2D和3D繪圖功能。本文將深入探討PPL的核心概念、Future的應用,以及FireMonkey的繪圖機制,並透過實際範例展示如何使用TCanvas進行圖形繪製。

深入理解Delphi的平行程式函式庫

Delphi的PPL提供了一套完整的平行程式設計工具,讓開發者能夠充分利用多核心處理器的運算能力。透過將耗時的操作放到背景執行緒執行,可以顯著提升應用程式的回應速度。

任務與未來的基礎概念

PPL中的Task和Future是實作平行程式設計的核心元件。Task代表了一個可平行執行的作業單元,而Future則是Task的一種特殊形式,能夠傳回計算結果。

任務的基本使用

Task允許開發者將耗時的操作封裝在獨立的執行緒中執行,避免阻塞主執行緒。以下是一個基本的Task使用範例:

var
 執行緒任務: ITask;
begin
 執行緒任務 := TTask.Run(procedure
 begin
   // 執行耗時操作
   執行長時間運算(200);
 end);
end;

內容解密:

  1. 建立Task物件:透過TTask.Run方法建立一個新的Task例項。
  2. 定義執行內容:在匿名方法中定義需要在背景執行緒執行的程式碼。
  3. 自動啟動任務:Task建立後會自動開始執行,無需手動呼叫啟動方法。

未來的應用

Future機制允許開發者取得平行計算的結果。透過TTask.Future方法,可以建立一個傳回特定型別結果的平行任務。

var
 計算結果: IFuture<Double>;
begin
 計算結果 := TTask.Future<Double>(function: Double
 begin
   Result := 執行長時間運算(200);
 end);

 // 取得計算結果
 var 結果值 := 計算結果.Value;
end;

內容解密:

  1. 建立Future物件:使用TTask.Future方法建立一個傳回Double型別結果的Future。
  2. 定義計算邏輯:在匿名函式中實作具體的計算過程。
  3. 取得結果:透過Value屬性取得計算結果,若計算未完成則會阻塞等待。

使用Future實作平行計算

Future的一個重要應用場景是平行執行多個獨立的計算任務。以下範例展示瞭如何使用Future平行計算多個值:

var
 第一值, 第二值, 第三值: IFuture<Double>;
begin
 第一值 := TTask.Future<Double>(function: Double
 begin
   Result := 執行長時間運算(200);
 end);

 第二值 := TTask.Future<Double>(function: Double
 begin
   Result := 執行長時間運算(300);
 end);

 第三值 := TTask.Future<Double>(function: Double
 begin
   Result := 執行長時間運算(400);
 end);

 var 總和 := 第一值.Value + 第二值.Value + 第三值.Value;
end;

內容解密:

  1. 平行建立多個Future:同時建立多個Future物件並啟動平行計算。
  2. 取得各個計算結果:透過存取各個Future的Value屬性取得計算結果。
  3. 彙總計算結果:將各個Future的結果進行彙總處理。

透過平行計算,可以將原本需要順序執行的耗時操作(總耗時約900毫秒)縮短到約400毫秒(最長的單個操作耗時),顯著提升了整體效能。

FireMonkey繪圖技術詳解

FireMonkey是Delphi的跨平臺UI框架,提供了強大的2D和3D繪圖功能。透過TCanvas抽象類別,FireMonkey實作了跨平臺的圖形繪製能力。

TCanvas繪圖基礎

在FireMonkey中,TCanvas是進行2D繪圖的核心類別。通常需要在TPaintBoxOnPaint事件處理函式中進行繪圖操作:

procedure TForm1.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
 Canvas.BeginScene;
 try
   // 繪圖程式碼
 finally
   Canvas.EndScene;
 end;
end;

繪製基本圖形

以下範例展示瞭如何使用TCanvas繪製一個簡單的場景(藍天和太陽):

const
 預設透明度 = 1;
 太陽X = 150;
 太陽Y = 150;
 太陽半徑 = 50;
 光芒數量 = 12;
 光芒長度 = 100;

procedure TFormSun.PaintBox1Paint(Sender: TObject; Canvas: TCanvas);
begin
 Canvas.BeginScene;
 try
   // 繪製藍天
   Canvas.FillRect(PaintBox1.BoundsRect, 0, 0, [], 預設透明度);

   // 繪製太陽
   var 太陽中心 := PointF(太陽X, 太陽Y);
   var 太陽區域 := RectF(太陽中心.X - 太陽半徑, 太陽中心.Y - 太陽半徑, 
                        太陽中心.X + 太陽半徑, 太陽中心.Y + 太陽半徑);
   Canvas.Fill.Kind := TBrushKind.Solid;
   Canvas.FillEllipse(太陽區域, 預設透明度);

   // 繪製太陽光芒
   Canvas.Stroke.Kind := TBrushKind.Solid;
   Canvas.Stroke.Thickness := 5;
   for var i := 0 to 光芒數量 - 1 do
   begin
     var 角度 := i * Pi * 2 / 光芒數量;
     var 起點 := 太陽中心;
     var 終點 := PointF(太陽中心.X + 光芒長度 * Cos(角度), 
                       太陽中心.Y + 光芒長度 * Sin(角度));
     Canvas.DrawLine(起點, 終點, 預設透明度);
   end;
 finally
   Canvas.EndScene;
 end;
end;

內容解密:

  1. 繪製背景:使用FillRect方法繪製整片天空區域。
  2. 繪製太陽:透過FillEllipse方法繪製太陽的圓形。
  3. 繪製光芒:使用DrawLine方法根據計算出的角度繪製太陽的光芒線條。

簡化繪圖程式碼的實作

為了提高繪圖程式碼的可讀性和可維護性,可以使用類別輔助器擴充TCanvas的功能:

type
 TCanvasHelper = class helper for TCanvas
 public
   procedure 繪製線條(起點, 終點: TPointF; 顏色: TColor; 線寬: Single = 1);
   procedure 繪製實心矩形(區域: TRectF; 顏色: TColor = TAlphaColorRec.White);
   procedure 繪製實心圓形(中心: TPointF; 半徑: Double; 顏色: TColor);
 end;

procedure TCanvasHelper.繪製線條(起點, 終點: TPointF; 顏色: TColor; 線寬: Single = 1);
begin
 Self.Stroke.Kind := TBrushKind.Solid;
 Self.Stroke.Thickness := 線寬;
 Self.DrawLine(起點, 終點, 1);
end;

procedure TCanvasHelper.繪製實心圓形(中心: TPointF; 半徑: Double; 顏色: TColor);
var
 區域: TRectF;
begin
 區域 := RectF(中心.X - 半徑, 中心.Y - 半徑, 中心.X + 半徑, 中心.Y + 半徑);
 Self.Fill.Kind := TBrushKind.Solid;
 Self.FillEllipse(區域, 1);
end;

圖表翻譯:

  1. 擴充TCanvas功能:透過類別輔助器新增了多個實用的繪圖方法。
  2. 簡化繪圖程式碼:將複雜的繪圖操作封裝成簡單的方法呼叫。
  3. 提高可讀性:使繪圖程式碼更加直觀易懂。

繪圖流程

@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Delphi平行程式設計與FireMonkey繪圖解析

package "系統架構" {
    package "前端層" {
        component [使用者介面] as ui
        component [API 客戶端] as client
    }

    package "後端層" {
        component [API 服務] as api
        component [業務邏輯] as logic
        component [資料存取] as dao
    }

    package "資料層" {
        database [主資料庫] as db
        database [快取] as cache
    }
}

ui --> client : 使用者操作
client --> api : HTTP 請求
api --> logic : 處理邏輯
logic --> dao : 資料操作
dao --> db : 持久化
dao --> cache : 快取

note right of api
  RESTful API
  或 GraphQL
end note

@enduml

圖表翻譯:

此圖示展示了繪圖流程的主要步驟。首先判斷是否需要繪製背景,若需要則先繪製藍天背景。接著準備繪製前景元素,包括繪製太陽的圓形主體和光芒效果。最後完成整個繪圖流程。透過這個流程圖,可以清晰地理解繪圖操作的順序和邏輯關係。