Delphi Tips 
-----------------------------

キーワード:描画

>> Index

09/15 Win98 でタイトルバーのグラデーション色を得る
09/13 TFontDialog で標準以外のサイズを選択肢に表示したい
09/09 Metafile が Draw で1ピクセル小さく描画される
08/31 全角文字が半角文字の2倍幅になるフォントの選び方
08/13 TColor 値を文字列に変換する
05/14 システムカラーを得る、設定する
02/11 API を使って縦書きなどのフォントを指定する
02/08 SetWindowsExt/SetViewportExtを使うときの注意点

最終更新: 6825 日前

0260  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/15 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/15 osamu 編集
Win98 でタイトルバーのグラデーション色を得る

const
  COLOR_GRADIENTACTIVECAPTION   = 27;
  COLOR_GRADIENTINACTIVECAPTION = 28;

という前提で、GetSysColor() API を使用してください。
DWORD の色がかえります。( TColor に代入できます )

どーせやるなら、

const
  COLOR_GRADIENTACTIVECAPTION   = 27;
  COLOR_GRADIENTINACTIVECAPTION = 28;
  clGradientActiveCaption   = $80000000 + COLOR_GRADIENTACTIVECAPTION;
  clGradientInactiveCaption = $80000000 + COLOR_GRADIENTINACTIVECAPTION;

としておくと便利かもしれません。
この状態で、 Delphi4 の ColorToRGB のソースを見るかぎりでは

  ColorToRGB(clGradientActiveCaption)

は正常に動作します。

ところで…この定数ですが、、、、Delphi4 にも定義されていないようです。
# たんに、私が未確認なだけでしょうか?

勝手に Graphic.pas (Desktop 版では Graphic.int)に書き足しておいても問題はないと思うのですが…。。。
参照: [Delphi-ML:34285]

0253  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/13 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/13 osamu 編集
TFontDialog で標準以外のサイズを選択肢に表示したい

> ルビをうつフォントを指定しようと思い、TFontDialogで
> 片付けようと思いましたが、TFontDialogで、MSゴシック
> など8Pt以下のポイントが出てきません。指定できるように
> する方法をどなたかご存知でしょうか。

思いっきり強引ですけど

unit FontDialogEx;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs;
type
  TFontDialogEx = class(TFontDialog)
  protected
    function TaskModalDialog(DialogFunc: Pointer;
                             var DialogData): Bool; override;
  end;

procedure Register;

implementation

uses Dlgs, CommDlg;

const
  WM_FONTDIALOGEX = WM_USER + 256;
  str1: string = '4';
  str2: string = '5';
  str3: string = '6';
  str4: string = '7';

var
  OldHook: function(Wnd: HWnd; Msg: UINT; WParam: WPARAM;
                    LParam: LPARAM): UINT; stdcall;

function FontDialogHookEx(Wnd: HWnd; Msg: UINT; WParam: WPARAM;
                          LParam: LPARAM): UINT; stdcall;
begin
  if (Msg = WM_COMMAND) and (LOWORD(WParam) = cmb1) then begin
    PostMessage(Wnd, WM_FONTDIALOGEX, 0, 0);
  end;

  if Msg = WM_FONTDIALOGEX then begin
    SendDlgItemMessage(Wnd, cmb3, CB_RESETCONTENT, 0, 0);
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str1)));
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str2)));
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str3)));
    SendDlgItemMessage(Wnd, cmb3, CB_ADDSTRING, 0, LongInt(PCHAR(str4)));
    Result := 1;
    exit;
  end;
  Result := OldHook(Wnd, Msg, WParam, LParam);
end;

function TFOntDialogEx.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
begin
  OldHook := TChooseFont(DialogData).lpfnHook;
  TChooseFont(DialogData).lpfnHook := FontDialogHookEx;
  inherited TaskModalDialog(DialogFunc, DialogData);
end;

procedure Register;
begin
  RegisterComponents('NkCtrls', [TFontDialogEx]);
