歡迎光臨 Code²

Code Square, CodeSqaure, Pascal, Javascript

2008年12月17日星期三

完整範例 - Fontlist (4/10)

  因為目錄字型的處理比較复雜,所以我們暫時將它們放在一旁,首先著手處理系統字型。本篇及下兩篇將講解字型樣本的繪畫,然後將講解如何將字型樣本儲存成.bmp檔案。在所有功能都做好後,我們才著手處理目錄字型。而本篇的目標,便是能做到下圖的效果。

  說目錄字型處理比較复雜,是因為我們必須找出該目錄的所有字型,將之載入,然後找出對應的字型名,與之相比,系統字型早已裝載,Delphi 甚至將它們封裝在Screen變量中,使用起來很方便。

procedure TForm1.GetSystemFonts;
var
  i, l: integer;
begin
  SetLength(fSystemFonts,Screen.Fonts.Count);
  l:=0;
  for i:=0 to Screen.Fonts.Count-1 do
    if Screen.Fonts[i][1]<>'@' then
    begin
      fSystemFonts[l].Fontname:=Screen.Fonts[i];
      fSystemFonts[l].Filename:='';
      inc(l);
    end;
  SetLength(fSystemFonts,l);
end;

  對於系統字型,文件名並不易求,我們只是簡單地把它們設為空白。這裏要注意的是大部分中文字型,例如細明體,在Screen.fonts中出現兩份,其中一個是「細明體」,另一個是「@細明體」,後者用於直排文字,在此沒有必要重复,所以全部忽略了。

procedure TForm1.UpdateFonts;
begin
  btnSavebmp.enabled:=length(FFonts^)>0;
  Grid.RowCount:=length(FFonts^);
  Grid.Invalidate;
end;

  UpdateFonts是字型改變後的處理,其實不多,只是相應改變Grid的列數和要求它重畫。

  字型樣本繪畫在Grid上,要處理GridOnDrawCell,以下是其定義。

type
  TForm1 = class(TForm)
    ....
    procedure GridDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
  private
    procedure DrawCell(Canvas: tCanvas; Rect: tRect; Row: integer; Selected: boolean);
    ....
  end;

  GridDrawCell只是呼叫DrawCell,多了層轉折的原因,是為了多一層靈活性,以後將會解釋。

procedure TForm1.GridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  DrawCell(Grid.Canvas, Rect, ARow, gdSelected in State);
end;

  為了讓字型樣本足夠大,我們還需要在初始化時設定列高。同時,在Object Inspector中將Grid.GridWidth設為0,否則兩列之間有橫線。

procedure TForm1.FormCreate(Sender: TObject);
begin
  Grid.DefaultRowHeight:=32;
  Grid.DoubleBuffered:=true;
  ....
end;

  DoubleBuffered:=true防止Grid閃爍。以下是真正的繪畫方法,首先是一些常量的定義:

const
  FontBgColorHl = clNavy;
  FontBgColor0  = $00d0eFFF;
  FontBgColor1  = $00eFd0FF;
  FontColorHl   = clWhite;
  FontColor0    = clBlack;
  FontColor1    = clBlack;
procedure TForm1.DrawCell(Canvas: tCanvas; Rect: tRect; Row: integer;
  Selected: boolean);
begin
  with Canvas do
  begin
    if Selected
       then Brush.Color:=FontBgColorHl
       else if Row mod 2=0
         then Brush.Color:=FontBgColor0
         else Brush.Color:=FontBgColor1;
    FillRect(rect);
    if Row>=Length(fFonts^) then exit;

    if Selected
       then Font.Color:=FontColorHl
       else if Row mod 2=0
         then Font.Color:=FontColor0
         else Font.Color:=FontColor1;
    SetBkMode(Handle, TRANSPARENT);
    Font.Name:=fFonts^[Row].Fontname;
    Font.Height:=Rect.Bottom-Rect.Top-4;
    Textout(Rect.Left+2, Rect.Top+2,
            '詩中天地闊。Poem is lovely. - '+fFonts^[Row].Fontname);
  end;
end;

  DrawCell首先根據是否被選中,以及列數奇偶設定背景色,填滿,然後改變文字的色彩和字型,最後打印出「詩中天地闊。Poem is lovely.」及字型名稱。這裏有兩點應該注意:1)SetBkMode(Handle, TRANSPARENT);使打印出來的文字沒有背景。2)我們使用了Font.Height而不是Font.Size,這是必須的。雖然Windows說在同一設備上兩者之間有固定比例,但是這是忽略了字型的External leading的情況,如下圖,如果設定的是Font.Size,有些字便會超出格外。

  基本上這便是我們本篇要做的工作,看來還不錯,不過有些字型顯示成亂碼了,讓我們在下一篇處理吧。

沒有留言:

發佈留言