Delphi GDI對象之繪制文本


基本繪圖操作(Basic Drawing Operations)

現在大家已經知道Rectangle方法用來畫正方形和矩形,Ellipse方法用來畫圓和橢圓,MoveTo和LineTo方法則用來畫線。

還有Arc方法用於畫弧,Pie方法用於畫餅形,一切一切都是非常基礎的,沒有太大的必要詳細了解TCanvas的這些方法,下面開始更有趣的圖形操作,這些圖形操作在編寫Delphi應用程序時很可能遇到。

 

繪制文本(Drawing Text)

繪制文本聽起來不像太難,是么?實際上有一些容易犯的小錯誤,如果不加注意,可能會使繪制文本變得很困難,另外有幾條好的文本繪制特性應該了解。

1、TextOut與TextRect方法(The TextOut and TextRect Methods)

TextOut方法是在畫布上繪制文本的最基本的方法,關於TextOut沒有太多可講的,只需輸入X,Y位置和要顯示的文本——例如:

  Canvas.TextOut(20, 20, '最簡單的文本輸出');

這個代碼在窗體上位置20,20處顯示指定的字符串。

image


X、Y坐標是指所要繪制文本的左上角而不是底線,為了說明這個意思,試驗這段代碼:

  Canvas.TextOut(20, 20, 'This is a text');
  Canvas.MoveTo(20, 20);
  Canvas.LineTo(100, 20);

這段代碼(20,20)處顯示一些文字並從這個位置到(100,20)畫線。如下圖,顯示了這段代碼的執行結果。注意直線畫在文本上部。

image

每當要顯示文本時,使用TextOut不需要許多精確定位。


TextRect方法要求指定要顯示的文本,還要指定剪切矩形框。當文本需要限制在一定的界域內時使用這種方法。落在界線外的文本均被剪掉,下面代碼確保顯示不超過100像素的文本。

  Canvas.TextRect(Rect(20, 50, 120, 70), 20, 50,
    '這是非常長的一行文字,可能會被裁減掉');

顯示如下,因為字符串長度超過了100像素,因此被裁減掉了。

image

TextOut和TextRect都只能繪制單行文字,不能對文本進行換行。

Tip

To draw text with tab stops, see the Windows API function TabbedTextOut.

輸出具有制表符的文本,參見Windows API函數TabbedTextOut。

2、文本背景(Text Backgrounds)

改變文本背景顏色是非常容易的,因此可以這樣做,如下代碼:

Canvas.Brush.Color := clWhite;

顯示效果如下:

image


在進行設置背景色的時候應該養成這種習慣,即先存儲先前的刷子類型,處理完文本后再恢復到原來的類型。代碼如下:

var
  OldStyle: TBrushStyle;
  OldColor: TColor;
begin
  ClearCanvas;
  OldStyle := Canvas.Brush.Style;
  OldColor := Canvas.Brush.Color;
  Canvas.Brush.Color := clRed;
  Canvas.TextOut(20, 20, '現在文本的背景色為紅色了');
  Canvas.Brush.Style := OldStyle;
  Canvas.Brush.Color := OldColor;
  Canvas.TextOut(20, 50, '現在又恢復原始的樣式了');
end;

顯示效果如下:

image

如果要使用文本透明背景,可將刷子類型設置為bsClear。如下代碼:

  Canvas.Brush.Style := bsClear;

使用透明背景還有其他好處,比如說要在圖像背景上顯示一些文本,在這種情況下,使用透明背景輸出文本比較理想,代碼如下:

var
  OldStyle: TBrushStyle;
  Bitmap: TBitmap;
begin
  Bitmap := TBitmap.Create;
  Bitmap.LoadFromFile('handshak.bmp');
  Canvas.Draw(0, 0, Bitmap);
  Canvas.Font.Name := 'Arial Bold';
  Canvas.Font.Size := 13;
  OldStyle := Canvas.Brush.Style;
  Canvas.Brush.Style := bsClear;
  Canvas.TextOut(20, 5, '透明背景色文本');
  Canvas.Brush.Style := OldStyle;
  Canvas.TextOut(20, 30, '非透明背景色文本');
  Bitmap.Free;
end;

這個代碼在窗體上畫位圖,之后在窗體位圖上用透明背景繪制文本,在以常規樣式繪制文本,效果如下:

image


3、DrawText函數(The DrawText Function)

Windows API的DrawText函數提供了比TextOut更大的制作畫布上的文本的控制能力,基於某種原因,TCanvas類沒有DrawText方法。使用DrawText則意味着直接使用API。首先看一看一個基本的DrawText例子,然后再講述這個函數的更多用途。

var
  R: TRect;
begin
  R := Rect(20, 20, 220, 80);
  Canvas.Rectangle(20, 20, 220, 80);
  DrawText(Canvas.Handle, 'An example of DrawText.', -1, R,
    DT_SINGLELINE or DT_VCENTER or DT_CENTER);
end;

下圖顯示了該代碼結果以及下面幾個例子的結果。

image

首先TRect記錄利用Windows API Rect函數初始化。之后,一個規則的矩形繪制於畫布上(矩形畫於畫布上以便可以設想所要畫的矩形大小)。最后,調用DrawText函數繪制文本。

