AFsoft WebSite(エーエフソフト・ウェブサイト)
 

オペレーティング・システムについて

プログラミングについて
ホームページについて
キャドについて
電子カタログについて
書籍・雑誌
イベント
リンク集
Delphi2010 Direct2D(2) 2010/12/08

それではもう少し、Direct2Dについて見ていきます。
テスト32(フォルダ「032」)として新規作成しておきます。
 
ヘルプでは、OnPaintイベントハンドラで TDirect2DCanvasインスタンスを作成し、描画を行い、すぐに解放しています。
これが必要なのは、そのたびにフォームに関連付けられた実際のデバイスコンテキストHDC)が変わって、前に作成された TDirect2DCanvasインスタンスが無効になる可能性があるためです。この方法は非常に単純ではありますが、実際には採用できない可能性があります。再描画のたびに Direct2D リソースを取得し解放しなければならないからです。
とあるのですが、この意味が少々分かりにくいのですが、確かに、ヘルプにある
LCanvas := TDirect2DCanvas.Create(Canvas, ClientRect);
というようにHDC経由で生成している場合には、パターンがよく分からないのですが、作図出来たり出来なかったり、という状況があるようです(※実際に確認しました)。しかし、Windowsハンドルを経由して生成した場合、これもヘルプにありますが
LCanvas := TDirect2DCanvas.Create(Handle);
この場合は、HDC経由で生成して描画しなかった同じプログラムでも描画出来ますが、これは、Windowsハンドルはウインドウを一度生成してそれを閉じるまでは変わらないためかと思われます。しかし、同じヘルプ画面でこの2通りを示した状態で、その違いや出来る・出来ないについて言及されていない、というのはちょっと「???」です。そういうわけで私としては、HDC経由ではなく、Windowハンドル経由でプログラムを作る事にします。
 
この場合、Formの場合には、ハンドルもあり、キャンバス(Canvas)もありますから、そのまま使えるのですが、例えばパネル(Panel)を置いてその上に、となると、パネルにはハンドルはありますがキャンバスはありません。ペイントボックス(PaintBox)を配置して、という場合には、ペイントボックスにキャンバスはありますが、ハンドルはありません。そこで、パネルを配置し、その上にペイントボックスを配置します。

プログラムを下記のようにしてみます。
unit Unit1;
 
interface
 
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, StdCtrls, Direct2D, D2D1 ;
 
type
 TForm1 = class(TForm)
  StatusBar1: TStatusBar;
  Panel1: TPanel;
  Panel2: TPanel;
  Splitter1: TSplitter;
  PaintBox1: TPaintBox;
  Button1: TButton;
  procedure FormShow(Sender: TObject);
  procedure FormClose(Sender: TObject; var Action: TCloseAction);
  procedure Button1Click(Sender: TObject);
 private
  { Private 宣言 }
  D2DCanvas : TDirect2DCanvas ;
  D2DCanvasFlag : Boolean ;
 public
  { Public 宣言 }
 end;
 
var
 Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 if (D2DCanvasFlag) then begin
  // Direct2D
  D2DCanvas.BeginDraw;
  try
   with D2DCanvas do begin
    Brush.Color := clWhite ;
    Pen.Color := clBlue;
    Rectangle(0, 0, 100, 100);
   end;
  except
   ;
  end;
  D2DCanvas.EndDraw;
 end
 else begin
  // WindowsGDI
  with PaintBox1.Canvas do begin
   Brush.Color := clWhite ;
   Pen.Color := clBlue;
   Rectangle(0, 0, 100, 100);
  end;
 end;
end;
 
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 if (D2DCanvasFlag) then
  D2DCanvas.Free;
end;
 
procedure TForm1.FormShow(Sender: TObject);
begin
 // Direct2D が使えるかどうかのチェック
 D2DCanvasFlag := False ;
 if TDirect2DCanvas.Supported then begin
  try
   D2DCanvas := TDirect2DCanvas.Create(Panel1.Handle);
   D2DCanvasFlag := True ;
  except
   ;
  end;
 end;
 if (D2DCanvasFlag) then
  StatusBar1.SimpleText := 'Direct2D<OK>'
 else
  StatusBar1.SimpleText := 'Direct2D<NG>';
end;
 
end.
という具合にすれば、従来のWindowsGDI と Direct2D の双方をサポートするようなプログラムが書けるかな?という趣向です。ただ、WindowsGDI は TCanvas、Direct2D は TDirect2DCanvas と”別物”であるため、描画ルーチンで似たようなものを2つ描かないといけないのは多少イマイチかもしれません。が、描画データを別に持って、そのデータを参照して描画するようなプログラムであれば、一度共通プログラムを作ってしまえばさほどの負担ではないかもしれません。
 
プログラムを保存・コンパイル(再構築)・実行し、ボタンをクリックします。

WindowsGDI時(Direct2Dが使えない状態)
 

Direct2D時
 
というようになりますから、最初は、クライアント領域一杯に独自指定の背景色でベタ塗りを意図的に行った方が良いかもしれません。なお、この状態で画面をリサイズし、ボタンをクリックすると・・・

WindowsGDI時(Direct2Dが使えない状態)
 

Direct2D時
 
という具合に、Direct2Dの場合は ストレッチされるように拡大縮小されてしまうようです。これはこれで面白いと思いますが、リサイズ時には、一旦解放をして再生成を行い、ストレッチされないようにするのが普通かもしれません。
・・・
type
 TForm1 = class(TForm)
  ・・・
 private
  { Private 宣言 }
  D2DCanvas : TDirect2DCanvas ;
  D2DCanvasFlag : Boolean ;
  procedure D2Dinit ;
 public
 
・・・
 
procedure TForm1.D2Dinit ;
begin
 // Direct2D が使えるかどうかのチェック
 D2DCanvasFlag := False ;
 if TDirect2DCanvas.Supported then begin
  try
   D2DCanvas := TDirect2DCanvas.Create(Panel1.Handle);
   D2DCanvasFlag := True ;
  except
   ;
  end;
 end;
 if (D2DCanvasFlag) then
  StatusBar1.SimpleText := 'Direct2D<OK>'
 else
  StatusBar1.SimpleText := 'Direct2D<NG>';
end;
 
procedure TForm1.FormResize(Sender: TObject);
begin
 if (D2DCanvasFlag) then begin
  D2DCanvas.Free;
  //
  D2Dinit ;
 end;
end;
 
procedure TForm1.FormShow(Sender: TObject);
begin
 D2Dinit ;
end;
このようにして保存・コンパイル(再構築)・実行をすれば、リサイズしてボタンをクリックしてもストレッチされるような状態にはなりません。

Before


After
 
ただ、ここではボタンを押して描画を行うようになっていますから気にならないのですが、リサイズを行っている最中に、何度も画面の自動再描画が行われるようです。画面が何かで隠されたり、最小化(アイコン化)して通常表示したり最大化するような場合にも、画面の自動再描画は行われます。この場合、OnPaintイベントハンドラにて画面の再描画を行うようにするのが通常なのですが、今回のように四角を描くだけなら気になりませんが、時間の掛かるような巨大な描画データとなると、リサイズをしている最中に何度もそれが行われてしまい、使いにくくなってしまうのは容易に想像出来てしまいます。その場合は、何らかの回避手段を行う必要がありますので注意して下さい。
 
 
次に、ボタンをクリックした時の処理を下記のようにしてみます。
procedure TForm1.Button1Click(Sender: TObject);
var
 px,py : integer ;
begin
 px := PaintBox1.ClientWidth ;
 py := PaintBox1.ClientHeight ;
 if (D2DCanvasFlag) then begin
  // Direct2D
  D2DCanvas.BeginDraw;
  try
   with D2DCanvas do begin
    Brush.Color := clWhite ;
    Pen.Color := clBlue;
    Rectangle(0, 0, px, py);
    Pen.Color := clRed ;
    Pen.Style := psDot ;
    MoveTo(0,0);
    LineTo(px,py);
    MoveTo(0,py);
    LineTo(px,0);
   end;
  except
   ;
  end;
  D2DCanvas.EndDraw;
 end
 else begin
  // WindowsGDI
   with PaintBox1.Canvas do begin
    Brush.Color := clWhite ;
    Pen.Color := clBlue;
    Rectangle(0, 0, px, py);
    Pen.Color := clRed ;
    Pen.Style := psDot ;
    MoveTo(0,0);
    LineTo(px,py);
    MoveTo(0,py);
    LineTo(px,0);
   end;
 end;
end;
これを保存・コンパイル(再構築)・実行すると下記のようになります。

WindowsGDI時(Direct2Dが使えない状態)
 

Direct2D時
 
というように、プロパティ・メソッドはおおよそ同じように利用出来るようです。が、一部対応していないものもあるようです。上記でも、同じ点線(psDot)でも線種ピッチが随分違うのが見て取れますし、例えば、Pixel プロパティは使えないとの事です。使えないものについては、PaintBoxのCanvasに対して行うようにすれば、出来ない、という事はありません。この辺りがこの TCanvas と TDirect2DCanvas を両用するメリットの1つではないかと思います。
 
このほか、Direct2DのTDirect2DCanvasには、独自のメソッド(関数・手続き)があるようです。次回はそれについて見ていきたいと思います。
 
バッチファイル
BASIC
C言語のお勉強
拡張子な話
DOSプログラム
Delphi
>Delphi入門編
>Delphi2010
▲2010/12/05
 2010/12/08
▼2010/12/09
 
シェアウェア
Script!World
データベース
 
お問い合わせ
本サイトはリンクフリーです
リンクバナー
(C)Copyright 1999-2015. By AFsoft All Rights Reserved.