示例:文本换行
说明:
有许多算法可对一个正文流进行分行。将这些算法硬编进使用它们的类中是不可取的。我们可以定义一些类来封装不同的换行算法,从而避免这些问题。一个以这种方法封装的算法称为一个策略(strategy)。
代码:
unit uComposition;
interface
uses
Windows, Classes, Graphics;
type
TIntArray = array of integer;
TCoord = TPoint;
TCoords = array of TCoord;
TCompositor = class;
{文档元素}
TComponent = class
private
FCanvas: TCanvas;
FNatural: TCoord; //--正常大小(宽、高)
FShrink: TCoord; //--可伸展性
FStretch: TCoord; //--可收缩性
public
constructor Create(ACanvas: TCanvas; ANatural, AStretch, AShrink: TCoord);
//---
procedure Draw(ALineWidth: integer; ABreaks: TIntArray; ABreakCount: integer;
var ABreakIndex: integer); virtual;
//---
property Natural: TCoord read FNatural;
property Stretch: TCoord read FStretch;
property Shrink: TCoord read FShrink;
end;
TComponents = array of TComponent;
TTextComponent = class(TComponent)
private
FText: string;
public
constructor Create(ACanvas: TCanvas; AText: string; ANatural, AStretch, AShrink: TCoord);
//---
procedure Draw(ALineWidth: integer; ABreaks: TIntArray; ABreakCount: integer;
var ABreakIndex: integer); override;
end;
TGraphComponent = class(TComponent)
end;
{文档}
TComposition = class
private
FCompositor: TCompositor;
FComponents: TComponents;
FComponentCount: integer;
//---
FLineWidth: integer;
FLineCount: integer;
FLineBreaks: TIntArray;
public
constructor Create(ACompositor: TCompositor);
destructor Destroy; override;
//---
procedure Add(AComponent: TComponent);
procedure Repair();
//---
property LineWidth: integer read FLineWidth write FLineWidth;
end;
{换行策略}
TCompositor = class
public
function Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer; virtual; abstract;
end;
TSimpleComponentor = class(TCompositor)
public
function Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer; override;
end;
TTeXComponentor = class(TCompositor)
public
function Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer; override;
end;
TArrayComponentor = class(TCompositor)
public
function Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer; override;
end;
procedure Test(ACanvas: TCanvas);
implementation
uses Math;
const
CNT_CHAR_WIDTH = 10;
CNT_CHAR_Height = 20;
procedure Test(ACanvas: TCanvas);
var
ACompositor: TCompositor;
AComposition: TComposition;
//---
procedure _Add(const AText: string);
var
ATextWidth, ATextHeight: Integer;
begin
with AComposition do
begin
ATextWidth := Length(AText) * CNT_CHAR_WIDTH;
ATextHeight := CNT_CHAR_Height;
Add(TTextComponent.Create(
ACanvas, AText,
Point(ATextWidth, ATextHeight),
Point(ATextWidth, ATextHeight - 5),
Point(ATextWidth, ATextHeight + 5)
));
end;
end;
begin
//ACompositor := TSimpleComponentor.Create;
//ACompositor := TTeXComponentor.Create;
ACompositor := TArrayComponentor.Create;
AComposition := TComposition.Create(ACompositor);
try
_Add('aaaaaaaaaaaaaaaaaaaaa');
_Add('bbbbbbbbbbbbbbbbbbbbb');
_Add('aaaaaaaaaaaaaaaaaaaaaa');
_Add('bbbbbbbbbbbbbbbbbbbbbbb');
//---
AComposition.LineWidth := 8 * CNT_CHAR_WIDTH;
AComposition.Repair;
finally
AComposition.Free;
ACompositor.Free;
end;
end;
procedure TComposition.Add(AComponent: TComponent);
begin
SetLength(FComponents, FComponentCount + 1);
FComponents[FComponentCount] := AComponent;
FComponentCount := Length(FComponents);
end;
constructor TComposition.Create(ACompositor: TCompositor);
begin
FCompositor := ACompositor;
FComponentCount := Length(FComponents);
end;
destructor TComposition.Destroy;
//---
procedure _ClearComponents;
var
i: Integer;
begin
for i := Low(FComponents) to High(FComponents) do
FComponents[i].Free;
end;
begin
_ClearComponents;
//---
inherited;
end;
procedure TComposition.Repair();
var
ANatural, AStretchability, AShrinkability: TCoords;
AComponentCount: integer;
ABreaks: TIntArray;
ABreakCount: integer;
//---
procedure _InitParams;
var
i: Integer;
begin
AComponentCount := Length(FComponents);
//---
SetLength(ANatural, AComponentCount);
SetLength(AStretchability, AComponentCount);
SetLength(AShrinkability, AComponentCount);
//---
for i := Low(FComponents) to High(FComponents) do
begin
with FComponents[i] do
begin
ANatural[i] := Natural;
AStretchability[i] := Stretch;
AShrinkability[i] := Shrink;
end;
end;
end;
//---
procedure _DrawComponents;
var
i, ALineIndex: integer;
begin
ALineIndex := 0;
for i := Low(FComponents) to High(FComponents) do
FComponents[i].Draw(FLineWidth, FLineBreaks, FLineCount, ALineIndex);
end;
begin
_InitParams;
//---
ABreakCount := FCompositor.Compose(ANatural, AStretchability, AShrinkability,
AComponentCount, FLineWidth, ABreaks);
FLineCount := ABreakCount;
FLineBreaks := ABreaks;
//---
_DrawComponents;
end;
function TSimpleComponentor.Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer;
var
i,j,AComponentLineCount,ABreakY,ABreakCount:Integer;
//---
procedure _AddBreak;
begin
Inc(ABreakCount);
SetLength(ABreaks,ABreakCount);
//---
ABreaks[ABreakCount - 1] := ABreakY;
end;
begin
ABreakCount := 0;
ABreakY := 0;
//---
for i := 0 to AComponentCount - 1 do
begin
with ANatural[i] do
begin
AComponentLineCount := Ceil(X / ALineWidth);
for j := 0 to AComponentLineCount - 1 do
begin
_AddBreak;
ABreakY := ABreakY + Y;
end;
end;
end;
//---
Result := ABreakCount;
end;
function TTeXComponentor.Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer;
var
i,j,AComponentLineCount,ABreakY,ABreakCount:Integer;
//---
procedure _AddBreak;
begin
Inc(ABreakCount);
SetLength(ABreaks,ABreakCount);
//---
ABreaks[ABreakCount - 1] := ABreakY;
end;
begin
ABreakCount := 0;
ABreakY := 0;
//---
for i := 0 to AComponentCount - 1 do
begin
with ANatural[i] do
AComponentLineCount := Ceil(X / ALineWidth);
//---
for j := 0 to AComponentLineCount - 2 do
begin
_AddBreak;
ABreakY := ABreakY + AStretch[i].Y;
end;
//---
if AComponentLineCount - 1 >= 0 then
begin
_AddBreak;
ABreakY := ABreakY + AShrink[i].Y;
end;
end;
//---
Result := ABreakCount;
end;
function TArrayComponentor.Compose(ANatural, AStretch, AShrink: TCoords;
AComponentCount, ALineWidth: integer; var ABreaks: TIntArray): integer;
const
CNT_LineHeight = 25;
var
i,j,AComponentLineCount,ABreakY,ABreakCount:Integer;
//---
procedure _AddBreak;
begin
Inc(ABreakCount);
SetLength(ABreaks,ABreakCount);
//---
ABreaks[ABreakCount - 1] := ABreakY;
end;
begin
ABreakCount := 0;
ABreakY := 0;
//---
for i := 0 to AComponentCount - 1 do
begin
with ANatural[i] do
AComponentLineCount := Ceil(X / ALineWidth);
for j := 0 to AComponentLineCount - 1 do
begin
_AddBreak;
ABreakY := ABreakY + CNT_LineHeight;
end;
end;
//---
Result := ABreakCount;
end;
constructor TComponent.Create(ACanvas: TCanvas; ANatural, AStretch, AShrink: TCoord);
begin
FCanvas := ACanvas;
FNatural := ANatural;
FStretch := AStretch;
FShrink := AShrink;
end;
procedure TComponent.Draw(ALineWidth: integer; ABreaks: TIntArray; ABreakCount:
integer; var ABreakIndex: integer);
begin
end;
constructor TTextComponent.Create(ACanvas: TCanvas; AText: string; ANatural, AStretch,
AShrink: TCoord);
begin
inherited Create(ACanvas, ANatural, AStretch, AShrink);
//---
FText := AText;
end;
procedure TTextComponent.Draw(ALineWidth: integer; ABreaks: TIntArray;
ABreakCount: integer; var ABreakIndex: integer);
var
i, ALineCount, ALineCharCount: Integer;
ALineText: string;
begin
if ABreakIndex >= ABreakCount then
Exit;
//---
ALineCharCount := ALineWidth div CNT_CHAR_WIDTH;
ALineCount := Ceil(Length(FText) / ALineCharCount);
//---
with FCanvas do
begin
with Font do
begin
Name := '宋体';
Size := 11;
Color := clRed;
end;
//---
for i := 0 to ALineCount - 1 do
begin
ALineText := Copy(FText, ALineCharCount * i + 1, ALineCharCount);
TextOut(10, ABreaks[ABreakIndex], ALineText);
//---
Inc(ABreakIndex);
end;
end;
end;
end.
《GOF设计模式》—策略(STRATEGY)—Delphi源码示例:文本换行
最新推荐文章于 2024-11-02 15:12:27 发布