Delphi Programming / Object Pascal
[掲載 2012年12月09日] [更新 2012年12月09日] GDI+ 関係サンプル |
GDI+ 関係サンプル
G070_ワールド座標系とページ座標系 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
G070_GDIPlus_TranslateTransformScale.zip [1,196 KB] 2012年12月09日版 (EXE 同梱) |
座標の原点,(0, 0) は,通常,コントロールや Canvas の左上の隅です.
GDI+ では,この原点を移動して設定することができます.また,X軸,Y軸の倍率の設定,つまりスケーリングも設定することができます.
この機能は,例えば,関数のグラフの作成に使えます.原点の移動をしなければ,単なる拡大・縮小表示にも利用可能です.このページのサンプルは,単にこの機能を確認するだけのプログラムです.
原点がデフォルトの左上の時,GDI+ では「ワールド座標系」,原点を再設定したり,軸のスケーリングをした座標を「ページ座標系」と言っています.「デバイス座標系」というのもありますが,ここでは省略します. |
このサンプルでは以下のコントロールを使用しています.
- TrackBar1 X 軸方向の原点移動量の設定
- TrackBar2 Y 軸方向の原点移動量の設定
- ComboBox1 X 軸と Y 軸のスケーリング (X, Y 軸共同じ値)
原点の移動とスケーリングには以下の関数を使用します.
- 原点の設定関数 TGPGraphics.TranslateTransform
- スケーリングの関数 TGPGraphics.ScaleTransform
画像と文字列の描画は,次のようになっています.描画の始点は (0, 0) となっています. |
GDPGraphic.DrawImage(GDPImage, MakeRect(0, 0, 100, 100));
GDPGraphic.DrawString('DELPHI', -1, GDPFont, MakePoint(0.0, 0.0), GDPBrush);
プログラムを実行して,トラックバーを操作すると,画像と文字列が画面上を移動します.通常であれば,描画始点が (0, 0) となっていますから,左上に表示されるはずのものが移動して表示されます.これは,原点が移動し,新しいワールド座標系の原点を始点として描画されるからです.
このサンプルでは,原点を移動した後にスケーリングを実行しています.これを逆にすると,スケーリング後の値で原点移動します.したがって結果は違ってくることになります. |
|
図1
設計時画面 |
|
図2
実行開始時の画面
- 描画始点が (0, 0) なので左上から表示されている
|
|
図3
トラックバーを操作
|
次に,コンボボックスでスケーリングの値を変更してみます.
画像と文字列が拡大するのが確認できます.軸スケールそのものが拡大されます.したがって,描画内容である線の太さ等も拡大または縮小されることになります. |
|
図4
スケーリングを変更した結果
- 描画用コントロールである TMyPanel の描画スケールが変わる
|
リスト1
ワールド座標系とページ座標系の確認のためのテスト |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FXLocation : Single;
FYLocation : Single;
FScale : Single;
procedure SetXLocation(const Value: Single);
procedure SetYLocation(const Value: Single);
procedure SetScale(const Value: Single);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property XLocation : Single read FXLocation write SetXLocation;
property YLocation : Single read FYLocation write SetYLocation;
property Scale : Single read FScale write SetScale;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
TrackBar2: TTrackBar;
ComboBox1: TComboBox;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure TrackBar2Change(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ ページ座標と軸方向の倍率';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 70, Self.ClientWidth - 10, Self.ClientHeight - 75);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//水平方向への原点行移動
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -250;
Max := 250;
Position := 0;
end;
//垂直方向への原点移動
with TrackBar2 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -150;
Max := 150;
Position := 0;
end;
//スケーリング
ComboBox1.Items.Clear;
ComboBox1.Style := csDropDownList;
ComboBox1.Items.CommaText := '0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0';
ComboBox1.ItemIndex := 2;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// X軸方向の座標原点の移動
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.XLocation := TrackBar1.Position;
end;
//=============================================================================
// TrackBar2のOnClickイベント処理
// Y軸方向の座標原点の移動
//=============================================================================
procedure TForm1.TrackBar2Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.YLocation := TrackBar2.Position;
end;
//=============================================================================
// ComboBox1のOnClickイベント処理
// 座標のスケーリング設定
//=============================================================================
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.Scale := StrToFloat(ComboBox1.Items[ComboBox1.ItemIndex]);
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティの初期化
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FXLocation := 0.0;
FYLocation := 0.0;
FScale := 1.0;
end;
//-----------------------------------------------------------------------------
// XLocationプロパティ設定用メソッド
// X軸方向の原点移動
//-----------------------------------------------------------------------------
procedure TMyPanel.SetXLocation(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FXLocation <> Value then begin
FXLocation := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// YLocationプロパティ設定用メソッド
// Y軸方向の原点移動
//-----------------------------------------------------------------------------
procedure TMyPanel.SetYLocation(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FYLocation <> Value then begin
FYLocation := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// Scaleプロパティ設定用メソッド
// 座標軸のスケーリング
//-----------------------------------------------------------------------------
procedure TMyPanel.SetScale(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FScale <> Value then begin
FScale := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LImageFilePath : String;
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
LGPFont : TGPFont;
LGPBrush : TGPSolidBrush;
begin
inherited;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + '503.bmp';
LGPImage := TGPImage.Create(LImageFilePath);
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//念のためリセット
LGPGraphic.ResetTransform;
//座標の原点を (FXLocation, FYLocation) に移動する
//これをページ座標とも言う
LGPGraphic.TranslateTransform(FXLocation, FYLocation);
//水平方向(X軸方向),垂直方向(Y軸方向)の倍率を共にFScale倍にする
LGPGraphic.ScaleTransform(FScale, FScale);
//上の設定で,画像オブジェクトを描画
//描画始点は (0, 0) となっているが,ワールド座標では (FXLocation, FYLocation)
LGPGraphic.DrawImage(LGPImage, MakeRect(0, 0, 100, 100));
//フォントとブラシを生成して文字列を描画
//これも描画始点は (0, 0)
LGPFont := TGPFont.Create('Arial', 30, FontStyleRegular, UnitPixel);
LGPBrush := TGPSolidBrush.Create(MakeColor(255, 0, 0, 0));
LGPGraphic.DrawString('DELPHI', -1, LGPFont, MakePoint(0.0, 0.0), LGPBrush);
//Createしたオブジェクトは解放する
LGPFont.Free;
LGPBrush.Free;
LGPImage.Free;
LGPGraphic.Free;
end;
end.
次は,座標の原点が移動した座標系,マイクロソフトの解説で言うところのページ座標系での値を,元々の,左上が原点 (0, 0) であるワールド座標系の座標値に変換するテストです.
移動後の原点と,スケーリングの値から計算してもかまいませんが,TransformPoints という関数が利用できます.この関数は引数の指定により,逆の変換もできます.サンプルでは,この関数を使用して,画像の表示領域の矩形を描画します.
当然ですが,画像を囲む枠線を描画するだけであれば,わさわざ変換しなくても,ページ座標系の座標値でできます. |
|
図5
実行開始画面 |
|
図6
実行結果例
- 画像を囲む枠線が描画されている
- コンボボックスで描画スケールを変更しているので,TMyPanel の描画スケールが変わっている
|
リスト2
ページ座標系の座標値を,ワールド座標系の座標値に変換 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPAPI, GDIPOBJ, ComCtrls;
type
TMyPanel = class(TPanel)
private
FXLocation : Single;
FYLocation : Single;
FScale : Single;
procedure SetXLocation(const Value: Single);
procedure SetYLocation(const Value: Single);
procedure SetScale(const Value: Single);
protected
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
property XLocation : Single read FXLocation write SetXLocation;
property YLocation : Single read FYLocation write SetYLocation;
property Scale : Single read FScale write SetScale;
end;
TForm1 = class(TForm)
TrackBar1: TTrackBar;
TrackBar2: TTrackBar;
ComboBox1: TComboBox;
procedure FormCreate(Sender: TObject);
procedure TrackBar1Change(Sender: TObject);
procedure TrackBar2Change(Sender: TObject);
procedure ComboBox1Change(Sender: TObject);
private
{ Private 宣言 }
MyPanel : TMyPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := 'GDI+ ワールド座標系の座標値に変換';
//描画するコントロールを生成
MyPanel := TMyPanel.Create(Self);
with MyPanel do begin
Parent := Self;
SetBounds(5, 70, Self.ClientWidth - 10, Self.ClientHeight - 75);
DoubleBuffered := True;
ControlStyle := MyPanel.ControlStyle + [csOpaque];
BevelOuter := bvNone;
Visible := True;
Color := clWhite;
ParentBackground := False;
Anchors := [akLeft, akTop, akRight, akBottom];
end;
//水平方向への原点行移動
with TrackBar1 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -250;
Max := 250;
Position := 0;
end;
//垂直方向への原点移動
with TrackBar2 do begin
ShowSelRange := False;
TickStyle := tsNone;
Height := 26;
Min := -150;
Max := 150;
Position := 0;
end;
//スケーリング
ComboBox1.Items.Clear;
ComboBox1.Style := csDropDownList;
ComboBox1.Items.CommaText := '0.2, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0';
ComboBox1.ItemIndex := 2;
end;
//=============================================================================
// TrackBar1のOnClickイベント処理
// X軸方向の座標原点の移動
//=============================================================================
procedure TForm1.TrackBar1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.XLocation := TrackBar1.Position;
end;
//=============================================================================
// TrackBar2のOnClickイベント処理
// Y軸方向の座標原点の移動
//=============================================================================
procedure TForm1.TrackBar2Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.YLocation := TrackBar2.Position;
end;
//=============================================================================
// ComboBox1のOnClickイベント処理
// 座標のスケーリング設定
//=============================================================================
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
if not Assigned(MyPanel) then exit;
MyPanel.Scale := StrToFloat(ComboBox1.Items[ComboBox1.ItemIndex]);
end;
{ TMyPanel }
//-----------------------------------------------------------------------------
// コンストラクタ
// 各種プロパティの初期化
//-----------------------------------------------------------------------------
constructor TMyPanel.Create(AOwner: TComponent);
begin
inherited;
FXLocation := 0.0;
FYLocation := 0.0;
FScale := 1.0;
end;
//-----------------------------------------------------------------------------
// XLocationプロパティ設定用メソッド
// X軸方向の原点移動
//-----------------------------------------------------------------------------
procedure TMyPanel.SetXLocation(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FXLocation <> Value then begin
FXLocation := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// YLocationプロパティ設定用メソッド
// Y軸方向の原点移動
//-----------------------------------------------------------------------------
procedure TMyPanel.SetYLocation(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FYLocation <> Value then begin
FYLocation := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// Scaleプロパティ設定用メソッド
// 座標軸のスケーリング
//-----------------------------------------------------------------------------
procedure TMyPanel.SetScale(const Value: Single);
begin
if not Assigned(Parent) then exit;
if FScale <> Value then begin
FScale := Value;
Invalidate;
end;
end;
//-----------------------------------------------------------------------------
// TMyPanelクラスのPaintメソッド
// 実際の描画コード
//-----------------------------------------------------------------------------
procedure TMyPanel.Paint;
var
LPoints : array [0..1] of TGPPointF;
LObjWidth : Single;
LObjHeight : Single;
LStartX : Single;
LStartY : Single;
LImageFilePath : String;
LGPImage : TGPImage;
LGPGraphic : TGPGraphics;
LGPPen : TGPPen;
LObjRect : TGPRectF;
begin
inherited;
//元の画層のサイズではなく,別の幅と高さで描画する
LObjWidth := 100.0;
LObjHeight := 100.0;
//描画始点
LStartX := 0.0;
LStartY := 0.0;
//画像ファイルを指定.TGPImaageインスタンスを生成して読み込む
LImageFilePath := ExtractFilePath(ParamStr(0)) + '503.bmp';
LGPImage := TGPImage.Create(LImageFilePath);
//このTMyPanelのCanvasを描画先にしてTGPGraphicsのインスタンスを生成
LGPGraphic := TGPGraphics.Create(Canvas.Handle);
//念のためリセット
LGPGraphic.ResetTransform;
//座標の原点を (FXLocation, FYLocation) に移動する
//これをページ座標と言う
LGPGraphic.TranslateTransform(FXLocation, FYLocation);
//水平方向(X軸方向),垂直方向(Y軸方向)の倍率を共にFScale倍にする
LGPGraphic.ScaleTransform(FScale, FScale);
//上の設定で,画像オブジェクトを描画
LGPGraphic.DrawImage(LGPImage, MakeRect(LStartX, LStartY, LObjWidth, LObjHeight));
//---------------------------------------------------------------------------
// 以下,ページ座標系の座標値をワールド座標系の値に変換するコード
// 画像オブジェクトを囲む矩形を描画する
// ページ座標系のままで描画してもよいが,軸のスケールを変換していると,線の
// 太さも拡大・縮小されてしまう
//---------------------------------------------------------------------------
//描画開始座標値と対角点の座標の値を配列に格納
LPoints[0] := MakePoint(0.0, 0.0);
LPoints[1] := MakePoint(LObjWidth, LObjHeight);
//ワールド座標系の値に変換
LGPGraphic.TransformPoints(CoordinateSpacePage,
CoordinateSpaceWorld,
PGPPointF(@LPoints),
Length(LPoints));
//座標系をワールド座標系に戻す
LGPGraphic.ResetTransform;
//ペンのオブジェクト生成し,それで四角形を描く
LGPPen := TGPPen.Create(aclBlack);
LGPPen.SetDashStyle(DashStyleDash);
LObjRect := MakeRect(LPoints[0].X,
LPoints[0].Y,
LPoints[1].X - LPoints[0].X,
LPoints[1].Y - LPoints[0].Y);
LGPGraphic.DrawRectangle(LGPPen, LObjRect);
//Createしたオブジェクトは解放する
LGPPen.Free;
LGPImage.Free;
LGPGraphic.Free;
end;
end.
|