|
Delphi Programming / Object Pascal
[掲載 2010年02月27日] [更新 2015年10月31日] Delphi サンプルプログラム集 |
884_文字フォントやコードページと文字セットの関係 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
884_FontCharSetCodePages.zip [5,204 KB] 2015年10月31日版 (EXE 同梱) |
- 2014年06月16日
- TLanguages を使用した言語ロケールの列挙のサンプルを追加
- 2015年10月31日
- 日本語のフォント名を英語 (米国) のフォント名に変換するサンプル等を追加
|
自分のシステムにどんなフォントがインストールされていて,どんな言語で使用可能なの調べてみました.また,文字コード関係のサンプルプログラムで使用している MLang の関数を使用して同様な調査をするテストプログラムを作成してみました.
以下のプログラムで表示されるリスト,内容は Windows,Windows の [地域と言語] の設定でインストールされている言語,またフォントによって違ってくることになります.
このページでもそうですが,サンプルプログラムの他のページの記事でも「文字コード」と「コードページ」を混合して使用している箇所がありますが,文章の流れで判断していただければと思います.文字コードと Unicode との変換テーブルが「コードページ」です.
このページのコードで使用してる MultiLanguage_TLB.pas は,タイプライブラリの取り込みで作成したものですが,一部,筆者が修正しています.この MultiLanguage_TLB.pas を,ライブラリパスの通ったフォルダに置いて,uses に MultiLanguage_TLB を追加して使用します.あるいは,プロジェクトに追加して使用します.
本ページのサンプルプロジェクトでは,プロジェクトに追加して使用しています. |
システムにインストールされている全てのフォントと文字セットを列挙します.
Windows API の EnumFontFamiliesEx 関数を使用して取得しています.
結果を見ると,MSゴシック (MS Gothic) がいろいろな言語で使用されていることが分かります.当然ですが,日本以外の国では「MS ゴシック」という名前ではありません. |
- 図2
- タイトルの列をクリックするとその例をソート (整列) する.これはトグル動作となっている
- この図は FaceName でソートしたもの
|
|
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons, Grids, ComCtrls;
type
TForm1 = class(TForm)
StatusBar1: TStatusBar;
ListView1: TListView;
procedure FormShow(Sender: TObject);
procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
procedure ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
Data: Integer; var Compare: Integer);
private
{ Private 宣言 }
SortColumnIndex : Integer;
SortColum: array of Integer;
procedure GetFontCharsetList;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// EnumFontFamiliesExのコールバック関数
//=============================================================================
function EnumFontFamExProc(lpelf: PEnumLogFontEx; lpntm: PNewTextMetricEx;
nFontType: Integer; lParam: LParam):Integer; stdcall;
var
AFontName : String;
FontMaskStr : String;
AItem : TListItem;
CharSetStr : String;
begin
//フォント名
AFontName := lpelf.elfLogFont.lfFaceName;
//縦書きフォントは除外
if Pos('@', AFontName) = 0 then begin
FontMaskStr := '';
if (nFontType and RASTER_FONTTYPE) = RASTER_FONTTYPE then begin
FontMaskStr := 'RASTER ';
end;
if (nFontType and DEVICE_FONTTYPE) = DEVICE_FONTTYPE then begin
FontMaskStr := 'DEVICE ';
end;
if (nFontType and TRUETYPE_FONTTYPE) = TRUETYPE_FONTTYPE then begin
FontMaskStr := 'TRUETYPE ';
end;
AItem := Form1.ListView1.Items.Add;
AItem.Caption := FontMaskStr;
AItem.SubItems.Add(lpelf.elfStyle);
AItem.SubItems.Add(AFontName);
AItem.SubItems.Add(lpelf.elfScript);
case lpelf.elfLogFont.lfCharSet of
0: CharSetStr := 'ANSI_CHARSET';
1: CharSetStr := 'DEFAULT_CHARSET';
2: CharSetStr := 'SYMBOL_CHARSET';
128: CharSetStr := 'SHIFTJIS_CHARSET';
129: CharSetStr := 'HANGEUL_CHARSET';
134: CharSetStr := 'GB2312_CHARSET';
136: CharSetStr := 'CHINESEBIG5_CHARSET';
255: CharSetStr := 'OEM_CHARSET ';
130: CharSetStr := 'JOHAB_CHARSET';
177: CharSetStr := 'HEBREW_CHARSET';
178: CharSetStr := 'ARABIC_CHARSET';
161: CharSetStr := 'GREEK_CHARSET';
162: CharSetStr := 'TURKISH_CHARSET';
163: CharSetStr := 'VIETNAMESE_CHARSET';
222: CharSetStr := 'THAI_CHARSET';
238: CharSetStr := 'EASTEUROPE_CHARSET';
204: CharSetStr := 'RUSSIAN_CHARSET';
77: CharSetStr := 'MAC_CHARSET';
186: CharSetStr := 'BALTIC_CHARSET';
else
CharSetStr := '';
end;
AItem.SubItems.Add(CharSetStr);
end;
//列挙を継続
Result := 1;
end;
//=============================================================================
// フォーム表示開始時の処理
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
i : Integer;
begin
//ListViewの各カラムの幅とタイトルを設定
ListView1.Column[0].Width := 80;
ListView1.Column[0].Caption := 'FontType';
ListView1.Column[1].Width := 80;
ListView1.Column[1].Caption := 'Style';
ListView1.Column[2].Width := 140;
ListView1.Column[2].Caption := 'FaceName';
ListView1.Column[3].Width := 130;
ListView1.Column[3].Caption := 'Script';
ListView1.Column[4].Width := 170;
ListView1.Column[4].Caption := 'CharSet';
//SortColumはソート用のInteger配列
//カラムの数だけ配列要素を確保
SetLength(SortColum, ListView1.Columns.Count);
//ソート順の値を格納しておく
//実際には1でも0でOK(ソート後に負の値にする)
for i := 0 to Length(SortColum) - 1 do begin
SortColum[i] := 1;
end;
//フォントのリスト作成
GetFontCharsetList;
StatusBar1.Panels[0].Text := ' 列挙数: ' + IntToStr(ListView1.Items.Count);
end;
//=============================================================================
// システムの全てのフォント名をリストするメソッド
//=============================================================================
procedure TForm1.GetFontCharsetList;
var
DC : HDC;
ALogFont : TLOGFONT;
begin
ListView1.Clear;
DC := GetDC(0);
try
//ALogFontの設定
//ここでは全てのフォントのリストを取得する設定
//フォント名だけのリストを取得する関数はEnumFontFamilies
ALogFont.lfCharSet := DEFAULT_CHARSET;
ALogFont.lfFaceName := '';
ALogFont.lfPitchAndFamily := 0;
EnumFontFamiliesEx(DC, ALogFont, @EnumFontFamExProc, 0, 0);
finally
ReleaseDC(Handle, DC);
end;
end;
//=============================================================================
// OnColumnClickイベント
// クリックした列のソートを実行
//=============================================================================
procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
SortColumnIndex := Column.Index;
//AlphaSortメソッドは,OnCompareイベントの定義があればそれを実行する
ListView1.AlphaSort;
//次のクリックに備えてソート順番を逆にしておく
SortColum[SortColumnIndex] := -SortColum[SortColumnIndex];
end;
//=============================================================================
// OnCompareイベント
// クリックした列のソートを実行
//
// 本サンプルのListViewは仮想リストビューではないのでこのようにイベントで処理
// できる
//=============================================================================
procedure TForm1.ListView1Compare(Sender: TObject; Item1, Item2: TListItem;
Data: Integer; var Compare: Integer);
var
Str1 : String;
Str2 : String;
AIndex : Integer;
begin
if SortColumnIndex = 0 then begin
Str1 := Item1.Caption;
Str2 := Item2.Caption;
end else begin
//SubItemのIndexは0,1,2,...
AIndex := SortColumnIndex - 1;
Str1 := Item1.SubItems[AIndex];
Str2 := Item2.SubItems[AIndex];
end;
Compare := SortColum[SortColumnIndex] * CompareText(Str1, Str2);
end;
end.
Charset の定数名の列挙だけであれば,GetCharsetValues メソッドを使用して,以下のように取得できます. |
|
図3
Charset の定数名の列挙 |
var
CharSetList : TStringList;
procedure TForm1.Button1Click(Sender: TObject);
begin
CharSetList := TStringList.Create;
try
Graphics.GetCharsetValues(AddCharacterSet);
CharSetList.Sort;
ListBox1.Items := CharSetList;
finally
FreeAndNil(CharSetList);
end;
end;
procedure TForm1.AddCharacterSet(const S: string);
begin
CharSetList.Add(S);
end;
Charset の定数の文字列は,CharsetToIdent メソッドを使用して取得できます.
この関数では VIETNAMESE_CHARSET (= 163) が取得できないので,本ページのサンプルでは使用していません.最初のコードのように,コード中で文字列をセットしています.
最初のサンプルコードで使用している CharSet の値と文字列は,Windows SDK 8.1 の wingdi.h に記載されている全てです. |
|
図4
Charset 定数の文字列の取得
|
procedure TForm1.Button1Click(Sender: TObject);
var
i : Integer;
SetName : String;
begin
ListBox1.Items.Clear;
ListBox1.Sorted := True;
for i := Low(TFontCharset) to High(TFontCharset) do begin
if Graphics.CharsetToIdent(i, SetName) then begin
if Trim(SetName) <> '' then begin
ListBox1.Items.Add(Format('%3s', [IntToStr(i)]) + ' ' + SetName);
end;
end;
end;
end;
また,システムで使用可能なフォント名を列挙するだけであれば,以下のコードで可能です. |
|
図5
システムで使用可能なフォント名のリスト |
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Assign(Screen.Fonts);
end;
次はシステムがサポートするコードページと,実際にインストールされているコードページを列挙するサンプルです.EnumSystemCodePage 関数を使用しています.
MaxCharSize はその文字コードの 1 文字が使用する最大バイト数です.また DefaultChar は,該当する文字コード (その言語で正常かどうかとは無関係) がない場合等に表示する文字です. |
- 図7
- 実行結果
- UTF-8 は最大 4 バイト使用する
|
|
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons, Grids, ComCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
ComboBox1: TComboBox;
StatusBar1: TStatusBar;
ListView1: TListView;
procedure FormShow(Sender: TObject);
procedure ComboBox1Click(Sender: TObject);
private
{ Private 宣言 }
procedure GetSystemCodePageList;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//-----------------------------------------------------------------------------
// EnumSystemCodePagesのコールバック関数
//
// GetCPInfoEx関数の引数値
// CP_ACP システム既定のANSI コードページの情報取得
// CP_MACCP システム既定のMacintosh コードページの情報取得
// CP_OEMCP システム既定のOEMコードページの情報取得
//-----------------------------------------------------------------------------
function EnumCodePagesProc(CodeStr: PChar): Integer; stdcall;
var
Str : String;
CpInfo : TCPINFOEX;
AItem : TListItem;
begin
//コールバックが返したコードページ値からコードページの情報を取得
Str := CodeStr;
GetCPInfoEx(StrToInt(Str), CP_ACP, CpInfo);
AItem := Form1.ListView1.Items.Add;
//コードページの値
AItem.Caption := Format('%7s', [CodeStr]);
//コードページ名
AItem.SubItems.Add(CpInfo.CodePageName);
//コードページの文字が使用する最大バイト数
AItem.SubItems.Add(IntToStr(CpInfo.MaxCharSize));
//デフォルトで表示される文字(?とかドット文字のこと)
AItem.SubItems.Add(CpInfo.UnicodeDefaultChar);
//コールバックの呼出し継続
Result := 1;
end;
//=============================================================================
// フォーム表示開始時の処理
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
AColumn : TListColumn;
begin
ComboBox1.Style := csDropDownList;
ComboBox1.Items.BeginUpdate;
ComboBox1.Items.AddObject('CP_INSTALLED', TObject(CP_INSTALLED));
ComboBox1.Items.AddObject('CP_SUPPORTED', TObject(CP_SUPPORTED));
ComboBox1.Items.EndUpdate;
ComboBox1.ItemIndex := 0;
//カラム(列)の設定
AColumn := ListView1.Columns.Add;
AColumn.Width := 80;
AColumn.Caption := 'CodePage';
AColumn := ListView1.Columns.Add;
AColumn.Width := 235;
AColumn.Caption := 'CodePageName';
AColumn := ListView1.Columns.Add;
AColumn.Width := 85;
AColumn.Caption := 'MaxCharSize';
AColumn := ListView1.Columns.Add;
AColumn.Width := 85;
AColumn.Caption := 'DefaultChar';
ListView1.SortType := stText;
//列挙用メソッド実行
GetSystemCodePageList;
ListView1.SetFocus;
end;
//=============================================================================
// システムのコードページを列挙するメソッド
// EnumSystemCodePages関数を使用
//
// EnumSystemCodePagesの第2引数のFlagは
// CP_INSTALLED インストールされているコードページだけの列挙
// CP_SUPPORTED システムがサポートするコードページの列挙
//=============================================================================
procedure TForm1.GetSystemCodePageList;
var
Flag : Cardinal;
begin
Screen.Cursor := crHourGlass;
StatusBar1.Panels[0].Text := '';
StatusBar1.Update;
ListView1.Clear;
ListView1.Update;
ListView1.Items.BeginUpdate;
//Flagの指定
Flag := Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]);
//コールバック関数を呼出して列挙
EnumSystemCodePages(@EnumCodePagesProc, Flag);
StatusBar1.Panels[0].Text := ' 列挙数: ' + IntToStr(ListView1.Items.Count);
Screen.Cursor := crDefault;
ListView1.Items.EndUpdate;
end;
//=============================================================================
// コンボボックスで選択したらリストを再取得
//=============================================================================
procedure TForm1.ComboBox1Click(Sender: TObject);
begin
//列挙用メソッド実行
GetSystemCodePageList;
ListView1.SetFocus;
end;
end.
MLang.dll は IE 等の表示関係で使用される DLL です.この MLang の関数を使用して利用可能なコードページのリストを取得するサンプルです.これは MLang を使用するアプリで使用可能なコードページということになります.
IMultiLanguage の IEnumCodePage インターフェイスの EnumCodePages 関数を使用しています.この関数を実行して得られる TMIMECPINFO 構造体から情報を取得しています. |
- 図9
- 実行結果
- コンボボックスのリストは列挙タイプの指定
|
|
リスト3
MLang がサポートするコードページのリスト |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons, Grids, ComCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
ComboBox1: TComboBox;
StatusBar1: TStatusBar;
ListView1: TListView;
procedure FormShow(Sender: TObject);
procedure ComboBox1Click(Sender: TObject);
private
{ Private 宣言 }
procedure GetMlangCodePageList;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses MultiLanguage_TLB, ActiveX, ComObj;
{$R *.dfm}
//=============================================================================
// フォーム表示開始時の処理
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
AColumn : TListColumn;
begin
ComboBox1.Clear;
ComboBox1.Items.BeginUpdate;
//列挙タイプの選択項目
//内容についてはMSDNの記事参照
ComboBox1.Items.AddObject('dwFlag=0x0000', TObject($00000000));
ComboBox1.Items.AddObject('MIMECONTF_MAILNEWS', TObject($00000001));
ComboBox1.Items.AddObject('MIMECONTF_BROWSER', TObject($00000002));
ComboBox1.Items.AddObject('MIMECONTF_MINIMAL', TObject($00000004));
ComboBox1.Items.AddObject('MIMECONTF_IMPORT', TObject($00000008));
ComboBox1.Items.AddObject('MIMECONTF_SAVABLE_MAILNEWS', TObject($00000100));
ComboBox1.Items.AddObject('MIMECONTF_SAVABLE_BROWSER', TObject($00000200));
ComboBox1.Items.AddObject('MIMECONTF_EXPORT', TObject($00000400));
ComboBox1.Items.AddObject('MIMECONTF_PRIVCONVERTER', TObject($00010000));
ComboBox1.Items.AddObject('MIMECONTF_VALID', TObject($00020000));
ComboBox1.Items.AddObject('MIMECONTF_VALID_NLS', TObject($00040000));
ComboBox1.Items.AddObject('MIMECONTF_MIME_IE4', TObject($10000000));
ComboBox1.Items.AddObject('MIMECONTF_MIME_LATEST', TObject($20000000));
ComboBox1.Items.AddObject('MIMECONTF_MIME_REGISTRY', TObject($40000000));
ComboBox1.ItemIndex := 0;
ComboBox1.Items.EndUpdate;
//カラム設定
//MultiLaunguage_TLB.pas内の記述順
AColumn := ListView1.Columns.Add;
AColumn.width := 90;
AColumn.Caption := 'CodePage';
AColumn := ListView1.Columns.Add;
AColumn.width := 120;
AColumn.Caption := 'FamilyCodePage';
AColumn := ListView1.Columns.Add;
AColumn.width := 200;
AColumn.Caption := 'Description';
AColumn := ListView1.Columns.Add;
AColumn.width := 100;
AColumn.Caption := 'WebCharset';
AColumn := ListView1.Columns.Add;
AColumn.width := 150;
AColumn.Caption := 'HeaderCharset';
AColumn := ListView1.Columns.Add;
AColumn.width := 150;
AColumn.Caption := 'BodyCharset';
AColumn := ListView1.Columns.Add;
AColumn.width := 150;
AColumn.Caption := 'FixedWidthFont';
AColumn := ListView1.Columns.Add;
AColumn.width := 150;
AColumn.Caption := 'ProportionalFont';
AColumn := ListView1.Columns.Add;
AColumn.width := 160;
AColumn.Caption := 'GDICharset';
ListView1.SortType := stText;
GetMlangCodePageList;
end;
//=============================================================================
// MLangのEnumCodePages関数でコードページ情報の列挙するメソッド
//=============================================================================
procedure TForm1.GetMlangCodePageList;
var
MLang : IMultiLanguage;
EnumCodePage : IEnumCodePage;
Flags : DWORD;
Fetched : ULONG;
MIMECPInfo : TMIMECPINFO;
CodePageStr : String;
CharsetStr : String;
AItem : TListItem;
begin
Screen.Cursor := crHourGlass;
StatusBar1.Panels[0].Text := '';
StatusBar1.Update;
ListView1.Clear;
ListView1.Update;
ListView1.Items.BeginUpdate;
//列挙タイプを指定するFlagsの設定
//Flagの内容についてはMSDNの記事参照
Flags := Integer(ComboBox1.Items.Objects[ComboBox1.ItemIndex]);
//IMultiLanguageオブジェクトの作成
MLang := CoCMultiLanguage.Create;
if MLang <> nil then begin
//IEnumCodePageインターフェース取得
MLang.EnumCodePages(Flags, EnumCodePage);
//コードページを1個づつ列挙
while EnumCodePage.Next(1, MIMECPInfo, Fetched) = S_OK do begin
//MultiLaunguage_TLB.pas内の記述順
AItem := ListView1.Items.Add;
CodePageStr := IntToStr(MIMECPInfo.uiCodePage);
AItem.Caption := Format('%7s', [CodePageStr]);
AItem.SubItems.Add(IntToStr(MIMECPInfo.uiFamilyCodePage));
AItem.SubItems.Add(MIMECPInfo.wszDescription);
AItem.SubItems.Add(MIMECPInfo.wszWebCharset);
AItem.SubItems.Add(MIMECPInfo.wszHeaderCharset);
AItem.SubItems.Add(MIMECPInfo.wszBodyCharset);
AItem.SubItems.Add(MIMECPInfo.wszFixedWidthFont);
AItem.SubItems.Add(MIMECPInfo.wszProportionalFont);
//Charset
//リストはDelphi2010のWindows.pas内で定義のもの
case MIMECPInfo.bGDICharset of
0: CharSetStr := 'ANSI_CHARSET';
1: CharSetStr := 'DEFAULT_CHARSET';
2: CharSetStr := 'SYMBOL_CHARSET';
128: CharSetStr := 'SHIFTJIS_CHARSET';
129: CharSetStr := 'HANGEUL_CHARSET';
134: CharSetStr := 'GB2312_CHARSET';
136: CharSetStr := 'CHINESEBIG5_CHARSET';
255: CharSetStr := 'OEM_CHARSET ';
130: CharSetStr := 'JOHAB_CHARSET';
177: CharSetStr := 'HEBREW_CHARSET';
178: CharSetStr := 'ARABIC_CHARSET';
161: CharSetStr := 'GREEK_CHARSET';
162: CharSetStr := 'TURKISH_CHARSET';
163: CharSetStr := 'VIETNAMESE_CHARSET';
222: CharSetStr := 'THAI_CHARSET';
238: CharSetStr := 'EASTEUROPE_CHARSET';
204: CharSetStr := 'RUSSIAN_CHARSET';
77: CharSetStr := 'MAC_CHARSET';
186: CharSetStr := 'BALTIC_CHARSET';
else
CharSetStr := '';
end;
AItem.SubItems.Add(CharsetStr);
end;
end;
MLang := nil;
StatusBar1.Panels[0].Text := ' 列挙数: ' + IntToStr(ListView1.Items.Count);
Screen.Cursor := crDefault;
ListView1.Items.EndUpdate;
ListView1.SetFocus;
if ListView1.Items.Count > 0 then ListView1.ItemIndex := 0;
end;
//=============================================================================
// 列挙タイプのリストを選択したら,列挙を再取得
//=============================================================================
procedure TForm1.ComboBox1Click(Sender: TObject);
begin
GetMlangCodePageList;
end;
end.
HTML コードで,言語名を識別するための <HTML> タグの lang 属性を規定する RFC1766 の一覧を取得するサンプルプログラムです.
IMultiLanguage の IEnumRfc1766 インターフェイスを使用しています.各項目値は TRFC1766INFO 構造体から取得しています. |
|
図10
設計時画面
|
|
図11
実行結果
|
リスト4
RFC1766 の言語識別タグ文字リスト |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons, Grids, ComCtrls;
type
TForm1 = class(TForm)
StatusBar1: TStatusBar;
ListView1: TListView;
procedure FormShow(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses MultiLanguage_TLB, ActiveX, ComObj;
{$R *.dfm}
//=============================================================================
// フォーム表示開始時の処理
// 表示開始と同時に言語名識別タグRfc1766(Request For Comments 1766)を列挙
// 現在はRFC 3066(BCP47),RFC 3282
//
// 1次言語タグ
// ISO 639で規定される2文字の言語コード
// -に続く)2次タグ
// 国名コード.1次タグがxの場合は任意実装
//
// lcidはwindows内部定義の値
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
AColumn : TListColumn;
MLang : IMultiLanguage;
EnumCodePage : IEnumRfc1766;
Fetched : ULONG;
Rfc1766Info : TRFC1766INFO;
AItem : TListItem;
begin
Screen.Cursor := crHourGlass;
StatusBar1.Panels[0].Text := '';
StatusBar1.Update;
ListView1.Clear;
ListView1.Update;
ListView1.Items.BeginUpdate;
//カラムの設定
AColumn := ListView1.Columns.Add;
AColumn.width := 60;
AColumn.Caption := 'lcid';
AColumn := ListView1.Columns.Add;
AColumn.width := 220;
AColumn.Caption := 'LocaleName';
AColumn := ListView1.Columns.Add;
AColumn.width := 70;
AColumn.Caption := 'Rfc1766';
//IMultiLanguageオブジェクトの作成
MLang := CoCMultiLanguage.Create;
//インターフェースの実装を確認
if MLang <> nil then begin
//IEnumCodePageインターフェース取得
MLang.EnumRfc1766(EnumCodePage);
//コードページを1個づつ列挙
while EnumCodePage.Next(1, Rfc1766Info, Fetched) = S_OK do begin
AItem := ListView1.Items.Add;
AItem.Caption := IntToStr(Rfc1766Info.lcid);
AItem.SubItems.Add(Rfc1766Info.wszLocaleName);
AItem.SubItems.Add(Rfc1766Info.wszRfc1766);
end;
end;
MLang := nil;
StatusBar1.Panels[0].Text := ' 列挙数: ' + IntToStr(ListView1.Items.Count);
Screen.Cursor := crDefault;
ListView1.Items.EndUpdate;
ListView1.SetFocus;
if ListView1.Items.Count > 0 then ListView1.ItemIndex := 0;
end;
end.
各々の文字が,どんな言語または文字セット (Charset) で使用できるのか,またサポートしているのかを確認するためのテストプログラムです.使用可能なフォント名は,面倒ですが最初のサンプルプログラムを使用すると確認することができます.こんなテストも Unicode 化されたからこそ意味があるのかも知れません.
何かのテストで利用可能なように (必要性はともかく),文字のコピー機能を付けてみました. |
- 図12
- 設計時画面
- 左端は文字一覧表示用の ListView
- 中央はその文字が使用可能な言語と文字セットの一覧表示用の ListView
- 右端は文字の拡大表示用の Label
|
|
- 図13
- ひらがなの「あ」は中国語と韓国語でも使用可能となっている
|
|
- 図15
- いわゆる○囲み数字もほとんど漢字使用圏だけ
|
|
- 図16
- アルファベットの A は多くの言語で使用されている
|
|
- 図17
- 現システムでコードページがサポートされていない (?).代替フォントで表示される例
|
|
他の国のテキストを表示した場合,現在設定中のフォントでは表示できないと,少し字体が潰れた様に表示されることがあります.こは代替フォントを使用して表示するためです.上の図もそうです.
このことを再確認したのが以下の図です.全く表示できない場合は,DefaultChar の文字で表示されることになります.
文書作成用アプリでは,代替フォントを使用しないものもあります.もっとも,代替フォントを使用されてしまうと,フォント名指定の意味がなくなってしまう気もします. |
|
図18
現在のフォント Tahoma では表示できない文字
- Tahoma はゴシック体であるが,明朝体のようになっている.これは代替フォント
- しかも上が少し空いている
|
|
図19
表示用フォントを SimHei に変更
- Description (この図では非表示) の値で言語を推測
- Simhei フォントを使用するには,Charset を CHINESE_GB2312 にする
- システムにインストールされている全フォントのリストから知ることができる
|
上の 2 つの図の内,最初の図は,表示コントロールの TFont.Charset の値を DEFAULT_CHARSET にした場合です.TFont.Charset の値を SHIFTJIS_CHARSET すると下図のようになります.
下図のように,フォントセットを明示的に設定した場合は,指定したフォントで表示できない文字は DefaulChar で表示されます.代替フォントでの表示はしません. |
|
図20
代替フォントを使用しない場合
- 文字コードは上の図と同じ U+FADD
- TFont.Charset が SHIFTJIS_CHARSET の場合
|
以上の文字の他,例えば「𠮷野家」という文字が,フォントによってどのように違うかを,次のコードで確認してみるといいのではないかと思います.𠮷野家の「𠮷」はサロゲートペアな文字です.冠が「土」と同じで,下が長くなっています.
また,「#$00020BB7 + '野家'」 と「吉野家」との違いを試してみるのもいいかも知れません. |
procedure TForm1.Button2Click(Sender: TObject);
var
StrText : String;
begin
StrText := #$00020BB7 + '野家';
Panel1.Font.Name := 'メイリオ'; //このフォント名を変更してみる
Panel1.Font.Size := 25;
Panel1.Caption := StrText;
Label1.Caption := Panel1.Font.Name;
Label2.Caption := IntToStr(Length(StrText));
//サロゲートペアの文字を含む上の結果は4
//MECSUtilsのMecsLengthを使用すれば,実際の表示の文字数である3となる
Label3.Caption := IntToStr(MecsLength(StrText));
end;
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, Buttons, Grids, ComCtrls, Generics.Collections,
Menus;
type
TForm1 = class(TForm)
Panel1: TPanel;
StatusBar1: TStatusBar;
ListView1: TListView;
ListView2: TListView;
ComboBox1: TComboBox;
Label1: TLabel;
CheckBox1: TCheckBox;
PopupMenu1: TPopupMenu;
popupCopy: TMenuItem;
procedure FormShow(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ListView1Data(Sender: TObject; Item: TListItem);
procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure ComboBox1Click(Sender: TObject);
procedure CheckBox1Click(Sender: TObject);
procedure popupCopyClick(Sender: TObject);
private
{ Private 宣言 }
ItemList : TList<WORD>;
procedure ShowCodePagesList;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses MultiLanguage_TLB, ActiveX, ComObj, Clipbrd;
{$R *.dfm}
//-----------------------------------------------------------------------------
// EnumFontFamiliesのコールバック関数
//-----------------------------------------------------------------------------
function EnumFontFamProc(lpelf: PEnumLogFont; lpntm: PNewTextMetric;
nFontType: Integer; lParam: LParam):Integer; stdcall;
var
AFontName : String;
begin
Result := 1;
AFontName := lpelf.elfLogFont.lfFaceName;
//縦書き用フォントは除外
if Pos('@', AFontName) = 0 then begin
Form1.ComboBox1.Items.Add(AFontName);
end;
end;
//=============================================================================
// フォーム表示開始時の処理
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
DC : HDC;
AIndex : Integer;
i : Integer;
begin
CheckBox1.Checked := True;
//文字コードポイント格納用リスト
ItemList := TList<WORD>.Create;
//文字ポイント表示用のListViewの設定
//カラムは設計時に設定すみ
ListView1.Column[0].Width := ListView1.ClientWidth
- GetSystemMetrics(SM_CXHSCROLL);
ListView1.Column[0].Caption := 'CodePoint';
//コードページ一覧表示用ListViewの設定
//カラムは設計時に設定すみ
ListView2.Column[0].Width := 70;
ListView2.Column[0].Caption := 'CodePage';
ListView2.Column[1].Width := 160;
ListView2.Column[1].Caption := 'Description';
ListView2.Column[2].Width := 150;
ListView2.Column[2].Caption := 'GDICharset';
//フォント名リストの作成
//全フォントのリストを取得する関数はEnumFontFamiliesEx
ComboBox1.Clear;
ComboBox1.Sorted := True;
DC := GetDC(Handle);
try
EnumFontFamilies(DC, nil, @EnumFontFamProc, 0);
AIndex := ComboBox1.Items.IndexOf(Label1.Font.Name);
ComboBox1.ItemIndex := AIndex;
finally
ReleaseDC(Handle, DC);
end;
//文字(コードポイント)一覧の作成
//このサンプルでは文字一覧表示のListViewを仮想リストビューとしているので
//このメソッドではItemListというリストに格納するだけ
//実際の描画はListViewのOnDataイベント内で行っている
Screen.Cursor := crHourGlass;
ListView1.Clear;
Label1.Caption := '';
Label1.Update;
for i := 0 to $FFFF -1 do begin
ItemList.Add(WORD(i));
end;
//ListViewに表示数を通知する
//仮想リストビューではこの通知で実際の描画が行われる
ListView1.Items.Count := ItemList.Count;
Screen.Cursor := crDefault;
ListView1.SetFocus;
StatusBar1.Panels[0].Text := ' 列挙数: ' + IntToStr(ItemList.Count);
end;
//=============================================================================
// オブジェクトの破棄
//=============================================================================
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(ItemList);
end;
//=============================================================================
// ListView1のOnDataイベント
// 文字コードポイント値とその文字をItemのCaptionに表示
//
// ListViewの各Itemの描画が必要となった場合に発生
// このイベントはListView1.OwnerData:=Trueでないと機能しない
//=============================================================================
procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
var
dwCode : WORD;
begin
if Item.Index > ItemList.Count then exit;
dwCode := ItemList[Item.Index];
Item.Caption := Format('U+%4.4x ', [dwCode]) + Chr(dwCode);
end;
//=============================================================================
// ListView1のOnSelectItemイベント
// 選択した文字をLabelに表示
//=============================================================================
procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
begin
if Item = nil then exit;
Label1.Caption := Chr(ItemList[Item.Index]);
//その文字をサポートしているコードページ一覧を表示
ShowCodePagesList;
end;
//=============================================================================
// CheckBox1のOnClickイベント
// チェックボックスのチェックを外したらコードページを非表示
//
// サイトの記事作成用(文字コードポイントとその表示文字の確認用)
//=============================================================================
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
ListView2.Visible := CheckBox1.Checked;
if ListView2.Visible then begin
Self.Width := 646;
Self.Height := 350;
end else begin
Self.Width := 250;
Self.Height := 240;
end;
end;
//=============================================================================
// ComboBox1のOnClickイベント
// コンボボックスでフォント名を選択したらそのフォントで文字を再表示
//
// サイトの記事作成用.なくても動作そのものに関係なし
//=============================================================================
procedure TForm1.ComboBox1Click(Sender: TObject);
begin
Label1.Font.Name := ComboBox1.Items[ComboBox1.ItemIndex];
ListView1.SetFocus;
end;
//=============================================================================
// 文字を拡大表示しているLabelのポップアップメニュー
// 文字をクリップボードにコピー
// コピーしても,貼り付け先のアプリによつては正常に表示されるとは限らない
// CharSeetから,そのCharsetに応じたフォントを選択しなければならない場合もある
//
// 筆者のテスト用.なくても動作そのものには関係なし
//=============================================================================
procedure TForm1.popupCopyClick(Sender: TObject);
var
AClipbrd : TClipboard;
begin
AClipbrd := TClipboard.Create;
try
AClipbrd.SetTextBuf(PChar(Label1.Caption));
finally
AClipbrd.Free;
end;
end;
//=============================================================================
// ListView1で選択した文字をサポートするコードページの一覧表示用メソッド
//=============================================================================
procedure TForm1.ShowCodePagesList;
var
AIndex : Integer;
MLang : IMultiLanguage;
MLangCodePages : IMLangCodePages;
dwCode : DWORD;
pdwCodePages : DWORD;
CodePage : UINT;
TempCodePages : UINT;
MIMECPInfo : TMIMECPINFO;
CharsetStr : String;
AItem : TListItem;
begin
ListView2.Clear;
ListView2.Update;
ListView2.Items.BeginUpdate;
AIndex := ListView1.Selected.Index;
if AIndex < 0 then exit;
//iMultiLanguageオブジェクトの作成
MLang := CoCMultiLanguage.Create;
//インターフェースの実装を確認
if MLang <> nil then begin
if MLang.QueryInterface(IID_IMLangCodePages, MLangCodePages) = S_OK then begin
dwCode := ItemList[AIndex];
MLangCodePages.GetCharCodePages(dwCode, pdwCodePages);
while pdwCodePages > 0 do begin
MLangCodePages.CodePagesToCodePage(pdwCodePages, CP_ACP, CodePage);
//取り出されたコードページの情報を取得
MLang.GetCodePageInfo(CodePage, MIMECPInfo);
//取得した情報を表示
AItem := ListView2.Items.Add;
AItem.Caption := IntToStr(MIMECPInfo.uiCodePage);
AItem.SubItems.Add(MIMECPInfo.wszDescription);
//Charset
//Delphi2010のwindows.pas内で定義されているもの
case MIMECPInfo.bGDICharset of
0: CharSetStr := 'ANSI_CHARSET';
1: CharSetStr := 'DEFAULT_CHARSET';
2: CharSetStr := 'SYMBOL_CHARSET';
128: CharSetStr := 'SHIFTJIS_CHARSET';
129: CharSetStr := 'HANGEUL_CHARSET';
134: CharSetStr := 'GB2312_CHARSET';
136: CharSetStr := 'CHINESEBIG5_CHARSET';
255: CharSetStr := 'OEM_CHARSET ';
130: CharSetStr := 'JOHAB_CHARSET';
177: CharSetStr := 'HEBREW_CHARSET';
178: CharSetStr := 'ARABIC_CHARSET';
161: CharSetStr := 'GREEK_CHARSET';
162: CharSetStr := 'TURKISH_CHARSET';
163: CharSetStr := 'VIETNAMESE_CHARSET';
222: CharSetStr := 'THAI_CHARSET';
238: CharSetStr := 'EASTEUROPE_CHARSET';
204: CharSetStr := 'RUSSIAN_CHARSET';
77: CharSetStr := 'MAC_CHARSET';
186: CharSetStr := 'BALTIC_CHARSET';
else
CharSetStr := '';
end;
AItem.SubItems.Add(CharsetStr);
MLangCodePages.CodePageToCodePages(CodePage, TempCodePages);
//処理したpdwCodePagesの値は0にする
pdwCodePages := pdwCodePages and (not TempCodePages);
end;
end;
end;
MLang := nil;
ListView2.Items.EndUpdate;
end;
end.
代替フォントですが,MLang に IMLangFontLink というインターフェイスがあり,MapFont という関数があります.これを使用すると知ることができるかも知れません.
今回はこの動作については確認しませんでした.他のサンプルプログラムの記事でも書いていますが,文字コードの違うテキスト等は,適切なコードページとフォントを指定して処理する方がいいのではないかと思います.全く文字コードが不明な場合の完全な対処方法は,現在のところ困難なのではないでしょうか. |
07_TLanguages を使用した言語ロケールの列挙 |
アプリケーションによっては,コードページと言語ロケールの情報が必要な場合があります.
ここまでのサンプルで,コードページを列挙するテストをしました.本サンプルは,現在のシステムがサポートしている言語ロケールを列挙します.
SysUtils の TLanguages クラスを利用したサンプルです.TLanguages を使用すると,言語ロケールや言語名等が取得できます.
MSDN オンイランでは,言語ロケールとコードページ関係の記事は,下記の MSDN のリンクの [国別言語サポート (National Language Support)] のページにあります.
|
リスト6
システムがサポートしている言語ロケールの情報を列挙 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
ListView1: TListView;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
// TListViewのカラムを作成して,各カラムの設定を行う
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
ListView1.ViewStyle := vsReport;
ListView1.Columns.Add;
ListView1.Columns.Add;
ListView1.Columns.Add;
ListView1.Columns.Add;
ListView1.Columns.Add;
//ListViewの各カラムの幅とタイトルを設定
ListView1.Column[0].Caption := 'Name';
ListView1.Column[0].Width := 280;
ListView1.Column[1].Caption := 'ID';
ListView1.Column[1].Width := 80;
ListView1.Column[2].Caption := 'LocaleName';
ListView1.Column[2].Width := 70;
ListView1.Column[3].Caption := 'LocaleID';
ListView1.Column[3].Width := 70;
ListView1.Column[4].Caption := 'Ext';
ListView1.Column[4].Width := 50;
Label1.Caption := '';
end;
//=============================================================================
// TLanguagesを使用して,システムがサポートしている言語ロケールを列挙
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LangList : TLanguages;
i : Integer;
AItem : TListItem;
begin
ListView1.SortType := stText;
ListView1.Items.Clear;
ListView1.Items.BeginUpdate;
LangList := TLanguages.Create;
try
Label1.Caption := 'Count : ' + IntToStr(LangList.Count);
for i := 0 to LangList.Count - 1 do begin
AItem := ListView1.Items.Add;
AItem.Caption := LangList.Name[i];
AItem.SubItems.Add(LangList.ID[i]);
AItem.SubItems.Add(LangList.LocaleName[i]);
AItem.SubItems.Add(IntToStr(LangList.LocaleID[i]));
AItem.SubItems.Add(LangList.Ext[i]);
end;
finally
LangList.Free;
end;
ListView1.Items.EndUpdate;
end;
end.
現在のユーザの言語ロケールの情報は,下のコードで取得できます.
まず,GetUserDefaultLCID で,現在のユーザの既定の言語ロケール識別子を取得します.その値を元にしてその他の値を取得します.上のコードと同じく,TLanguages クラスを使用しています.
指定した言語のロケール名を取得する方法は,この後のサンプルを参考にしてください.
|
|
図23
実行結果 |
リスト7
現在のユーザの,既定の言語ロケールの情報を取得 |
//=============================================================================
// ユーザーの既定ロケール識別子を取得して,それを元に言語名等を取得する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LangList : TLanguages;
LangListNo : Integer;
UserLocaleID : Cardinal;
AItem : TListItem;
begin
LangList := TLanguages.Create;
try
UserLocaleID := GetUserDefaultLCID;
LangListNo := LangList.IndexOf(UserLocaleID);
ListView1.Items.Clear;
AItem := ListView1.Items.Add;
//LangList.NameFromLocaleID[UserLocaleID];でも同じ
AItem.Caption := LangList.Name[LangListNo];
AItem.SubItems.Add(LangList.ID[LangListNo]);
AItem.SubItems.Add(LangList.LocaleName[LangListNo]);
AItem.SubItems.Add(IntToStr(LangList.LocaleID[LangListNo]));
AItem.SubItems.Add(LangList.Ext[LangListNo]);
finally
LangList.Free;
end;
end;
08_IDWriteFontCollection を使用したフォント名の列挙 - Direct2D |
Direct2D に実装されている IDWriteFontCollection インターフェイスを使用して,システムにインストールされているフォント名を列挙します.
また,指定した言語ロケールだけのフォント名を列挙して表示します.
本サンプルは,Windows Vista 以降,Delphi 2010 以降専用です.
|
|
図24
設計時画面 |
|
図25
システムにインストールされているフォント名 |
|
図26
日本語ロケールのフォント名のリスト |
|
図27
英語 (米国) ロケールのフォント名のリスト |
リスト8
Direct2D の IDWriteFontCollection を使用したシステムフォント名の列挙
指定ロケール名のフォント名の列挙 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
Direct2D,
D2D1;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Font.Name := 'MS ゴシック';
Memo1.Font.Size := 10;
Memo1.ScrollBars := ssVertical;
end;
//=============================================================================
// システムにインストールされているフォント名を全て列挙
//
// usesにDirect2D,D2D1が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LIDWriteFontCollection : IDWriteFontCollection;
LIDWriteFontFamily : IDWriteFontFamily;
LIDWriteLocalizedStrings : IDWriteLocalizedStrings;
LstringBurrer : array[0..LF_FACESIZE-1] of Char;
i : Integer;
j : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
//インストールされているフォントセットのオブジェクトを取得
DWriteFactory.GetSystemFontCollection(LIDWriteFontCollection);
//取得したオブジェクトからフォント情報を順番に取得
for i := 0 to LIDWriteFontCollection.GetFontFamilyCount - 1 do begin
LIDWriteFontCollection.GetFontFamily(i, LIDWriteFontFamily);
LIDWriteFontFamily.GetFamilyNames(LIDWriteLocalizedStrings);
for j := 0 to LIDWriteLocalizedStrings.GetCount - 1 do begin
LIDWriteLocalizedStrings.GetString(j, LstringBurrer, Length(LstringBurrer));
Memo1.Lines.Add(FormatFloat('000', i) + ' ' + LstringBurrer);
end;
end;
Memo1.Lines.EndUpdate;
end;
//=============================================================================
// システムにインストールされているフォント名を列挙
// ロケール名が日本語のフォントのみの列挙
//
// usesにDirect2D,D2D1が必要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
const
SUBLANG_JAPANESE_JAPAN = $01;
var
LLangId : WORD;
Llcid : DWORD;
LIDWriteFontCollection : IDWriteFontCollection;
LIDWriteFontFamily : IDWriteFontFamily;
LIDWriteLocalizedStrings : IDWriteLocalizedStrings;
LBuffer : array[0..LOCALE_NAME_MAX_LENGTH-1] of Char;
LlocaleName : string;
LIndex : Cardinal;
Lexists : LongBool;
i : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
//ロケール名を取得
LLangId := MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN);
Llcid := MAKELCID(LLangId, SORT_DEFAULT);
//現システムのロケールの場合は以下で取得可能
//LCIDToLocaleName(GetUserDefaultLangID, LBuffer, Length(LBuffer), 0);
LCIDToLocaleName(Llcid, LBuffer, Length(LBuffer), 0);
LlocaleName := LBuffer; //ja-JPになる
//インストールされているフォントセットのオブジェクトを取得
DWriteFactory.GetSystemFontCollection(LIDWriteFontCollection);
//取得したオブジェクトからフォント情報を順番に取得
for i := 0 to LIDWriteFontCollection.GetFontFamilyCount - 1 do begin
LIDWriteFontCollection.GetFontFamily(i, LIDWriteFontFamily);
LIDWriteFontFamily.GetFamilyNames(LIDWriteLocalizedStrings);
LIDWriteLocalizedStrings.FindLocaleName(LlocaleName[1], LIndex, Lexists);
if not Lexists then Continue;
LIDWriteLocalizedStrings.GetString(LIndex, LBuffer, Length(LBuffer));
Memo1.Lines.Add(FormatFloat('000', i) + ' ' + LBuffer);
end;
Memo1.Lines.EndUpdate;
end;
//=============================================================================
// システムにインストールされているフォント名を列挙
// ロケール名が英語(米国)のフォントのみの列挙
//
// usesにDirect2D,D2D1が必要
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
LLangId : WORD;
Llcid : DWORD;
LIDWriteFontCollection : IDWriteFontCollection;
LIDWriteFontFamily : IDWriteFontFamily;
LIDWriteLocalizedStrings : IDWriteLocalizedStrings;
LBuffer : array[0..LOCALE_NAME_MAX_LENGTH-1] of Char;
LlocaleName : string;
LIndex : Cardinal;
Lexists : LongBool;
i : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
//ロケール言語名を取得
LLangId := MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
Llcid := MAKELCID(LLangId, SORT_DEFAULT);
LCIDToLocaleName(Llcid, LBuffer, Length(LBuffer), 0);
LlocaleName := LBuffer; //en-USになる
//インストールされているフォントセットのオブジェクトを取得
DWriteFactory.GetSystemFontCollection(LIDWriteFontCollection);
//取得したオブジェクトからフォント情報を順番に取得
for i := 0 to LIDWriteFontCollection.GetFontFamilyCount - 1 do begin
LIDWriteFontCollection.GetFontFamily(i, LIDWriteFontFamily);
LIDWriteFontFamily.GetFamilyNames(LIDWriteLocalizedStrings);
LIDWriteLocalizedStrings.FindLocaleName(LlocaleName[1], LIndex, Lexists);
if not Lexists then Continue;
LIDWriteLocalizedStrings.GetString(LIndex, LBuffer, Length(LBuffer));
Memo1.Lines.Add(FormatFloat('000', i) + ' ' + LBuffer);
end;
Memo1.Lines.EndUpdate;
end;
end.
09_日本語フォント名に対応する英語フォント名を列挙 - Direct2D |
日本語フォント名に対応する英語 (米国) フォント名を列挙するサンプルです.
Direct2D に実装されている機能を使用しています.
本サンプルは,Windows Vista 以降,Delphi 2010 以降専用です.
|
|
図28
設計時画面 |
|
図29
日本語フォント名と英語フォント名 |
リスト9
日本語フォント名に対応する英語フォント名を列挙 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
Direct2D,
D2D1,
MECSUtils;
{$R *.dfm}
//-----------------------------------------------------------------------------
// この関数はTMemoに表示する際の体裁を整えているだけなので本質的には不要
//
// 指定した長さの文字列を作成する関数
// 文字列が指定長さより短い場合は半角の空白で埋める
// 文字列の長さのチェックはしていないので注意
//
// ASrcText : 対象の文字列
// ALen : 設定する文字列の半角単位での長さ
// AJustify : 左寄せの時はtaLeftJustify(デフォルト).それ以外は右寄せ
//
// usesにMECSUtilsが必要
//-----------------------------------------------------------------------------
function CreateFixedLengthText(ASrcText: String; ALen: Integer;
AJustify: TAlignment=taLeftJustify): String;
var
LSpcLen : Integer;
begin
if Length(ASrcText) = 0 then begin
Result := StringOfChar(' ', ALen);
end else begin
LSpcLen := ALen - MecsStringWidth(ASrcText);
if LSpcLen > 0 then begin
if AJustify = taLeftJustify then begin
Result := ASrcText + StringOfChar(' ', LSpcLen);
end else begin
Result := StringOfChar(' ', LSpcLen) + ASrcText;
end;
end else begin
Result := ASrcText;
end;
end;
end;
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.Font.Name := 'MS ゴシック';
Memo1.Font.Size := 10;
Memo1.ScrollBars := ssBoth;
end;
//=============================================================================
// 日本語名のフォントに対応する英語表記のフォント名の一覧
//
// usesにDirect2D,D2D1が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
const
SUBLANG_JAPANESE_JAPAN = $01;
var
LLangId : WORD;
Llcid : DWORD;
LIDWriteFontCollection : IDWriteFontCollection;
LIDWriteFontFamily : IDWriteFontFamily;
LIDWriteLocalizedStrings : IDWriteLocalizedStrings;
LBuffer_JP : array[0..LOCALE_NAME_MAX_LENGTH-1] of Char;
LBuffer_EN : array[0..LOCALE_NAME_MAX_LENGTH-1] of Char;
LlocaleName_JP : string;
LlocaleName_EN : string;
LIndex : Cardinal;
Lexists : LongBool;
LFormatText : string;
i : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.BeginUpdate;
//日本語のロケール名を取得
//LlocaleName_JP := 'ja-JP';の1行だけでも同じ
LLangId := MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN);
Llcid := MAKELCID(LLangId, SORT_DEFAULT);
LCIDToLocaleName(Llcid, LBuffer_JP, Length(LBuffer_JP), 0);
LlocaleName_JP := LBuffer_JP; //ja-JPになる
//英語(米国)のロケール名を取得
//LlocaleName_EN := 'en-US';の1行だけでも同じ
LLangId := MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
Llcid := MAKELCID(LLangId, SORT_DEFAULT);
LCIDToLocaleName(Llcid, LBuffer_EN, Length(LBuffer_EN), 0);
LlocaleName_EN := LBuffer_EN; //en-USになる
//インストールされているフォントセットのオブジェクトを取得
DWriteFactory.GetSystemFontCollection(LIDWriteFontCollection);
//取得したオブジェクトからフォント情報を順番に取得
for i := 0 to LIDWriteFontCollection.GetFontFamilyCount - 1 do begin
LIDWriteFontCollection.GetFontFamily(i, LIDWriteFontFamily);
LIDWriteFontFamily.GetFamilyNames(LIDWriteLocalizedStrings);
LIDWriteLocalizedStrings.FindLocaleName(LlocaleName_JP[1], LIndex, Lexists);
if not Lexists then Continue;
//日本語のフォント名を取得
LIDWriteLocalizedStrings.GetString(LIndex, LBuffer_JP, Length(LBuffer_JP));
//英語のフォント名を取得
LIDWriteLocalizedStrings.FindLocaleName(LlocaleName_EN[1], LIndex, Lexists);
LIDWriteLocalizedStrings.GetString(LIndex, LBuffer_EN, Length(LBuffer_EN));
//書式を整えて結果を出力
LFormatText := FormatFloat('000', i) + ' '
+ CreateFixedLengthText(LBuffer_JP, 19)
+ CreateFixedLengthText(LBuffer_EN, 20);
Memo1.Lines.Add(LFormatText);
end;
Memo1.Lines.EndUpdate;
end;
end.
10_指定フォント名を英語フォント名に変換 - Direct2D |
指定したフォント名を,英語フォント名に変換するサンプルです.
Button2 のクリックイベントでは,専用の関数を作成して,英語フォント名以外のフォント名を英語フォント名に変換します.また,フォントダイアログで選択したフォント名を英語フォント名に変換します.この英語フォント名の言語ロケールは英語 (米国) です.
Button1, Button2 クリックでも,縦書きフォントの場合の処理はしていません.
Direct2D に実装されている機能を使用しています.
本サンプルは,Windows Vista 以降,Delphi 2010 以降専用です.
|
|
図30
設計時画面 |
|
図31
フォント名 [MS P明朝] を英語のフォント名に
|
|
図32
ハングルフォント名を英語のフォント名に変換
- Button2 は日本語フォント名以外も英語のフォント名に変換する
|
|
図33
中国のフォント名を英語のフォント名に変換 |
下図は,フォントダイアログで選択したフォント名を英語フォント名に変換したところです.
英語名のフォントの場合は変換しません.
|
|
図34
フォントダイアログで選択したフォントのフォント名を英語フォント名に変換 |
リスト10
指定した英語フォント名以外を,英語フォント名に変換 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
Edit1: TEdit;
FontDialog1: TFontDialog;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
uses
Direct2D,
D2D1;
{$R *.dfm}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
CheckBox1.Checked := True;
Memo1.Font.Name := 'MS ゴシック';
Memo1.Font.Size := 10;
Edit1.Text := 'MS P明朝';
end;
//=============================================================================
// 日本語のフォント名を英語表記のフォント名に変換
//
// usesにDirect2D,D2D1が必要
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LIDWriteFontCollection : IDWriteFontCollection;
LIDWriteFontFamily : IDWriteFontFamily;
LIDWriteLocalizedStrings : IDWriteLocalizedStrings;
LBuffer : array[0..LOCALE_NAME_MAX_LENGTH-1] of Char;
LlocaleName_JP : string;
LlocaleName_EN : string;
LIndex : Cardinal;
Lexists : LongBool;
i : Integer;
begin
Memo1.Lines.Clear;
//言語のロケール名
LlocaleName_JP := 'ja-JP';
LlocaleName_EN := 'en-US';
//インストールされているフォントセットのオブジェクトを取得
DWriteFactory.GetSystemFontCollection(LIDWriteFontCollection);
//取得したオブジェクトからフォント情報を順番に取得
for i := 0 to LIDWriteFontCollection.GetFontFamilyCount - 1 do begin
LIDWriteFontCollection.GetFontFamily(i, LIDWriteFontFamily);
LIDWriteFontFamily.GetFamilyNames(LIDWriteLocalizedStrings);
LIDWriteLocalizedStrings.FindLocaleName(LlocaleName_JP[1], LIndex, Lexists);
if not Lexists then Continue;
//日本語のフォント名を取得
LIDWriteLocalizedStrings.GetString(LIndex, LBuffer, Length(LBuffer));
//目的の日本語フォント名だったら英語表記のフォント名を取得
if Edit1.Text = LBuffer then begin
LIDWriteLocalizedStrings.FindLocaleName(LlocaleName_EN[1], LIndex, Lexists);
LIDWriteLocalizedStrings.GetString(LIndex, LBuffer, Length(LBuffer));
Memo1.Lines.Add(LBuffer);
break;
end;
end;
end;
//-----------------------------------------------------------------------------
// 引数のフォント名が英語フォント名でない場合,英語のフォント名を返す関数
// 引数のフォント名が英語フォント名の場合はそのままの値を返す
//
// usesにDirect2D,D2D1が必要
//-----------------------------------------------------------------------------
function GetUSEnglishFontName(AFontName: string): string;
var
LIDWriteFontCollection : IDWriteFontCollection;
LIDWriteFontFamily : IDWriteFontFamily;
LIDWriteLocalizedStrings : IDWriteLocalizedStrings;
LstringBuffer : array[0..LF_FACESIZE-1] of Char;
LResultName : string;
i : Integer;
j : Integer;
begin
Result := '';
//インストールされているフォントセットのオブジェクトを取得
DWriteFactory.GetSystemFontCollection(LIDWriteFontCollection);
//取得したオブジェクトからフォント情報を順番に取得
for i := 0 to LIDWriteFontCollection.GetFontFamilyCount - 1 do begin
LIDWriteFontCollection.GetFontFamily(i, LIDWriteFontFamily);
LIDWriteFontFamily.GetFamilyNames(LIDWriteLocalizedStrings);
LResultName := '';
for j := 0 to LIDWriteLocalizedStrings.GetCount - 1 do begin
LIDWriteLocalizedStrings.GetString(j, LstringBuffer, Length(LstringBuffer));
//最初のフォント名は英語名
if j = 0 then begin
if AFontName = LstringBuffer then begin
Result := LstringBuffer;
break;
end else begin
LResultName := LstringBuffer;
end;
//もし2番目以降があれば英語名以外のフォント名
end else begin
if AFontName = LstringBuffer then begin
Result := LResultName;
Break;
end;
end;
end;
if Result <> '' then Break;
end;
end;
//=============================================================================
// フォント選択ダイアログを表示
// 選択した日本語フォント名等を英語フォント名に変換
// Edit1に直接入力したフォント名も変換可能
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LFontName : string;
begin
if CheckBox1.Checked then begin
if FontDialog1.Execute(Handle) then begin
Edit1.Text := FontDialog1.Font.Name;
LFontName := GetUSEnglishFontName(Edit1.Text);
Memo1.Text := LFontName;
end;
end else begin
LFontName := GetUSEnglishFontName(Edit1.Text);
Memo1.Text := LFontName;
end;
end;
end.
|