end;

end.

一応動いてます(^^ フォント名毎に表示するサイズリストを変えたい場合は、cmb1 に選択されているフォント名を確認するコードが必要になるでしょう。

一瞬元のポイントサイズがコンボボックスに表示されてしまいますが今のところ他に良い手を思いつきません(^^;
参照: [Delphi-ML:42562] <ダイアログ> <Dialogs> <コンポーネント >

0248  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/09/09 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/09/09 osamu 編集
Metafile が Draw で1ピクセル小さく描画される

>拡張メタファイルを作成するツールを作ろうとしています。
>そこで、メタファイルに編集を加えるたびに以前編集した像が
>1ドット(?)ずつ縮小してしまう問題があるのです。

TMetafile.Draw を見ると

  R := Rect;
  Dec(R.Right);  // Metafile rect includes right and bottom coords
  Dec(R.Bottom);
  PlayEnhMetaFile(ACanvas.Handle, FImage.FHandle, R);

となっていて、描画先矩形を 1ドット分縮小しているのが原因のようです。
Win32 Programmer's Ref. で PlayEnhMetafile を見ると、

Points along the edges of the rectangle are included in the picture.

なんて微妙なことが書いてあるのですが、実際には Win98 で試してみた限り矩形領域を小さくするのは正しくないようです。Dec をコメントにすると完全に同じ大きさの図形が得られます。

対処としては graphics.pas を修正するか、Right, Bottom を一つ大きめに指定して StretchDraw するしかないようです。

ただ、ディスプレイデバイスとメタファイルの参照デバイスが異なると多少の誤差は避けられないようです。この辺を考慮して高精度のメタファイルを作るにはメタファイルを直接編集するしかないと思います。
参照: [Delphi-ML:33593] <画像> <バグ>

0230  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/31 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/31 osamu 編集
全角文字が半角文字の2倍幅になるフォントの選び方

等幅フォントを使っても、全角文字と半角文字を混ぜて使うと、桁の位置がずれて見づらくなってしまう場合があります。これは、特定のフォントサイズ以外では、全角文字が半角文字の2倍の幅にならないことに起因しています。

ピクセル単位とポイント単位の変換は以下のようになっています。

Point  = 72 * ( Pixels / GetDeviceCaps(hDC, LOGPIXELS_) )
Pixels = Point / 72 * GetDeviceCaps(hDC, LOGPIXELS_)

ここで、LOGPIXELS_ は LOGPIXELSX または LOGPIXELSY ですが、幅を問題にする場合には、LOGPIXELSX を使います。

Pixels が整数になるような Point 数の等幅フォントを使えば、全角文字がちょうど半角文字二つ分の幅になり、エディタのように使った場合に、「ずれ」が生じません。

たとえば、画面の設定が 96dpi の時、第2式は
Pixels = 4 * Point / 3
となりますので、適するサイズは、3の倍数ポイントのフォントということになります。
参照:

0203  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/08/13 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/08/13 osamu 編集
TColor 値を文字列に変換する

レジストリに TColor 型の値を格納したいような場合、ColorToString 関数を使えば TColor から AnsiString に変換できるので、あとは TRegistry の WriteString で書き出してやればいいと思います。
反対に AnsiString から TColor に戻すのは StringToColor 関数を使えばいいです。
詳しくはヘルプを見てください。
参照: [builder:17839] <文字列> <PASCAL>

0187  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/05/14 おばQ rev 1.3
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/05/14 おばQ 編集
システムカラーを得る、設定する

ひきさんのページ『日本Delphi振興会』にも載っていますが
更に情報を加えておきます。

WindowsAPIでWindowsのシステムカラーを得たり設定したりする事が出来ます。それぞれGetSysColor、SetSysColorというAPI関数です。

サンプルとしてButton1を押すと色の設定情報を読込み
Button2を押すと読込んだ情報を設定するというものを作りました。

Button1を押して
その後にコントロールパネルでWindowsの色設定を変更しても
Button2を押す事で変更前の色設定になります。

const
  SysColorMaxNumber=28;
type
  TForm1 = class(TForm)
…省略…
  private
    FList: array[0..SysColorMaxNumber] of Integer;
    FColorList: array[0..SysColorMaxNumber] of TColor;
    FRGBList: array[0..SysColorMaxNumber] of Longint;
  end;

…省略…
procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i:=0 to SysColorMaxNumber do
  begin
    FList[i] := i;
    FColorList[i] := TColor(GetSysColor(i));
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i: Integer;
begin
  for i:=0 to SysColorMaxNumber do
    FRGBList[i] := ColorToRGB(FColorList[i]);
  SetSysColors(SysColorMaxNumber,FList,FRGBList);
end;

GetSysColor(COLOR_ACTIVECAPTION)という定数も指定出来ます。この定数はwindows.pasに定義されています。

Delphiで定義されている色のclBtnFaceやclActiveCaptionとAPIでのGetSysColor(COLOR_ACTIVECAPTION)との違いは以下のようなコードで理解できるでしょう。

ShowMessage(IntToHex((clRed),8));
ShowMessage(IntToHex((clBtnFace),8));
ShowMessage(IntToHex(GetSysColor(COLOR_BTNFACE),8));
ShowMessage(IntToHex(ColorToRGB(clRed),8));
ShowMessage(IntToHex(ColorToRGB(clBtnFace),8));
ShowMessage(IntToHex(ColorToRGB(GetSysColor(COLOR_BTNFACE)),8));
参照:

0137  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/11 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/11 osamu 編集
API を使って縦書きなどのフォントを指定する

var
    lbl :TLogFont;
begin
    // ここをいろいろ変えれば縦横比を変えることができる
    // (日本語の場合、幅:高さ=1:2で横倍率が100%)
    lbl.lfWidth := 10;
    lbl.lfHeight := 20;
    // 文字の太さ(0〜1000)
    // 「標準」の太さは400、「太字」の太さは700
    lbl.lfWeight := 400;
    // 反時計回りの角度(単位は1/10度)
    lbl.lfEscapement := 2700;
    // 下線なし(デフォルトでは「あり」)
    lbl.lfUnderline := 0;
    // 打ち消し線なし(デフォルトでは「あり」)
    lbl.lfStrikeOut := 0;
    // 斜体無効(デフォルトでは有効)
    lbl.lfItalic := 0;
    // 縦書き用の「@」がつくフォントを使用する
    lbl.lfFaceName := '@MS ゴシック';

    // フォントを作成
    Canvas.Font.Handle := CreateFontIndirect(lbl);
    // キャンバスのブラシスタイルを変えることで
    // 背景を透明にして描画します
    Canvas.Brush.Style := bsClear;
    // 文字列を描画
    Canvas.TextOut(300, 300, '縦書き文字');
end;

参照: [Delphi-ML:24027] <その他コンポーネント関連> <コンポーネント >

0064  D1   D2   D3   D4   D5   D6   D7   3.1   95   98    作成: 1999/02/08 osamu rev 1.1
   B1   B3   B4   B5   B6   B7   NT3   NT4   2K   XP  更新: 1999/02/08 osamu 編集
SetWindowsExt/SetViewportExtを使うときの注意点

TCanvas.Handle に対してこれらの関数を呼んで使う際の注意点。

(1) Font.Height と Font.Size の関係はマッピングモードが MM_TEXT
    で有ることを仮定しているので SetMapMode API でマッピングモードを
    変えた場合は Font.Height のみを使った方が良いでしょう。
(2) API の効果の寿命はイベントハンドラ毎です。
    引き継がれません。
参照: [Delphi-ML:19671] <Windows>

[新規作成] [最新の情報に更新]

How To
Lounge
KeyWords

Tips
Delphi
Home
Osamu Takeuchi osamu@big.or.jp