|
画像・図形の移動リサイズ関係サンプル
R020_背景として使用するコンテナ用のコントロール |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE(UP1) Pro |
|
R020_ContainerControl.zip [606 KB] 2017年09月20日版 |
描画コントロール配置用の専用コンテナ用コントロール |
描画用のコントロールは複数使用することがあります.複数の描画コントロールを使用する場合,描画コントロールの選択や削除等の機能が必要になります.
そのような機能を追加したコントロールを作成しました.このコントロールは,描画コントロールを配置する背景,つまりコンテナとなるコントロールです.TCustomPanel の派生コントロールとなっています.コンポーネントとして登録するためのコードはありません.実行時に生成します.
下表は,これらのコントロールに実装したプロパティです.
背景画像は参考用に添付はしていますが,別に用意する必要があります.実際のアプリケーションではリソースから読み込む形式になると思われます.
|
プロパティ |
型 |
説明 |
CtrlList |
TList<T> |
描画コントロールを管理する配列
描画コントロールを生成すると自動的にこの配列に格納される
TList<TplBaseDragResize> として定義している |
ExitMouseEvent |
Boolean |
True にするとマウス関係イベント (マウス関係メソッド) は実行されなくなる.描画オブジェクトのマウスイベントも発生しなくなる
本コントロールの継承クラスで独自のマウス操作を実装できる |
BackImage |
Boolean |
描画オブジェクトの透過状態確認用の背景画像の表示
デフォルトは False で表示しない |
SelectMode |
Boolean |
複数の描画コントロールの選択は,デフォルトでは [Ctrl] キー押下の状態でラバーバンドを表示する
このプロパティの値を True にすると [Ctrl] キーを押下しなくてもラバーバンドの表示が可能.終了後は False にする必要がある
デフォルトは fasle |
ZoomValue |
Integer |
拡大表示の時の倍率の取得.読み出し専用
デフォルトは 100 で 100 % の原寸表示 |
リスト1
専用のコンテナコントロールに実装したメソッド類 |
function PtInResizeCtrl(X, Y: Integer; ACtrl: TplBaseDragResize): Boolean;
function GetPtInResizeCtrl(X, Y: Integer): TplBaseDragResize;
procedure SelectAllCtrls;
procedure DeSelectAllCtrls;
procedure DeleteCtrl(AIndex: Integer = -1);
procedure DeleteAllCtrls;
procedure BringToFrontCtrl(AIndex: Integer = -1);
procedure SendToBackCtrl(AIndex: Integer = -1);
procedure SetZOrderCtrl(ACtrl: TplBaseDragResize; NewIndex: Integer=-1); overload;
procedure SetZOrderCtrl(OldIndex: Integer; NewIndex: Integer=-1); overload;
procedure SetZoomValue(AZoomValue: Integer = 100);
function SelectedCtrlsRect: TRect;
function LocatedCtrlsRange: TPoint;
procedure AlignSelectedCtrls(AType: TAlign);
procedure CascadeSelectedCtrls(ADistance: Integer);
function GPBitmapFromSelectedCtrls: TGPBitmap;
procedure BitmapFromSelectedCtrls(ABitmap: TBitmap);
メソッド名 |
戻り値 |
説明 |
PtInResizeCtrl |
Boolean |
指定座標に指定の描画コントロールが存在する場合 True を返す |
GetPtInResizeCtrl |
plBaseDragResize |
指定座標の描画コントロールを取得
存在しない間場合は nil を返す |
SelectAllCtrls |
- |
全ての描画コントロールの選択状態にする |
DeSelectAllCtrls |
- |
全ての描画コントロールの選択状態を解除する |
DeleteCtrl |
- |
指定描画コントロールを削除
描画コントロールをインデックスで指定
引数省略時は選択中の全ての描画コントロールを削除 |
DeleteAllCtrls |
- |
描画中の全ての描画コントロールを削除 |
BringToFrontCtrl |
- |
指定描画コントロールを最前面に移動
描画コントロールはインデックスで指定する
引数省略時合は選択中の Z オーダの一番下が対象 |
SendToBackCtrl |
- |
指定描画コントロールを最背面に移動
描画コントロールはインデックスで指定
引数省略時は選択中の Z オーダの一番下が対象 |
SetZOrderCtrl |
- |
指定インデックスの描画コントロールの Z オーダ変更 |
SetZOrderCtrl |
- |
指定描画コントロールの Z オーダ変更
描画コントロールをインスタンスで指定 |
SetZoomValue |
- |
拡大表示の倍率を % 値で設定
設定可能な範囲は 20 ~ 1500 |
SelectedCtrlsRect |
TRect |
選択中の描画コントロールを含む TRect 値の取得 |
LocatedCtrlsRange |
TPoint |
選択中の描画コントロールを含む右端と下端の位置を取得
TScrollBox の縦と横の Range の値に相当する |
AlignSelectedCtrls |
- |
選択中の描画コントロールの整列
引数の TAign
型の値で整列状態を指定する
alCustomを指定すると左右中央揃え |
CascadeSelectedCtrls |
- |
選択中の描画コントロールのカスケード整列 |
GPBitmapFromSelectedCtrls |
TGPBitmap |
選択中の描画を合成して 1 つの TGPBitmap 画像を作成 |
BitmapFromSelectedCtrls |
- |
選択中の描画を合成して 1 つの TBitmap 画像を作成 |
描画コントロールは,CtrlList という配列に自動的に格納されます.この配列は TList<T> ですが,本コンテナコントロールでは,TListBox のような,以下のメンバを実装しています.
|
プロパティ |
型 |
説明 |
SelCount |
Integer |
選択中の描画コントロールの数.読み出し専用 |
ItemIndex |
Integer |
選択中の描画コントロールのインデックスまたは選択するインデックス |
PtInResizeCtrl,
GetPtInResizeCtrl
メソッドは ExitMouseEvent プロパティと組み合わせて使用すると特別な機能を実装できます.ExitMouseEvent プロパティの値を True にすると,本コントロール本来のマウスイベント (マウスメソッド) のコードを実行しなくなり,描画コントロールのマウスイベントも発生しなくなります.
本コントロールの継承クラスを作成し,独自のマウスイベントを実装すれば,コンテナコントロール上で画像の編集機能等が実装できます.
また,ラバーバンド等を描画すれば,本コンテナコントロール内限定の,矩形範囲の画面キャプチャ等の機能も実装できます.
ただし,注意が必要です.以下のように,ExitMouseEvent プロパティの値が False の時はマウスイベント (マウスメソッド) の処理を実行しないようにしておく必要があります.この処理をしておかないと,ExitMouseEvent の値が True の時のコードも実行されてしまいます.
|
リスト2
ExitMouseEvent プロパティを利用する際の注意
TMyBackCtrl は TplContainerPanel の継承クラス |
procedure TMyBackCtrl.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
Y: Integer);
var
LCtrl : TplBaseDragResize;
begin
inherited;
if not Self.ExitMouseEvent then exit;
LCtrl := GetPtInResizeCtrl(X, Y);
if LCtrl <> nil then begin
//
end;
01_TPanel を使用したコンテナ用コントロール |
透明または半透明の画像を表示した時,透過状態が確認てきるよう市松模様の画像を背景に描画することがあります. そこで,コンテナ用のコントロールにもこの機能を実装しました.その動作確認です. |
[備考]
ントロールのサイズが大きい場合,背景画像の描画でリソース不足が発生することがあります.
複数の画像等をコンテナコントロールに表示している場合は,透過状態は容易に確認できます.したがって,透過状態の確認用としての背景画像を表示するのは,画像等を単独で表示する際に必要な機能と思われます.
|
|
図1
背景画像を表示した状態 |
|
図2
背景色を変更
|
リスト3
透過状態を確認するための背景画像の表示テスト |
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, plContainerPanel, CheckLst;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
ColorDialog1: TColorDialog;
CheckBox1: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure CheckBox1Click(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;
FBackCtrl.BackImage := True;
end;
//=============================================================================
// フォーム破棄時の処理
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(FBackCtrl);
end;
//=============================================================================
// 背景色の変更
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
if ColorDialog1.Execute then begin
FBackCtrl.Color := ColorDialog1.Color;
CheckBox1.Checked := FBackCtrl.BackImage;
end;
end;
//=============================================================================
// 背景画像の表示・非表示の切り換え
//=============================================================================
procedure TForm1.CheckBox1Click(Sender: TObject);
begin
if not Assigned(FBackCtrl) then exit;
FBackCtrl.BackImage := CheckBox1.Checked;
end;
end.
02_TPanel を使用したコンテナ用コントロールのソースコード |
TPanel を使用した背景のコンテナ用コントロールのソースコードです. |
リスト4
TPanel を使用した背景のコンテナ用コントロールのソースコード
このユニットファイルをライブラリのパスが通った場所に置いて使用する |
unit plContainerPanel;
interface
uses
Windows, Messages,SysUtils, Classes, Graphics, Controls, StdCtrls, ExtCtrls,
Forms, plBaseDragResize, GDIPAPI, GDIPOBJ, GDIPUTIL, Generics.Collections;
type
TplContainerPanel = class;
TplCtrlList = class(TList<TplBaseDragResize>)
private
function GetFItemIndex: Integer;
procedure SetFItemIndex(const Value: Integer);
protected
procedure Notify(const Item: TplBaseDragResize; Action:
TCollectionNotification); override;
published
public
procedure Clear;
function SelCount: Integer;
property ItemIndex : Integer read GetFItemIndex write SetFItemIndex;
end;
TplContainerPanel = class(TCustomPanel)
private
FCtrlList : TplCtrlList;
FBackImagePath : string;
FBackBitmap : TBitmap;
FBackImage : Boolean;
FExitMouseEvent : Boolean;
FDragFlag : Boolean;
FDragStartY : Integer;
FDragStartX : Integer;
FRubberShape : TShape;
FSelectMode : Boolean;
FPtInAnyCtrlRect : Boolean;
FZoomOriginValue : Integer;
FZoomBeforeValue : Integer;
FZoomCurrensValue : Integer;
FZoomValue : Integer;
procedure SetBackImage(const Value: Boolean);
procedure SetFExitMouseEvent(const Value: Boolean);
protected
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure MoveResizeControlByKey(ALeft, ATop, AWidth, AHeight,
AdecX, AdecY, AdecW, AdecH: Integer);
procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X: Integer;
Y: Integer); override;
procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
procedure WMCreatedresizecontrol(var Message: TMessage);
message WM_CREATED_RESIZECONTROL;
procedure CMColorchanged(var Message: TMessage); message CM_COLORCHANGED;
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function PtInResizeCtrl(X, Y: Integer; ACtrl: TplBaseDragResize): Boolean;
function GetPtInResizeCtrl(X, Y: Integer): TplBaseDragResize;
procedure SelectAllCtrls;
procedure DeSelectAllCtrls;
procedure DeleteCtrl(AIndex: Integer = -1);
procedure DeleteAllCtrls;
procedure BringToFrontCtrl(AIndex: Integer = -1);
procedure SendToBackCtrl(AIndex: Integer = -1);
procedure SetZOrderCtrl(ACtrl: TplBaseDragResize; NewIndex: Integer=-1); overload;
procedure SetZOrderCtrl(OldIndex: Integer; NewIndex: Integer=-1); overload;
procedure SetZoomValue(AZoomValue: Integer = 100);
function SelectedCtrlsRect: TRect;
function LocatedCtrlsRange: TPoint;
procedure AlignSelectedCtrls(AType: TAlign);
procedure CascadeSelectedCtrls(ADistance: Integer);
function GPBitmapFromSelectedCtrls: TGPBitmap;
procedure BitmapFromSelectedCtrls(ABitmap: TBitmap);
property ExitMouseEvent : Boolean read FExitMouseEvent write SetFExitMouseEvent;
published
property Align;
property OnDblClick;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnResize;
property OnKeyDown;
property PopupMenu;
property Color;
property CtrlList : TplCtrlList read FCtrlList;
property BackImage : Boolean read FBackImage write SetBackImage;
property SelectMode : Boolean read FSelectMode write FSelectMode;
property ZoomValue : Integer read FZoomValue;
end;
implementation
uses
Math,
plGPResizeLine;
{TplContainerPanel}
type
TContainerCtrl = class(TCustomPanel);
TBaseResizeCtrl = class(TplBaseDragResize);
var
FSelfBackControl : TplContainerPanel;
//=============================================================================
// コンストラクタ
//=============================================================================
constructor TplContainerPanel.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
DoubleBuffered := True;
ParentBackground := False;
//[csOpaque]は必要に応じて...
ControlStyle := ControlStyle + [csOpaque];
FSelfBackControl := Self;
FZoomOriginValue := 100;
FZoomBeforeValue := FZoomOriginValue;
FZoomCurrensValue := FZoomOriginValue;
FZoomValue := 100;
FSelectMode := False;
FPtInAnyCtrlRect := False;
FCtrlList := TplCtrlList.Create;
BorderStyle := bsNone;
Color := clWhite;
FBackImage := False;
FBackBitmap := TBitmap.Create;
FBackImagePath := ExpandFileName('backTexture_01.bmp');
if FileExists(FBackImagePath) then begin
FBackBitmap.LoadFromFile(FBackImagePath);
end;
end;
//=============================================================================
// デコンストラクタ
//=============================================================================
destructor TplContainerPanel.destroy;
begin
FreeAndNil(FCtrlList);
FreeAndNil(FBackBitmap);
inherited;
end;
//-----------------------------------------------------------------------------
// 描画コントロールが生成されてParentの設定が終了した時のメッセージ
// 描画コントロールから送られてくるメッセージ
//
// 管理用の配列に追加
// 拡大表示中に描画コントロールを追加した場合,その描画コントロールも拡大
//
// [備考]
// コントロール生成を検出だけであればCM_CONTROLCHANGEメッセージが使用可能
// CM_CONTROLCHANGEは子コントロールの生成,削除の際に発生する
//-----------------------------------------------------------------------------
procedure TplContainerPanel.WMCreatedresizecontrol(
var Message: TMessage);
var
LCtrl : TplBaseDragResize;
begin
LCtrl := TplBaseDragResize(Message.WParam);
FCtrlList.Add(LCtrl);
SetZoomValue(-1);
end;
//=============================================================================
// Paintメソッド
// 背景用の画像を描画
//=============================================================================
procedure TplContainerPanel.Paint;
var
LBitmap : TBitmap;
begin
inherited;
if (Assigned(FBackBitmap)) and FBackImage then begin
LBitmap := TBitmap.Create;
try
//大きなサイズになるとリソース不足になる
LBitmap.SetSize(Width, Height);
LBitmap.Canvas.Brush.Bitmap := FBackBitmap;
LBitmap.Canvas.FillRect(LBitmap.Canvas.ClipRect);
Canvas.Draw(0, 0, LBitmap);
finally
FreeAndNil(LBitmap);
end;
end;
end;
//-----------------------------------------------------------------------------
// CM_COLORCHANGEDメッセージ処理
// 色を変更すると背景画像が非表示になるのでプロパティを変更しておく
//-----------------------------------------------------------------------------
procedure TplContainerPanel.CMColorchanged(var Message: TMessage);
begin
inherited;
if not Assigned(Parent) then exit;
FBackImage := False;
Invalidate;
end;
//-----------------------------------------------------------------------------
// BackImageプロパティの設定用メソッド
// 背景画像の表示・非表示の切り換え
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SetBackImage(const Value: Boolean);
begin
if Value <> FBackImage then begin
FBackImage := Value;
Invalidate;
end;
end;
//=============================================================================
// DoContextPopupメソッド
//
// カーソルが描画コントロールの矩形領域内にある時だけポップアップメニューを表示
// 複数のコントロールが選択状態になっていない時は無効
//
// [備考]
// 複数の描画コントロールが選択状態の時はマウスイベントが透過状態になっている
// したがって FindDragTarget関数ではコントロールの検出はできない
//=============================================================================
procedure TplContainerPanel.DoContextPopup(MousePos: TPoint;
var Handled: Boolean);
var
LPos : TPoint;
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
LSelCnt : Integer;
LFlag : Boolean;
begin
inherited;
if not Assigned(PopupMenu) then exit;
PopupMenu.AutoPopup := False;
LPos.X := MousePos.X;
LPos.Y := MousePos.Y;
LFlag := False;
LSelCnt := 0;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if LCtrl.Selected then Inc(LSelCnt);
if PtInResizeCtrl(LPos.X, LPos.Y, LCtrl) then begin
LFlag := True;
end;
end;
if LFlag and (LSelCnt >= 2) then begin
LPos := ClientToScreen(MousePos);
PopupMenu.Popup(LPos.X, LPos.Y);
end else begin
Handled := True;
end;
end;
//-----------------------------------------------------------------------------
// 指定したインデックスの描画コントロールを削除
// インデックスを指定しない場合は選択中の全てのコントロールを削除
//-----------------------------------------------------------------------------
procedure TplContainerPanel.DeleteCtrl(AIndex: Integer);
var
LCtrlNo : Integer;
LCtrl : TplBaseDragResize;
LDelFlag : Boolean;
begin
if FCtrlList.Count <= 0 then exit;
LDelFlag := False;
if AIndex >= 0 then begin
if AIndex < FCtrlList.Count then begin
FCtrlList.Delete(AIndex);
LDelFlag := True;
end;
end else begin
for LCtrlNo := FCtrlList.Count - 1 downto 0 do begin
LCtrl := FCtrlList[LCtrlNo];
if LCtrl.Selected then begin
FCtrlList.Delete(LCtrlNo);
LDelFlag := True;
end;
end;
end;
//Zオーダが最上位のコントロールを選択状態にする
AIndex := FCtrlList.Count - 1;
if (AIndex >= 0) and LDelFlag then begin
FCtrlList[AIndex].Selected := True;
end;
end;
//-----------------------------------------------------------------------------
// 表示中の全ての描画コントロールを削除
//-----------------------------------------------------------------------------
procedure TplContainerPanel.DeleteAllCtrls;
begin
FCtrlList.Clear;
end;
//-----------------------------------------------------------------------------
// 表示中の全ての描画コントロールを選択
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SelectAllCtrls;
var
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
begin
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
LCtrl.Selected := True;
LCtrl.Mousethrough := True;
end;
end;
//-----------------------------------------------------------------------------
// 全てのコントロールの選択を解除
//-----------------------------------------------------------------------------
procedure TplContainerPanel.DeSelectAllCtrls;
var
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
begin
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
LCtrl.Selected := False;
LCtrl.Mousethrough := False;
end;
end;
//-----------------------------------------------------------------------------
// 指定インデックスの描画コントロールを最前面に移動
// インデックスの指定がない場合は選択中の描画コントロールが対象
//
// Mousethroughは複数の描画コントロールが選択状態の検出に使用している
// MousethroughがTrueの描画コントロールが1つでもあると複数選択状態
//-----------------------------------------------------------------------------
procedure TplContainerPanel.BringToFrontCtrl(AIndex: Integer);
var
LCtrlNo : Integer;
LCtrl : TplBaseDragResize;
begin
if AIndex >= 0 then begin
if AIndex < FCtrlList.Count then begin
LCtrl := FCtrlList[AIndex];
LCtrl.BringToFront;
FCtrlList.Move(AIndex, FCtrlList.Count -1);
end;
end else begin
for LCtrlNo := FCtrlList.Count - 1 downto 0 do begin
LCtrl := FCtrlList[LCtrlNo];
if (LCtrl.Selected) and (not LCtrl.Mousethrough) then begin
LCtrl.BringToFront;
FCtrlList.Move(LCtrlNo, FCtrlList.Count -1);
break;
end;
end;
end;
end;
//-----------------------------------------------------------------------------
// 指定インデックスの描画コントロールを最背面に移動
// インデックスの指定がない場合は選択中の描画コントロールが対象
//
// Mousethroughは複数の描画コントロールが選択状態の検出に使用している
// MousethroughがTrueの描画コントロールが1つでもあると複数選択状態
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SendToBackCtrl(AIndex: Integer);
var
LCtrlNo : Integer;
LCtrl : TplBaseDragResize;
begin
if AIndex >= 0 then begin
if AIndex < FCtrlList.Count then begin
LCtrl := FCtrlList[AIndex];
LCtrl.SendToBack;
FCtrlList.Move(AIndex, 0);
end;
end else begin
for LCtrlNo := FCtrlList.Count - 1 downto 0 do begin
LCtrl := FCtrlList[LCtrlNo];
if (LCtrl.Selected) and (not LCtrl.Mousethrough) then begin
LCtrl.SendToBack;
FCtrlList.Move(LCtrlNo, 0);
break;
end;
end;
end;
end;
//-----------------------------------------------------------------------------
// 指定描画コントロールを指定Zオーダにする
// 第2引数の値がデフォルトの-1の時は最前面にする
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SetZOrderCtrl(ACtrl: TplBaseDragResize;
NewIndex: Integer);
var
LOldIndex : Integer;
LCtrlNo : Integer;
begin
if ACtrl = nil then exit;
if (NewIndex < -1) or (NewIndex >= FCtrlList.Count) then exit;
//引数のインデックスの描画コントロールのインスタンスを取得
LOldIndex := FCtrlList.IndexOf(ACtrl);
if NewIndex = -1 then NewIndex := FCtrlList.Count - 1;
if LOldIndex = NewIndex then exit;
FCtrlList.Move(LOldIndex, NewIndex);
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
FCtrlList[LCtrlNo].BringToFront;
end;
end;
//-----------------------------------------------------------------------------
// 指定インデックスの描画コントロールを指定Zオーダにする
// 第2引数の値がデフォルトの-1の時は最前面にする
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SetZOrderCtrl(OldIndex, NewIndex: Integer);
var
LCtrlNo : Integer;
begin
if (OldIndex < 0) or (OldIndex >= FCtrlList.Count) then exit;
if (NewIndex < -1) or (NewIndex >= FCtrlList.Count) then exit;
if NewIndex = -1 then NewIndex := FCtrlList.Count - 1;
if OldIndex = NewIndex then exit;
FCtrlList.Move(OldIndex, NewIndex);
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
FCtrlList[LCtrlNo].BringToFront;
end;
end;
//-----------------------------------------------------------------------------
// 選択中の描画コントロールの整列
// 左端揃え,上端揃え,右端揃え,下端揃え,左右中央揃え
// alCustomを指定すると左右中央揃え
//-----------------------------------------------------------------------------
procedure TplContainerPanel.AlignSelectedCtrls(AType: TAlign);
var
LSelRect : TRect;
LSelWidth : Integer;
LNo : Integer;
LCtrl : TplBaseDragResize;
LExtend : Integer;
begin
//選択中のコントロールのTRectの値を取得
LSelRect := SelectedCtrlsRect;
case AType of
alLeft:
begin
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if (LCtrl.Selected) and (LCtrl.Visible) then begin
if LCtrl is TplGPResizeLine then begin
LExtend := LCtrl.Left - TplGPResizeLine(LCtrl).ExtendLeft;
LCtrl.Left := LSelRect.Left + LExtend;
end else begin
LCtrl.Left := LSelRect.Left;
end;
end;
end;
end;
alTop:
begin
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if (LCtrl.Selected) and (LCtrl.Visible) then begin
if LCtrl is TplGPResizeLine then begin
LExtend := LCtrl.Top - TplGPResizeLine(LCtrl).ExtendTop;
LCtrl.Top := LSelRect.Left + LExtend;
end else begin
LCtrl.Top := LSelRect.Top;
end;
end;
end;
end;
alRight:
begin
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if (LCtrl.Selected) and (LCtrl.Visible) then begin
if LCtrl is TplGPResizeLine then begin
LExtend := LSelRect.Right - TplGPResizeLine(LCtrl).ExtendRight;
LCtrl.Left := LCtrl.Left + LExtend;
end else begin
LCtrl.Left := LSelRect.Right - LCtrl.Width;
end;
end;
Application.ProcessMessages;
Sleep(1);
end;
end;
alBottom:
begin
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if (LCtrl.Selected) and (LCtrl.Visible) then begin
if LCtrl is TplGPResizeLine then begin
LExtend := LSelRect.Bottom - TplGPResizeLine(LCtrl).ExtendBottom;
LCtrl.Top := LCtrl.Top + LExtend;
end else begin
LCtrl.Top := LSelRect.Bottom - LCtrl.Height;
end;
end;
end;
end;
alCustom:
begin
LSelWidth := LSelRect.Right - LSelRect.Left;
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if (LCtrl.Selected) and (LCtrl.Visible) then begin
if LCtrl is TplGPResizeLine then begin
LExtend := TplGPResizeLine(LCtrl).ExtendWidth;
LCtrl.Left := LSelRect.Left + (LSelWidth - LExtend) div 2;
end else begin
LCtrl.Left := LSelRect.Left + (LSelWidth - LCtrl.Width) div 2;
end;
end;
end;
end;
end;
end;
//-----------------------------------------------------------------------------
// 選択中の描画コントロールをカスケード整列するメソッド
// 直線描画コントロールの拡張領域は考慮していない
//-----------------------------------------------------------------------------
procedure TplContainerPanel.CascadeSelectedCtrls(ADistance: Integer);
var
LLeft : Integer;
LTop : Integer;
LNo : Integer;
LSelNo : Integer;
LCtrl : TplBaseDragResize;
begin
LLeft := 0;
LTop := 0;
LSelNo := 1;
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if (LCtrl.Selected) and (LCtrl.Visible) then begin
LCtrl.Left := LLeft + (LSelNo - 1) * ADistance;
LCtrl.Top := LTop + (LSelNo - 1) * ADistance;
inc(LSelNo);
end;
end;
end;
//-----------------------------------------------------------------------------
// 選択中の描画コントロールの描画を1つのTGPBitmapにする関数
// 表示サイズ(反転状態も含めて)の状態で取得する
//
// 呼び出し側ではTGPBimapを生成しなくてもよい
// 生成してもよいが,設定内容は破棄される
// 結果のTBitmapは呼出し側で解放,破棄する
//-----------------------------------------------------------------------------
function TplContainerPanel.GPBitmapFromSelectedCtrls:
TGPBitmap;
var
LCtrl : TplBaseDragResize;
LSelRect : TRect;
LNo : Integer;
LGPBitmap : TGPBitmap;
LSelWidth : Integer;
LselHeight : Integer;
LSelLeft : Integer;
LSelTop : Integer;
LCtrlLeft : Integer;
LCtrlTop : Integer;
begin
LSelRect := SelectedCtrlsRect;
LSelWidth := LSelRect.Right - LSelRect.Left;
LselHeight := LSelRect.Bottom - LSelRect.Top;
LSelLeft := LSelRect.Left;
LSelTop := LSelRect.Top;
LGPBitmap := TGPBitmap.Create(LSelWidth, LselHeight);
try
for LNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LNo];
if LCtrl.Visible then begin
if (LCtrl.Selected) or (LCtrl.DispOnly) then begin
if LCtrl is TplGPResizeLine then begin
LCtrlLeft := TplGPResizeLine(LCtrl).ExtendLeft;
LCtrlTop := TplGPResizeLine(LCtrl).ExtendTop;
end else begin
LCtrlLeft := LCtrl.Left;
LCtrlTop := LCtrl.Top;
end;
LCtrl.DrawRoutine(nil, LGPBitmap, LCtrlLeft - LSelLeft, LCtrlTop - LSelTop);
end;
end;
end;
Result := TGPBitmap(LGPBitmap.Clone);
finally
FreeAndNil(LGPBitmap);
end;
end;
//-----------------------------------------------------------------------------
// 選択中の描画コントロールの描画を1つのTBitmapにするメソッド
// 表示サイズ(反転状態も含めて)の状態で取得する
//
// 呼び出し側ではTBimapを生成しておくこと
// 解放,破棄も呼出し側で行う.使用方法がTGPBitmap取得の関数と違うので注意
//-----------------------------------------------------------------------------
procedure TplContainerPanel.BitmapFromSelectedCtrls(ABitmap: TBitmap);
var
LGPBitmap : TGPBitmap;
LImgGUID : TGUID;
LMemStream : TMemoryStream;
begin
LMemStream := TMemoryStream.Create;
LGPBitmap := GPBitmapFromSelectedCtrls;
try
if GetEncoderClsid('image/bmp', LImgGUID) >= 0 then begin
LGPBitmap.Save(TStreamAdapter.Create(LMemStream), LImgGUID);
LMemStream.Position := 0;
ABitmap.LoadFromStream(LMemStream);
end;
finally
FreeAndNil(LGPBitmap);
FreeAndNil(LMemStream);
end;
end;
//-----------------------------------------------------------------------------
// 拡大または縮小表示メソッド
// アンチエイリアスの処理なしで表示
// 引数の値が100の時は元の表示倍率
// 1000の時は10倍,50の時は1/2の縮小表示
//
// -1は新規に描画コントロールが追加された時に実行
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SetZoomValue(AZoomValue: Integer);
var
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
LStartNo : Integer;
LTempInt : Integer;
begin
if (AZoomValue > 1500) or ((AZoomValue < 20) and (AZoomValue <> -1)) then exit;
if AZoomValue = 100 then begin
if FZoomCurrensValue = FZoomOriginValue then exit;
SetBounds(Left, Top, Width * 100 div FZoomValue, Height * 100 div FZoomValue);
FZoomValue := 100;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
TContainerCtrl(LCtrl).ScaleBy(FZoomOriginValue, FZoomCurrensValue);
TBaseResizeCtrl(LCtrl).ZoomValue := FZoomValue;
LCtrl.Left := Trunc(LCtrl.Left * FZoomOriginValue / FZoomCurrensValue);
LCtrl.Top := Trunc(LCtrl.Top * FZoomOriginValue / FZoomCurrensValue);
end;
FZoomBeforeValue := FZoomOriginValue;
FZoomCurrensValue := FZoomOriginValue;
end else begin
if AZoomValue = -1 then begin
LStartNo := FCtrlList.Count - 1;
if FZoomOriginValue = FZoomCurrensValue then exit;
FZoomBeforeValue := FZoomOriginValue;
end else begin
LStartNo := 0;
LTempInt := FZoomCurrensValue div FZoomBeforeValue * FZoomOriginValue;
FZoomCurrensValue := LTempInt * AZoomValue div 100;
if FZoomCurrensValue = FZoomBeforeValue then exit;
end;
FZoomValue := Trunc(FZoomCurrensValue / FZoomOriginValue * 100);
if AZoomValue <> -1 then begin
SetBounds(Left, Top, Trunc(Width * FZoomCurrensValue / FZoomBeforeValue),
Trunc(Height * FZoomCurrensValue / FZoomBeforeValue));
end;
for LCtrlNo := LStartNo to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
TContainerCtrl(LCtrl).ScaleBy(FZoomCurrensValue, FZoomBeforeValue);
LCtrl.Left := Trunc(LCtrl.Left * FZoomCurrensValue / FZoomBeforeValue);
LCtrl.Top := Trunc(LCtrl.Top * FZoomCurrensValue / FZoomBeforeValue);
TBaseResizeCtrl(LCtrl).ZoomValue := FZoomValue;
if LCtrl.Selected then begin
LCtrl.Selected := False;
LCtrl.Selected := True;
end;
end;
FZoomBeforeValue := FZoomCurrensValue;
end;
end;
//=============================================================================
// WM_GETDLGCODEメッセージ処理
// KeyDownで特殊キーを検出するには,WM_GETDLGCODEメッセージの処理が必要
// このコントロールが親フォームでActiveControlになっている必要がある
//=============================================================================
procedure TplContainerPanel.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
inherited;
//DLGC_WANTARROWSを指定して,矢印キーを要求
Message.Result := DLGC_WANTARROWS;
end;
//=============================================================================
// KeyDownメソッド
// [Shift]キーが押下されていない場合は1ドットづつの移動
// [Shfit]キーが押下されていれば右端方向または下端方向へのリサイズ
//=============================================================================
procedure TplContainerPanel.KeyDown(var Key: Word; Shift: TShiftState);
var
LdecX : Integer;
LdecY : Integer;
LdecW : Integer;
LdecH : Integer;
LZoomValue : Integer;
LRect : TRect;
LLeft : Integer;
LTop : Integer;
LWidth : Integer;
LHeight : Integer;
begin
inherited;
if FCtrlList.Count <= 0 then exit;
//[ESC]で選択操作を強制終了
if Key = VK_ESCAPE then begin
FDragFlag := False;
if Assigned(FRubberShape) then FreeAndNil(FRubberShape);
ClipCursor(nil);
SetCaptureControl(nil);
Screen.Cursor := crDefault;
exit;
end;
if (Key < VK_LEFT) or (Key > VK_DOWN) then exit;
LZoomValue := FZoomCurrensValue div 100;
if LZoomValue < 0 then LZoomValue := 1;
LdecX := 0;
LdecY := 0;
LdecW := 0;
LdecH := 0;
Screen.Cursor := crDefault;
//[Shift\キーが押されている場合はリサイズ
if (ssShift in Shift) then begin
if Key = VK_LEFT then LdecW := -LZoomValue;
if Key = VK_RIGHT then LdecW := LZoomValue;
if Key = VK_UP then LdecH := -LZoomValue;
if Key = VK_DOWN then LdecH := LZoomValue;
end else begin
if Key = VK_LEFT then LdecX := -LZoomValue;
if Key = VK_RIGHT then LdecX := LZoomValue;
if Key = VK_UP then LdecY := -LZoomValue;
if Key = VK_DOWN then LdecY := LZoomValue;
end;
LRect := SelectedCtrlsRect;
LLeft := LRect.Left;
LTop := LRect.Top;
LWidth := Abs(LRect.Right - LRect.Left);
LHeight := Abs(LRect.Bottom - LRect.Top);
MoveResizeControlByKey(LLeft, LTop, LWidth, LHeight, LdecX, LdecY, LdecW, LdecH);
end;
//-----------------------------------------------------------------------------
// キー操作による移動リサイズ用のメソッド
//
// 引数の値によって描画用コントロールの位置とサイズを設定
// リサイズはドット単位(比率ではない)
//-----------------------------------------------------------------------------
procedure TplContainerPanel.MoveResizeControlByKey(ALeft, ATop,
AWidth, AHeight, AdecX, AdecY, AdecW, AdecH: Integer);
var
LCtrlNo : Integer;
LCtrl : TplBaseDragResize;
LADecX : Integer;
LADecY : Integer;
LADecW : Integer;
LADecH : Integer;
LLeft : Integer;
LTop : Integer;
LWidth : Integer;
LHeight : Integer;
LZoomValue : Integer;
LLimit : Integer;
begin
LZoomValue := FZoomCurrensValue div 100;
if LZoomValue < 0 then LZoomValue := 1;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
LADecX := AdecX;
LADecY := AdecY;
LADecW := AdecW;
LADecH := AdecH;
if LCtrl.DispOnly then begin
LAdecX := 0;
LAdecY := 0;
LAdecW := 0;
LAdecH := 0;
end else
if LCtrl.MoveOnly then begin
LAdecW := 0;
LAdecH := 0;
end else
if LCtrl.GrabHorzOnly then begin
LAdecY := 0;
LAdecH := 0;
end else
if LCtrl.GrabVertOnly then begin
LAdecX := 0;
LAdecW := 0;
end;
if LCtrl.Selected then begin
if LAdecX < 0 then begin
if (ALeft + AWidth - 10) < 0 then LAdecX := 0;
end;
if LAdecX > 0 then begin
if ((ALeft + 30) > (Width)) then ScrollBy(-Abs(LAdecX), 0);
end;
LLeft := LCtrl.Left + LAdecX;
if LAdecY < 0 then begin
if (ATop + AHeight - 10) < 0 then LAdecY := 0;
end;
if LAdecY > 0 then begin
if ((ATop + 30) > (Height)) then ScrollBy(0, -Abs(LAdecY));
end;
LTop := LCtrl.Top + LAdecY;
LWidth := LCtrl.Width + LAdecW;
LHeight := LCtrl.Height + LAdecH;
//一定の値より小さい値にはできないようにする
LLimit := 1;
if LWidth <= (LLimit * LZoomValue) then LWidth := (LLimit * LZoomValue);
if LHeight <= (LLimit * LZoomValue) then LHeight := (LLimit * LZoomValue);
LCtrl.SetBounds(LLeft, LTop, LWidth, LHeight);
end;
end;
end;
//-----------------------------------------------------------------------------
// 選択中の描画コントロールの選択領域の位置とサイズを計算
//-----------------------------------------------------------------------------
function TplContainerPanel.SelectedCtrlsRect: TRect;
var
LCtrlNo : Integer;
LCtrl : TplBaseDragResize;
LLeft : Integer;
LTop : Integer;
LRight : Integer;
LBottom : Integer;
LExendRect : TRect;
begin
LLeft := MaxInt;
LTop := MaxInt;
LRight := 0;
LBottom := 0;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if (LCtrl.Selected) then begin
if LCtrl is TplGPResizeLine then begin
LExendRect := TplGPResizeLine(LCtrl).ExtendRect;
//直線描画クラスは別扱い(描画領域が拡張されている)
LLeft := Min(LLeft, LExendRect.Left);
LTop := Min(LTop, LExendRect.Top);
LRight := Max(LRight, LExendRect.Right);
LBottom := Max(LBottom, LExendRect.Bottom);
end else begin
LLeft := Min(LLeft, LCtrl.Left);
LTop := Min(LTop, LCtrl.Top);
LRight := Max(LRight, LCtrl.Left + LCtrl.Width);
LBottom := Max(LBottom, LCtrl.Top + LCtrl.Height);
end;
end;
end;
Result := Rect(LLeft, LTop, LRight, LBottom);
end;
//-----------------------------------------------------------------------------
// 配置している描画コントロールを1つにした時の幅と高さを取得する
// スクロールのRangeの値に相当する値
//-----------------------------------------------------------------------------
function TplContainerPanel.LocatedCtrlsRange: TPoint;
var
LCtrlNo : Integer;
LCtrl : TplBaseDragResize;
LRight : Integer;
LBottom : Integer;
LExendRect : TRect;
begin
LRight := 0;
LBottom := 0;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if LCtrl is TplGPResizeLine then begin
//直線描画クラスは別扱い(描画領域が拡張されている)
LExendRect := TplGPResizeLine(LCtrl).ExtendRect;
LRight := Max(LRight, LExendRect.Right);
LBottom := Max(LBottom, LExendRect.Bottom);
end else begin
LRight := Max(LRight, LCtrl.Left + LCtrl.Width);
LBottom := Max(LBottom, LCtrl.Top + LCtrl.Height);
end;
end;
Result := Point(LRight, LBottom);
end;
//-----------------------------------------------------------------------------
// マウスカーソル下に指定描画コントロールが存在するかを調べる関数
//-----------------------------------------------------------------------------
function TplContainerPanel.PtInResizeCtrl(X, Y: Integer;
ACtrl: TplBaseDragResize): Boolean;
begin
Result := (X >= ACtrl.Left) and (X <= (ACtrl.Left + ACtrl.Width));
Result := Result and (Y >= ACtrl.Top) and (Y <= (ACtrl.Top + ACtrl.Height));;
end;
//-----------------------------------------------------------------------------
// マウスカーソル下の描画コントロールを取得する関数
//-----------------------------------------------------------------------------
function TplContainerPanel.GetPtInResizeCtrl(X, Y: Integer): TplBaseDragResize;
var
LNo : Integer;
LCtrl : TplBaseDragResize;
begin
Result := nil;
if FCtrlList.Count = 0 then exit;
for LNo := FCtrlList.Count -1 downto 0 do begin
LCtrl := FCtrlList[LNo];
if PtInResizeCtrl(x, Y, LCtrl) then begin
Result := LCtrl;
break;
end;
end;
end;
//-----------------------------------------------------------------------------
// ExitMouseEventプロパティの設定用メソッド
// Trueにするこのコントロール本来のマウスイベントは機能しなくなる
// 描画コントロールのマウスイベントも発生しなくなる
// 本コントロール継承クラスで独自のマウス操作コードを実装するのに利用可能
//-----------------------------------------------------------------------------
procedure TplContainerPanel.SetFExitMouseEvent(const Value: Boolean);
var
LNo : Integer;
begin
if FExitMouseEvent <> Value then begin
FExitMouseEvent := Value;
if FExitMouseEvent then begin
for LNo := 0 to FCtrlList.Count - 1 do begin
FCtrlList[LNo].Mousethrough := True;
TBaseResizeCtrl(FCtrlList[LNo]).ExitMouseEvent := True;
end;
end else begin
for LNo := 0 to FCtrlList.Count - 1 do begin
FCtrlList[LNo].Mousethrough := False;
TBaseResizeCtrl(FCtrlList[LNo]).ExitMouseEvent := False;
end;
end;
end;
end;
//=============================================================================
// MouseDownメソッド
//
// 以下のいずれかの操作
// (1) 複数のコントロールの選択
// [Ctrl]キーを押下した状態でマウスでラバーはバンドを描いて選択
// (2) 選択中の複数の描画コントロールの移動
// (3) 選択の解除
// 描画コントロール以外のところでマウスの左ボタン押下
//
// SelectModeプロパティをTrueにするとFalseにするまで複数選択モードとなる
// [Ctrl]+[マウス左ボタン]押下で複数の描画コントロールを選択できる
// この機能は描画用の移動リサイズの基本クラスに実装している
//=============================================================================
procedure TplContainerPanel.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
LMultiSelect : Boolean;
LClipRect : TRect;
LForm : TCustomForm;
begin
inherited;
//キーによる操作を可能にする
//親フォーム検出のこの方法は簡便法
LForm := GetParentForm(Self);
if LForm <> nil then begin
LForm.ActiveControl := Self;
end;
if FExitMouseEvent then exit;
if Button <> mbLeft then exit;
LMultiSelect := False;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
//1つでもマウスイベントが透過状態であれば複数の選択状態とみなす
if LCtrl.Mousethrough = True then begin
LMultiSelect := True;
Break;
end;
end;
FPtInAnyCtrlRect := False;
if LMultiSelect then begin
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if PtInResizeCtrl(X, Y, LCtrl) then begin
if LCtrl.Selected then begin
FPtInAnyCtrlRect := True;
end else begin
FPtInAnyCtrlRect := True;
DeSelectAllCtrls;
LCtrl.Selected := True;
LCtrl.Mousethrough := False;
end;
Break;
end;
end;
end;
if not FPtInAnyCtrlRect then begin
if (ssCtrl in Shift) or FSelectMode then begin
GetWindowRect(Handle, LClipRect);
ClipCursor(@LClipRect);
FDragFlag := True;
FDragStartX := X;
FDragStartY := Y;
end else begin
DeSelectAllCtrls;
end;
end else begin
//移動開始
GetWindowRect(Handle, LClipRect);
ClipCursor(@LClipRect);
Screen.Cursor := crSizeAll;
FDragFlag := True;
FDragStartX := X;
FDragStartY := Y;
end;
end;
//=============================================================================
// MouseMoveメソッド
//=============================================================================
procedure TplContainerPanel.MouseMove(Shift: TShiftState; X, Y: Integer);
var
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
LIncX : Integer;
LIncY : Integer;
LLeft : Integer;
LTop : Integer;
LWidth : Integer;
LHeight : Integer;
LSumRect : TRect;
begin
inherited;
if FExitMouseEvent then exit;
if not FDragFlag then exit;
//ラバーバンドの描画
if not FPtInAnyCtrlRect then begin
if (X <> FDragStartX) or (Y <> FDragStartY) then begin
if not Assigned(FRubberShape) then begin
FRubberShape := TShape.Create(Self);
FRubberShape.Parent := Self;
FRubberShape.Brush.Style := bsClear;
FRubberShape.Pen.Width := 2;
FRubberShape.Pen.Style := psDot;
end;
LLeft := FDragStartX;
LTop := FDragStartY;
LWidth := X - FDragStartX;
LHeight := Y - FDragStartY;
if LWidth < 0 then begin
LLeft := FDragStartX - Abs(LWidth);
end;
if LHeight < 0 then begin
LTop := FDragStartY - Abs(LHeight);
end;
FRubberShape.SetBounds(LLeft, LTop, Abs(LWidth), Abs(LHeight));
end;
end else begin
//複数のコントロールの移動処理
LIncX := X - FDragStartX;
LIncY := Y - FDragStartY;
LSumRect := SelectedCtrlsRect;
//選択中のコントロールを移動する
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if LCtrl.Selected then begin
LLeft := LCtrl.Left + LIncX;
LTop := LCtrl.Top + LIncY;
LCtrl.SetBounds(LLeft, LTop, LCtrl.Width, LCtrl.Height);
end;
end;
FDragStartX := X;
FDragStartY := Y;
end;
end;
//=============================================================================
// MouseUpメソッド
//=============================================================================
procedure TplContainerPanel.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
LLeft : Integer;
LTop : Integer;
LWidth : Integer;
LHeight : Integer;
LSelectRect : TRect;
LRect : TRect;
LOutRect : TRect;
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
LSetCnt : Integer;
LZoomValue : Integer;
LForm : TCustomForm;
begin
inherited;
//親フォーム検出のこの方法は簡便法
LForm := GetParentForm(Self);
if LForm <> nil then begin
LForm.ActiveControl := Self;
end;
if FExitMouseEvent then exit;
if not FDragFlag then exit;
LZoomValue := FZoomCurrensValue div FZoomOriginValue;
if LZoomValue < 0 then LZoomValue := 1;
FDragFlag := False;
//ラバーバンド操作中
//FPtInAnyCtrlRect(MouseDown時のマウスの位置が描画コントロール内)
if not FPtInAnyCtrlRect then begin
if Assigned(FRubberShape) then begin
//ラバーバンド(TShape)の描画終了
LLeft := FRubberShape.Left;
LTop := FRubberShape.Top;
LWidth := FRubberShape.Width;
LHeight := FRubberShape.Height;
LSelectRect := Rect(LLeft, LTop, LLeft + LWidth, LTop + LHeight);
//コントロールの矩形領域の一部がTShapeの矩形内にあれば選択する
LSetCnt := 0;
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
LRect := Rect(LCtrl.Left,
LCtrl.Top,
LCtrl.Left + LCtrl.Width,
LCtrl.Top + LCtrl.Height);
if IntersectRect(LOutRect, LSelectRect, LRect) then begin
inc(LSetCnt);
LCtrl.Selected := True;
end else begin
LCtrl.Selected := False;
LCtrl.Mousethrough := False;
end;
end;
//選択した描画コントロールが2以上の時はそれらのマウス透過をTrueにする
//マウス透過すとこの背景コントロールかマウスイベントを受け取る
if LSetCnt >= 2 then begin
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if LCtrl.Selected then begin
LCtrl.Mousethrough := True;
end;
end;
end;
end;
if Assigned(FRubberShape) then FreeAndNil(FRubberShape);
ClipCursor(nil);
SetCaptureControl(nil);
Screen.Cursor := crDefault;
end else begin
//複数のコントロールの移動終了
for LCtrlNo := 0 to FCtrlList.Count - 1 do begin
LCtrl := FCtrlList[LCtrlNo];
if LCtrl.Selected then begin
LLeft := LCtrl.Left div LZoomValue * LZoomValue;
LTop := LCtrl.Top div LZoomValue * LZoomValue;
LCtrl.SetBounds(LLeft, LTop, LCtrl.Width, LCtrl.Height);
end;
end;
ClipCursor(nil);
SetCaptureControl(nil);
Screen.Cursor := crDefault;
end;
end;
{ TplCtrlList }
//=============================================================================
// Clearメソッド
// overrideではなく独自実装
//=============================================================================
procedure TplCtrlList.Clear;
begin
FSelfBackControl.SetZoomValue();
Count := 0;
Capacity := 0;
end;
//=============================================================================
// TListのItemの追加や削除の時に発生する通知メッセージ処理
//=============================================================================
procedure TplCtrlList.Notify(const Item: TplBaseDragResize;
Action: TCollectionNotification);
var
LCtrl : TplBaseDragResize;
LCtrlNo : Integer;
LFlag : Boolean;
begin
inherited;
LFlag := True;
if Action = cnAdded then begin
//外部でAddしてしまった場合の処置
for LCtrlNo := Count - 2 downto 0 do begin
LCtrl := Items[LCtrlNo];
if LCtrl = Item then begin
Extract(Item);
LFlag := False;
Break;
end;
end;
//追加した描画コントロールを選択状態にする
if LFlag then begin
for LCtrlNo := 0 to Count - 2 do begin
LCtrl := Items[LCtrlNo];
LCtrl.Selected := False;
end;
Item.Selected := True;
end;
end else
if Action = cnRemoved then begin
if Item <> nil then begin
LCtrl := Item;
FreeAndNil(LCtrl);
end;
end;
end;
//-----------------------------------------------------------------------------
// 選択中の描画コントロールの数を返す関数
//-----------------------------------------------------------------------------
function TplCtrlList.SelCount: Integer;
var
LCtrlNo : Integer;
LSelCnt : Integer;
begin
LSelCnt := 0;
for LCtrlNo := 0 to Count - 1 do begin
if Items[LCtrlNo].Selected then Inc(LSelCnt);
end;
Result := LSelCnt;
end;
//-----------------------------------------------------------------------------
// ItemIndexプロパティの設定用メソッド
// 選択する描画コントロールを指定する
// このプロパティで設定すると他の全ての選択は解除される
//-----------------------------------------------------------------------------
procedure TplCtrlList.SetFItemIndex(const Value: Integer);
var
LCtrlNo : Integer;
begin
if (Value >= 0) and (Value < Count) then begin
for LCtrlNo := 0 to Count - 1 do begin
if Value = LCtrlNo then begin
Items[LCtrlNo].Selected:= True;
end else begin
Items[LCtrlNo].Selected:= False;
end;
end;
end;
end;
//-----------------------------------------------------------------------------
// ItemIndexプロパティの取得用メソッド
// 選択されていない時は-1を返す
// 複数選択時はZオーダの一番低い描画コントロールのインデックスを返す
//-----------------------------------------------------------------------------
function TplCtrlList.GetFItemIndex: Integer;
var
LCtrlNo : Integer;
begin
Result := -1;
for LCtrlNo := 0 to Count - 1 do begin
if Items[LCtrlNo].Selected then begin
Result := LCtrlNo;
Break;
end;
end;
end;
end.
|