Delphi Programming / Object Pascal
[掲載 2005年01月01日] [更新 2016年04月17日] Delphi サンプルプログラム集 |
180_斜体フォントの幅 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro
Delphi 2009 以降専用 |
|
180_ItalicTextWidth.zip [1,077 KB] 2016年04月17日版 (EXE 同梱) |
- 2016年04月17日
- DHGL を使用する文字列幅の取得サンプルを追加
|
斜体フォントの幅を求めるサンプルです.
斜体フォントでテキストを描画して,そのテキストの幅と高さを取得します.そして,その描画領域の矩形を描画します.斜体フォントの幅は,GetCharABCWidths 関数を使用して,下図のようなフォントの ABC 幅と呼ばれる値を取得して計算しています.
True Type でないフォントの場合は,GetCharWidth32 関数を使用します.本サンプルは True Type フォントを対象にしています.
斜体フォントについては,中村拓男さんの著書に詳しい説明があります.
|
|
図1
フォントの ABC 幅の意味 |
下図が設計時と実行時の画面です.フォームの Canvas に描画するので,ボタンが 1 つだけです. |
|
図2
設計時画面 |
|
図3
実行画面
|
欧文フォントのテスト結果です.フォントの設定を次のコードに変更して実行しています.
欧文フォントは,Charset の値が SHIFTJIS_CHARSET の場合,フォント名の設定が反映されないことがあることに注意してください.
結果を見ると,先頭の文字 A が枠の左側に少しはみ出ています.これは,先頭の文字の ABC 幅を考慮していないためです.これを回避するには,先頭の文字の ABC 幅を計算して,描画開始位置と描画幅を計算する必要があります.
|
Canvas.Font.Name := 'Times New Roman';
Canvas.Font.Charset := ANSI_CHARSET;
|
図4
欧文フォントでの実行例 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
function ItalicTextWidth(ACanvas:TCanvas; AFont:TFont; Text:String): Integer;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// テスト実行
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LStrText : String;
LTextWidth : Integer;
LTextHeight : Integer;
LTop : Integer;
LLeft : Integer;
begin
LStrText := '列的の文字列';
LTop := 40;
LLeft := 8;
//描画に使用する共通のフォント設定
Canvas.Font.Name := 'MS Pゴシック';
Canvas.Font.Charset := SHIFTJIS_CHARSET;
//普通の書体でFormのCanvasに文字列を描画
Canvas.Font.Style := [];
Canvas.Brush.Color := clWhite;
Canvas.Font.Size := 38;
Canvas.TextOut(LLeft, LTop, LStrText);
LTextWidth := ItalicTextWidth(Canvas, Canvas.Font, LStrText);
LTextHeight := Canvas.TextHeight(LStrText);
//文字列を囲む領域に矩形を描画
Canvas.Brush.Color := clBlack;
Canvas.FrameRect(Rect(LLeft, LTop, LLeft + LTextWidth, LTop + LTextHeight));
//斜体フォントにして描画
LTop := LTop + LTextHeight + 10;
Canvas.Font.Style := [fsItalic];
Canvas.Brush.Color := clWhite;
Canvas.TextOut(LLeft, LTop, LStrText);
//文字列の幅を取得して,文字列を囲む領域に矩形を描画
LTextWidth := ItalicTextWidth(Canvas, Canvas.Font, LStrText);
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(LLeft, LTop, LLeft + LTextWidth, LTop + LTextHeight);
end;
//=============================================================================
// 文字列の幅(通常,斜体のテキスト幅)を求める関数
//
// ACanvas : テキストを描画するCanvas
// AFont : テキスト描画に使用するフォント
// Text : 描画テキスト文字列
//=============================================================================
function TForm1.ItalicTextWidth(ACanvas:TCanvas; AFont:TFont; Text: String): Integer;
var
LpStrText : PChar;
LCode : Cardinal;
LABCwidth : TABC;
begin
if not(Assigned(AFont)) or (Text = '') then begin
Result := 0;
end else begin
//最後の文字のABC幅だけ求めればよい
LpStrText := AnsiLastChar(Text);
if LpStrText^ in LeadBytes then begin
LCode := (Ord(LpStrText^) shl 8) + Ord((LpStrText + 1)^);
end else begin
LCode := Ord(LpStrText^);
end;
GetCharABCWidths(ACanvas.Handle, LCode, LCode, LABCwidth);
//結果は負数なので...
Result := ACanvas.TextWidth(Text) - (LABCwidth.abcC);
end;
end;
end.
02_ABC 幅を含めた文字列の長さ - DHGL の関数を使用 |
上のサンプルで示したように,文字列の長さを正確に取得するには,ABC 幅 (ペアリング) の値が必要であることが分かりました.
中村拓男氏で提供している DHGL に,TextUtils というユニットがあります.このユニットに ABC 幅を取得するための関数が実装されています.以下は,その関数を使用した結果と,テスト用のサンプルのコードです.
|
|
図5
ABC 幅を含めた文字列の長さ
- 細線は,文字列の幅と高さの四角形
- 上は,単純に TCanvas.TextWidth 関数で取得した場合
- 下が ABC 幅を考慮した場合
|
リスト2
ABC 幅を含めた文字列の長さ - DHGL の関数を使用 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TMainForm = class(TForm)
FontDialog: TFontDialog;
FontChangeButton: TButton;
procedure FontChangeButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
MainForm: TMainForm;
implementation
uses
TextUtils;
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TMainForm.FormCreate(Sender: TObject);
begin
FontDialog.Font := Font;
end;
//=============================================================================
// [フォント変更]ボタン
// フォントによる違いがあるかを確認するため
//=============================================================================
procedure TMainForm.FontChangeButtonClick(Sender: TObject);
begin
if FontDialog.Execute then begin
Canvas.Font := FontDialog.Font;
Invalidate;
end;
end;
//=============================================================================
// フォームのOnPaintイベント処理
// 文字列の幅の取得
// ABC幅を含める場合と含めない場合の違いの確認用
//
// GetTextAAdjust 関数
// 文字列の最初の文字のベアリング(A幅)が負の時の値にその値を正の整数値で返す
// GetTextCAdjust 関数
// 文字列の最後の文字のベアリング(C幅)が負の時にその値を正の整数値で返す
//
// usesにTextUtils(中村拓男氏作)が必要
//=============================================================================
procedure TMainForm.FormPaint(Sender: TObject);
var
LText : string;
LAAdjust : Integer;
LCAdjust : Integer;
LTextWidth : Integer;
LTextHeight : Integer;
LLeft : Integer;
LTop : Integer;
begin
//描画する文字列
LText := 'fontf';
//文字のABC幅関係の値を取得
LAAdjust := TextUtils.GetTextAAdjust(Canvas, LText);
LCAdjust := TextUtils.GetTextCAdjust(Canvas, LText);
//描画開始位置
LLeft := 20;
LTop := 50;
LTextWidth := Canvas.TextWidth(LText);
LTextHeight := Canvas.TextHeight(LText);
//ABC幅を考慮しない場合
Canvas.Brush.Style := bsSolid;
Canvas.TextOut(LLeft, LTop, LText);
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(LLeft,
LTop,
LLeft + LTextWidth,
LTop + LTextHeight);
//ABC幅を考慮した場合
LTop := LTop + LTextHeight + 30;
Canvas.Brush.Style := bsSolid;
Canvas.TextOut(LLeft + LAAdjust, LTop, LText);
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(LLeft,
LTop,
LLeft + LTextWidth + LAAdjust + LCAdjust,
LTop + LTextHeight);
end;
end.
|