歡迎光臨 Code²

Code Square, CodeSqaure, Pascal, Javascript

2008年12月21日星期日

完整範例 - Fontlist (9/10)

  GetFolderFonts是處理目錄字型的核心,它負責讀取字型檔案、載入字型、求得字型名稱和卸載字型。因為字型檔有多種,所以這些功能由子程序AddFiles完成,GetFolderFonts多次呼叫AddFiles以處理不同的字型檔。

  GetFolderFonts的第一步,是由RemovePrivateFonts卸裝之前安裝的目錄字型和清空fFolderFonts。然後它創建了兩個在AddFiles中要使用的TStringList和保存了Canvas.Font。並在呼叫AddFiles後放回舊值。

procedure TForm1.GetFolderFonts;
var
  OldFont: tFont;
  s1, s2: tstringlist;

procedure AddFiles(const Path, Ext: string); var sr: tSearchRec; tm: tagTEXTMETRICA; fd: tFontData; i,j,l: integer; begin if FindFirst(Path+Ext, faAnyFile, sr)=0 then repeat s1.Assign(Screen.Fonts); fd.Filename:=Path+sr.Name; AddFontResourceEx(pchar(fd.Filename), FontParam, nil) ; SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) ; s2.Assign(Screen.Fonts); fd.Fontname:=NewStringListItem(s1, s2); if fd.Fontname<>'' then begin Canvas.Font.Name:=fd.Fontname; GetTextMetrics(Canvas.Handle, tm); fd.Charset:=tm.tmCharSet; l:=length(fFolderFonts); setlength(fFolderFonts,l+1); fFolderFonts[l]:=fd; end else begin RemoveFontResourceEx(pchar(fd.Filename), FontParam, nil) ; SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) ; end; until FindNext(sr)<>0; FindClose(sr); end;
begin RemovePrivateFonts; OldFont:=tFont.Create; OldFont.Assign(Canvas.Font); s1:=tStringList.Create; s2:=tStringList.Create; try AddFiles(IncludeTrailingBackslash(FFolder), '*.tt*'); AddFiles(IncludeTrailingBackslash(FFolder), '*.fon'); AddFiles(IncludeTrailingBackslash(FFolder), '*.otf'); finally s1.Free; s2.Free; Canvas.Font.Assign(OldFont); OldFont.Free; end; end;

  AddFiles使用FindFirst/FindNext找出所有檔案,對每一個檔案它用AddFontResourceEx嘗試安裝,用SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) ;使系統告知其它程序(如使Delphi程序更新Screen.Fonts),然後找出新增的字型。如果有新的字型則將之加入,否則放棄,並卸裝字型。注意RemoveFontResourceEx的參數必須和AddFontResourceEx完全相同,在此我們使用了常量FontParamFR_PRIVATE表示其他程序沒法使用我們安裝的字型。

const
  FontParam     = FR_PRIVATE;

  NewStringListItem用來找出S2中第一個不存在於S1的字符串,它用了TStrings.IndexOf()

function NewStringListItem(const S1, S2: tStrings): string;
var
  i: integer;
begin
  result:='';
  if s2.count<=s1.count then exit;
  for i:=0 to s2.Count-1 do
    if (s2[i]<>'') and (s2[i][1]<>'@') and (s1.IndexOf(s2[i])<0) then
    begin
      result:=s2[i];
      exit;
    end;
end;

  為甚麼我們用這樣一個方法求字型名稱?這是因為字型名稱和字型檔案並不一一對應,例如「細明體」和「新細明體」是同一個檔案,而Times New Romans有四個檔案。此外字型名稱受系統內碼影響,例如「細明體」在非繁體系統中變成了「PMingLiu」。為了避免考慮這些复雜的問題,我們只好使用這個無賴卻有效的做法。

  字型的卸裝很容易,只要用RemoveFontResourceEx一一卸裝即可,然後把fFolderFonts清空即可。

procedure TForm1.RemovePrivateFonts;
var
  i: integer;
begin
  for i:=0 to length(fFolderFonts)-1 do
    RemoveFontResourceEx(pchar(fFolderFonts[i].Filename), FontParam, nil) ;
  SetLength(fFolderFonts, 0);
  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0) ;
end;

  當然,在程序結束時必須把安裝的字型卸裝:

procedure TForm1.FormDestroy(Sender: TObject);
begin
  RemovePrivateFonts;
end;

  以下是顯示目錄字型的例子:

沒有留言:

發佈留言