//DrawText函數的聲明如下:
DrawText(
  hDC: HDC;          {設備句柄}
  lpString: PChar;   {文本}
  nCount: Integer;   {要繪制的字符個數; -1 表示全部}
  var lpRect: TRect; {矩形結構}
  uFormat: UINT      {選項}
): Integer;          {返回文本高度}

下面詳解討論下函數的各種參數,如下所示:

  • 第一個參數用來指定繪制的設備描述環境。TCanvas的Handle屬性是畫布的HDC。因此輸入它作為第一參數。
  • 第二個參數是將要顯示的字符串。
  • 第三個參數是用於指定要繪制的字符數,但參數為-1時,字符串中所有字符都繪制。
  • 第四個參數是var TRect,這個參數是var參數,因為DrawText操作修改矩形。
  • 最后一個參數是指定繪制文本時使用的標志,在這個例子中使用了DT_SINGLELINE(單行文本)、DT_VCENTER(垂直居中)和DT_CENTER(水平居中)標志。DrawText一共有將近20個標志可供指定。這里不打算講每一個標志,全部標志參見Win32 API幫助。

前面的例子說明了DrawText函數一個最為普遍的用途;使文本水平居中、垂直居中等。在自制組件時這個特性非常有用。特別地,自制列表框、組合框和菜單經常需要使文本居中。現在可能不會馬上認識到這個函數的好處。但是,若開始做自制組件時或者開始寫自己的圖形組件時,就會認識到這一點。

DrawText另一個有趣的標志是DT_END_ELLIPSIS標志,如果文本太長不能套入指定矩形中,Windows將截取部分字符串,末尾加上省略號,表示字符串被截取,例如,下面的代碼:

var
  R: TRect;
begin
  R := Rect(20, 20, 120, 70);
  DrawText(Canvas.Handle, 'This text is too long to fit', -1, R, DT_END_ELLIPSIS);
end;
這段執行后,結果文本顯示如下圖:

image

如果矩形內文本可能太長的話,可以使用這種標志。


DT_CALCRECT是又一個非常有用的標志,它用來計算容納指定文本所需的矩形高度。當使用這個標志時,Windows計算所需高度,並返回這個高度,但不繪制文本。用戶告訴Windows矩形框應多寬,Windows將告訴用戶容納的文本所需矩形多高。事實上,Windows也修改矩形的bottom和left值。繪制多行文本時,這顯的尤為重要。

下列程序例子詢問Windows要包含所有文本所需的矩形框多高。之后,在屏幕上畫出矩形框,最后文本繪制在矩形框中。代碼如下:

var
  R: TRect;
  S: string;
begin
  R := Rect(20, 20, 150, 30);
  S := 'This is a very long string which will' +
    'run into multiple lines of text.';
  DrawText(Canvas.Handle, PChar(S), -1, R, DT_CALCRECT or DT_WORDBREAK);
  Canvas.Brush.Style := bsSolid;
  Canvas.Rectangle(R);
  Canvas.Brush.Style := bsClear;
  DrawText(Canvas.Handle, PChar(S), -1, R, DT_WORDBREAK);
end;
最后運行該代碼,效果如下:

image

注意,必須將DrawText的第二個參數由string類型轉化為PChar類型,這是因為DrawText需要的參數是指向字符數組的指針,而不是字符串類型本身。

將上面的代碼進行多次執行,每次修改顯示的字符串長度。不管怎么增加字符,矩形框總能准確框住文本。

Note

如果編寫適應各種版本的Delphi程序,就不能像上面那樣將string強制轉化為PChar類型,因為Delphi1下不能編譯,必須采用StrPCopy函數來使用,代碼如下:

procedure TForm1.btn10Click(Sender: TObject);
var
  R: TRect;
  S: string;
  temp: array[0..100] of Char; { 至少要有 length(s) + 1 的空間大小}
begin
  R := Rect(20, 20, 150, 30);
  S := 'This is a very long string which will' +
    'run into multiple lines of text.';
  { 采用StrPCopy函數轉化string類型為PChar類型}
  DrawText(Canvas.Handle, StrPCopy(temp, S), -1, R, DT_CALCRECT or DT_WORDBREAK);
  Canvas.Brush.Style := bsSolid;
  Canvas.Rectangle(R);
  Canvas.Brush.Style := bsClear;
  DrawText(Canvas.Handle, StrPCopy(temp, S), -1, R, DT_WORDBREAK);
end;

如果不考慮低版本的Delphi,則不必使用StrPCopy函數。

 

Note

用DrawText繪制文本比使用TextOut稍慢一些,若繪制操作對速度反應敏感,應該使用TextOut而不應該使用DrawText。用戶自己必須做更多的工作,但是執行速度將可能更快。當然,對於大多數的文本繪制,不必注意TextOut與DrawText之間的差別。

特別寫了一個效率比較的程序,通過統計執行相同工作所需的時間來判斷。具體代碼請大家自行下載示例代碼查看,這里不再貼出。如下圖:

image

 

DrawText函數是一個非常有用並且功能強大的函數,當編寫自己組件時,毫無疑問,這種函數將經常被使用。


以上代碼均在Delphi7下測試通過,示例代碼下載:GDI之繪制文本.rar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM