|
画像・図形の移動リサイズ関係サンプル
R070_描画用コントロールの保存と読み出し |
動作確認等 |
Windows 10 ビルド 19045 Pro 64 bit + Delphi XE5(UP2) Pro VCL-32 |
 |
R070_SaveCtrl.zip [3.1 MB] 2025年04月16日版 (EXE 同梱)
描画用クラスのソースコードは [概要] ページからダウンロードする |
本ページより前のページのサンプルにおける保存は,描画内容をビットマップなどの画像として保存するものでした.本ページのサンプルは,描画コントロールそのものをコンポーネントとして保存して読み出す手順です.
描画用のコントロールを保存する処理は,プリケーションで利用する時に便利なことがあります.設定ダイアログなどを表示してプロパティを設定する場合,プロパティの設定の前に描画用コントロールを保存して退避しておけば,[キャンセル] の時に元に戻すことができます. |
描画用のコントロールのクラスが 1 種類だけの場合の例です.このサンプルでは楕円描画用のコントロールだけを使用しています. |
 |
図1
[生成] ボタンをクリック
|

|
図2
[図保存してクリア] ボタンをクリック
- コンテナコントロール上に配置している 描画用コントロールの保存となる
|
 |
図3
[読み込む] ボタンをクリック
- ラバーバンド,グラブハンドルは保存しないので再現しない
|
リスト1
図形としての保存と読み出し.描画用クラスが 1 つだけの例 |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL,
plGPResizeImage,
plGPResizeLine,
plGPResizeEllipseEx,
plContainerPanel,
plBaseDragResize;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
FBackCtrl : TplContainerPanel;
FFileName : String;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
// 専用のコンテナコントロールを生成
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel1.Caption := '';
FBackCtrl := TplContainerPanel.Create(Self);
FBackCtrl.Parent := Self;
FBackCtrl.Align := alClient;
FFileName := '01_SavedCtrols.dat';
end;
//=============================================================================
// [生成] ボタン
// ここで生成するのは TplGPResizeEllipseEx だけ
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LCtrlElli : TplGPResizeEllipseEx;
begin
// 生成済みの描画用コントロールを削除
FBackCtrl.DeleteAllCtrls;
LCtrlElli := TplGPResizeEllipseEx.Create(Self);
LCtrlElli.Parent := FBackCtrl;
LCtrlElli.InverseDisp := True;
LCtrlElli.PenColor := aclRed;
LCtrlElli := TplGPResizeEllipseEx.Create(Self);
LCtrlElli.Parent := FBackCtrl;
LCtrlElli.InverseDisp := True;
LCtrlElli := TplGPResizeEllipseEx.Create(Self);
LCtrlElli.Parent := FBackCtrl;
LCtrlElli.InverseDisp := True;
LCtrlElli.PenColor := aclGreen;
end;
//=============================================================================
// [保存してクリア] ボタン
// 描画用コントロールをファイルに保存
// このコードは単一の描画用クラス専用
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LFileStream : TFileStream;
LCtrl : TplBaseDragResize;
Lindex : Integer;
begin
LFileStream := TFileStream.Create(FFileName, fmCreate);
try
for Lindex := 0 to FBackCtrl.CtrlList.Count - 1 do begin
LCtrl := FBackCtrl.CtrlList[Lindex];
LFileStream.WriteComponent(LCtrl);
Application.ProcessMessages;
end;
finally
FreeAndNil(LFileStream);
end;
FBackCtrl.DeleteAllCtrls;
end;
//=============================================================================
// [読み込み] ボタン
// 保存時の描画図形を再現
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
LFileStream : TFileStream;
LCtrl : TplBaseDragResize;
begin
FBackCtrl.DeleteAllCtrls;
LFileStream := TFileStream.Create(FFileName, fmOpenRead);
LockWindowUpdate(FBackCtrl.Handle);
try
if LFileStream.Size <= 0 then Exit;
LFileStream.Position := 0;
while True do begin
if LFileStream.Position >= LFileStream.Size then Break;
LCtrl := TplGPResizeEllipseEx.Create(Self);
LCtrl.Parent := FBackCtrl;
LFileStream.ReadComponent(LCtrl);
Application.ProcessMessages;
end;
finally
FreeAndNil(LFileStream);
LockWindowUpdate(0);
end;
end;
end.
|
異なるクラスの描画用コトンロールを複数保存して読み出す例です.
保存の時はクラス名を意識する必要はありませんが,読み込む時はクラスで型キャストする必要があります.以下のサンプルでは,クラス名の文字列と Selected プロパティの値を保存した後に描画用クラスのコントロール本体を保存するようにする例です.読み出す時はクラス名を読み出して,そのクラス名で処理を分岐します.
これは,より汎用的な方法と言えます. |
 |
図4
[生成] をクリック
|

|
図5
[図保存してクリア] ボタンをクリック |

|
図6
[読み込む] ボタンをクリック
|
リスト2
汎用的と言える描画用コントロールの保存と読み出し |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL, Generics.Collections,
plGPResizeImage,
plGPResizeLine,
plGPResizeEllipseEx,
plContainerPanel,
plBaseDragResize;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private 宣言 }
FBackCtrl : TplContainerPanel;
FFileName : String;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
// 専用のコンテナコントロールを生成
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel1.Caption := '';
FBackCtrl := TplContainerPanel.Create(Self);
FBackCtrl.Parent := Self;
FBackCtrl.Align := alClient;
FFileName := '01_SavedCtrols.dat';
end;
//=============================================================================
// [生成] ボタン
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LCtrl : TplBaseDragResize;
begin
// 生成済みの描画用コントロールを削除
FBackCtrl.DeleteAllCtrls;
LCtrl := TplGPResizeImage.Create(Self);
LCtrl.Parent := FBackCtrl;
LCtrl.InverseDisp := True;
TplGPResizeImage(LCtrl).LoadFromFile('../../Images/503_Transe.bmp');
LCtrl := TplGPResizeLine.Create(Self);
LCtrl.Parent := FBackCtrl;
LCtrl.Left := 120;
LCtrl.InverseDisp := True;
TplGPResizeLine(LCtrl).PenWidth := 20.0;
TplGPResizeLine(LCtrl).PenColor := $FF00A0FF;
TplGPResizeLine(LCtrl).StartArrow := True;
LCtrl := TplGPResizeEllipseEx.Create(Self);
LCtrl.Parent := FBackCtrl;
LCtrl.Left := 240;
LCtrl.InverseDisp := True;
TplGPResizeEllipseEx(LCtrl).PenColor := aclGreen;
end;
//=============================================================================
// [保存してクリア] ボタン
// 描画用コントロールをファイルに保存
//
// クラス名,Selected プロパティの値,コントロールの順に格納
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LFileStream : TFileStream;
LpBuffer : array [0..49] of Char;
LCtrl : TplBaseDragResize;
Lindex : Integer;
begin
if FBackCtrl.CtrlList.Count = 0 then Exit;
LFileStream := TFileStream.Create(FFileName, fmCreate);
try
for Lindex := 0 to FBackCtrl.CtrlList.Count - 1 do begin
LCtrl := FBackCtrl.CtrlList[Lindex];
FillChar(LpBuffer, SizeOf(LpBuffer), #0);
StrPCopy(@LpBuffer[0], LCtrl.ClassName);
LFileStream.Write(@LpBuffer[0], SizeOf(LpBuffer));
LFileStream.WriteData(LCtrl.Selected);
LFileStream.WriteComponent(LCtrl);
Application.ProcessMessages;
end;
finally
FreeAndNil(LFileStream);
end;
FBackCtrl.DeleteAllCtrls;
end;
//=============================================================================
// [読み込み] ボタン
// 保存時の図描画状態を再現
//
// クラス名,Selected プロパティの値,コントロールの順に読み出す
// uses に Generics.Collections が必要
//=============================================================================
procedure TForm1.Button3Click(Sender: TObject);
var
LFileStream : TFileStream;
LCtrl : TplBaseDragResize;
LpBuffer : array [0..49] of Char;
LClassName : String;
LSelected : Boolean;
LSelList : TList<Boolean>;
LIndex : Integer;
begin
FBackCtrl.DeleteAllCtrls;
LFileStream := TFileStream.Create(FFileName, fmOpenRead);
LSelList := TList<Boolean>.Create;
LockWindowUpdate(FBackCtrl.Handle);
try
if LFileStream.Size <= 0 then Exit;
LFileStream.Position := 0;
while True do begin
if LFileStream.Position >= LFileStream.Size then Break;
FillChar(LpBuffer, SizeOf(LpBuffer), #0);
LFileStream.Read(LpBuffer[0], SizeOf(LpBuffer));
LClassName := Trim(LpBuffer);
LFileStream.ReadData(LSelected);
LSelList.Add(LSelected);
if LClassName = 'TplBaseDragResize' then begin
LCtrl := TplBaseDragResize.Create(Self);
end else
if LClassName = 'TplGPResizeImage' then begin
LCtrl := TplGPResizeImage.Create(Self);
end else
if LClassName = 'TplGPResizeLine' then begin
LCtrl := TplGPResizeLine.Create(Self);
end else
if LClassName = 'TplGPResizeEllipseEx' then begin
LCtrl := TplGPResizeEllipseEx.Create(Self);
end else begin
// 失敗
FBackCtrl.DeleteAllCtrls;
Exit;
end;
LCtrl.Parent := FBackCtrl;
LFileStream.ReadComponent(LCtrl);
Application.ProcessMessages;
end;
// 選択状態の再現
for LIndex := 0 to FBackCtrl.CtrlList.Count -1 do begin
FBackCtrl.CtrlList[LIndex].Selected := LSelList[LIndex];
end;
finally
FreeAndNil(LFileStream);
FreeAndNil(LSelList);
LockWindowUpdate(0);
end;
end;
end.
|
03_画像や図形の複製 ( 画像や図形のコピー ) |
描画用コントロールの複製,つまり,図形をコピーして貼り付ける例です.描画用コントロールをメモリストリームに格納して読み出します.複数の描画用コントロールを複製するには,前項のように順番にメモリストリームに格納していきます. |
 |
図7
[生成] をクリック
|

|
図8
[図形を複製] をクリック
|
リスト3
画像や図形の複製 ( 画像や図形のコピー |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, GDIPOBJ, GDIPAPI, GDIPUTIL,
plGPResizeImage,
plGPResizeLine,
plGPResizeEllipseEx,
plContainerPanel,
plBaseDragResize;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private 宣言 }
FBackCtrl : TplContainerPanel;
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
//=============================================================================
// フォーム生成時の処理
// 専用のコンテナコントロールを生成
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
Panel1.Caption := '';
FBackCtrl := TplContainerPanel.Create(Self);
FBackCtrl.Parent := Self;
FBackCtrl.Align := alClient;
end;
//=============================================================================
// [生成] ボタン
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LCtrlElli : TplGPResizeEllipseEx;
begin
// 生成済みの描画用コントロールを削除
FBackCtrl.DeleteAllCtrls;
LCtrlElli := TplGPResizeEllipseEx.Create(Self);
LCtrlElli.Parent := FBackCtrl;
LCtrlElli.InverseDisp := True;
end;
//=============================================================================
// [図形を複製] ボタン
// [コピーして貼り付け] の機能
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LMemStream : TMemoryStream;
LCtrl : TplBaseDragResize;
Lindex : Integer;
begin
// 選択中のコントロールがない場合と 2 以上の時は何もしない
if FBackCtrl.CtrlList.SelCount = 0 then Exit;
if FBackCtrl.CtrlList.SelCount > 1 then Exit;
Lindex := FBackCtrl.CtrlList.ItemIndex;
LCtrl := FBackCtrl.CtrlList[Lindex];
LMemStream := TMemoryStream.Create;
try
if LCtrl is TplGPResizeEllipseEx then begin
LMemStream.WriteComponent(TplGPResizeEllipseEx(LCtrl));
LCtrl:= TplGPResizeEllipseEx.Create(Self);
LCtrl.Parent := FBackCtrl;
LMemStream.Position := 0;
LMemStream.ReadComponent(LCtrl);
LCtrl.Left := 0;
LCtrl.Top := 0;
LCtrl.Selected := True;
end;
finally
FreeAndNil(LMemStream);
end;
end;
end.
|
|