自作コンポーネントの parent プロパティ

解決


snail  2013-04-20 07:54:31  No: 44365

Win7 + XE2 の環境で Tedit + TSpeedButton を組み合わせた
コンポーネントを作っています。
どうしてもわからないのでどなたか教えてください。

現在の問題点、
作成したコンポーネントを設計時、マウスドラッグでPanelの上に
配置しても parent プロパティを正しく設定することができません。

配置時の Owner を確認すると Panel と Form どちらにドラッグし
ても Owner は Form になっています。
どうしたら Panel にドラッグしたことを感知することができますか。


Mr.XRAY  URL  2013-04-20 09:49:34  No: 44366

>どうしたら Panel にドラッグしたことを感知することができますか。

設計時にですよね.
これは,かなり難しいと思います.
個人的には,素直に,切り取り,貼り付けがいいと思いますが.
ヒントだけを.

設計時にマウスイベントを受け取るには,DesignWndProc か CM_DESIGNHITTEST を実装します.
(Delphi XE2 なら使用可能です)
もちろん,コンポーネントにです.

以下のようなコンポーネントを作成して,フォームに配置すると,
すぐに赤い色になります.なぜなら,通常はマウスクリックでコンポを配置しますから,
当然マウスイベントが発生します (これは設計時の動作ですから,実行時は元に戻ります)

コンポーネントエディタ側でコーディングするのか,Parent プロパティのオーバライド
が必要なのか.やったことがないので,確実なことが言えません.申し訳ないです.

unit plMyPanel;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TplMyPanel = class(TCustomPanel)
  private
    { Private 宣言 }
  protected
    { Protected 宣言 }
    procedure CMDesignHitTest(var Message: TCMDesignHitTest);
      message CM_DESIGNHITTEST;
  public
    { Public 宣言 }

  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('plXRAY', [TplMyPanel]);
end;

{ TplMyPanel }

procedure TplMyPanel.CMDesignHitTest(var Message: TCMDesignHitTest);
begin
  inherited;

  Self.ParentBackground := False;
  Self.Color := clRed;
end;

end.


KHE00221  2013-04-20 18:26:42  No: 44367

>作成したコンポーネントを設計時、マウスドラッグでPanelの上に
>配置しても parent プロパティを正しく設定することができません。

そもそも設計時に貼り付けるコンポーネントの parent は
自分で設定しないだろ?


KHE00221  2013-04-20 18:30:56  No: 44368

フォーム上に配置してあるコンポーネントを
パネルの移動した場合にparentをフォームからパネルに
変更したいと言ってる?


KHE00221  2013-04-20 18:39:39  No: 44369

>Win7 + XE2 の環境で Tedit + TSpeedButton を組み合わせた

Tedit か TSpeedButton どっちかが親で
もう片方を作るときのParentの設定が出来ないといってるのか・・・

Createした時点でParent はわからないからね

親Parent を設定された時に 個Parentを設定すればいい

XE2 なら 

TLabeledEdit を見ればわかるだろ


snail  2013-04-21 00:24:46  No: 44370

> Mr.XRAY

CMDesignHitTest が何かよくわかりませんが書き込んでいただいた
内容で修正して実行してみました。
ドロップした時点ではこのメッセージは呼び出されないようです。
貼り付けた後にマウスカーソルをコンポーネントの上を通過時に
色が変わりました。
貼り付けた後にマウスカーソルをコンポーネント通過させる
という作業をすれば設定できそうですね。


snail  2013-04-21 00:42:21  No: 44371

>KHE00221 さんこんにちは
>そもそも設計時に貼り付けるコンポーネントの parent は
>自分で設定しないだろ?

通常のコンポーネントならおっしゃるとおりですだと思います。
今回のコンポは Tedit + TSpeedButton + ListView の合体で
TEdit 右のSppdButton をクリックすると ListView を表示させています。

>フォーム上に配置してあるコンポーネントを
>パネルの移動した場合にparentをフォームからパネルに
>変更したいと言ってる?

>Createした時点でParent はわからないからね
そうなんですね。それでこまっています。Left Top は RequestAlign
メソッドで取り出せたんですが、

>親Parent を設定された時に 個Parentを設定すればいい
親の SetParent で子供の Parent を設定するようにコーディング
してみましたが
そもそも親の Parent が未設定の状態で Create メソッドを
抜けると Parent が Null と怒られ、適当に Form なんかセット
しておくと Create を抜けた後も SetParent は呼ばれない
みたいで困ってしまいました。
次はCreate時点のマウス位置から下のコンポーネントを判断して
みたいと考えている最中です。

>TLabeledEdit を見ればわかるだろ
最初にソースを見てみましたが私の能力を超えていました。


Mr.XRAY  URL  2013-04-21 04:51:08  No: 44372

>次はCreate時点のマウス位置から下のコンポーネントを判断して
>みたいと考えている最中です。

設計時のマウスイベントは,IDE が管理しています.
したがって,マウスのイベント,メッセージはとらえることはできません.
設計時にこれらの機能を使用するには,先に述べた CM_DESIGNHITTEST で
Result に 0 以外の値を返します.
ただし,そうすると,全てのマウス関係のメッセージを自前で処理しなければなりません.
自分自身が使うコンポーネントであれば,切り取り,貼り付けでいいのではないと思うのですが,
どうなんでしょう ?
実行時に Parent を変更するのであれば,比較的簡単ですけどね.

unit plMyPanel;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TplMyPanel = class(TPanel)
  private
    { Private 宣言 }
  protected
    { Protected 宣言 }
    procedure CMDesignHitTest(var Message: TCMDesignHitTest);
      message CM_DESIGNHITTEST;
  public
    { Public 宣言 }

  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('plXRAY', [TplMyPanel]);
end;

{ TplMyPanel }

//-----------------------------------------------------------------------------------
//  Resultに0以外の値を返すと,設計時にマウスメッセージの処理が可能
//  ただし,IDE のメッセージは処理できなくなる
//  つまり,設計時にマウスでのコントロールの移動もサイズ変更もできなくなる
//-----------------------------------------------------------------------------------
procedure TplMyPanel.CMDesignHitTest(var Message: TCMDesignHitTest);
begin
  inherited;
  Message.Result := 1;
end;

end.


Mr.XRAY  URL  2013-04-21 05:01:08  No: 44373

>Result に 0 以外の値を返します.
>ただし,そうすると,全てのマウス関係のメッセージを自前で処理しなければなりません.

例外があります.以下の記事で確認してください.
[Vcl.Controls.TCMDesignHitTest]
http://docwiki.embarcadero.com/Libraries/XE3/ja/Vcl.Controls.TCMDesignHitTest

MK_LBUTTON マウスの左ボタンが押された。 

等であれば,以下のように,CMDesignHitTest メッセージ内で処理可能です.
  
procedure TplMyPanel.CMDesignHitTest(var Message: TCMDesignHitTest);
begin 
  inherited;
  if Parent = nil then exit;

  if Message.Keys = MK_LBUTTON then begin
    Self.ParentBackground := False;
    Self.Color := clRed;
  end;
end;


Mr.XRAY  URL  2013-04-21 05:32:39  No: 44374

>ただし,そうすると,全てのマウス関係のメッセージを自前で処理しなければなりません.

スミマセン.情報が断片的で申し訳ないのですが.
このメッセージの処理は,WM_LBUTTONDOWN とかでなく,コンポーネント内部で
使用する MouseUp とか MouseDown メソッドを override して使います.例えば,以下のように

procedure TplMyPanel.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  AForm    : TForm;
begin
  inherited;

  if csDesigning in ComponentState then begin
    AForm := TForm(GetParentForm(Self, False));

    Self.ParentBackground := False;
    Self.Color := clRed;
    Self.Caption := AForm.Name;
   end;
end;


snail  2013-04-21 11:21:07  No: 44375

結局
http://stackoverflow.com/questions/6403217/how-to-set-a-tcustomcontrols-parent-in-create?answertab=active#tab-top

の書き込みを参考にして AfterConstruction イベントを捕まえて
無理矢理 parent をセットしました。

簡単なテストでは問題はでていませんが、又何かでてきるかもしれません。
みなさんありがとうございました。

↓はコンポーネントから関係する部分だけを抜き出したものです。

//------------------------------------------
//         TKELV  AfterConstruction イベント
// ここで Parent プロパティをセット
//------------------------------------------
procedure TKELV.AfterConstruction;
var
  WrkTPoint : TPoint;       // マウス座標の下にあるコンポーネント取り出し
  WrkTControl : TControl;
  WrkTWincontrol : TWincontrol;
begin
  inherited;
{
  if Assigned( FDebugMemo ) = True then
    FDebugMemo.Lines.Add(  IntToStr( FDebugMemo.Lines.Count ) + 'AfterConstruction' );
  Self.ParentBackground := False;
  Self.Color := clBlue;
  }
//----------------//
  if ( csDesigning in Self.ComponentState ) = True then  // 設計時はname プロパティの値はこのメソッドの後でセットされる。
  begin
    GetCursorPos( WrkTPoint );       // マウス座標の下にあるコンポーネント取り出し
    WrkTControl := FindDragTarget( WrkTPoint, True );
    if Assigned( WrkTControl ) = False then   exit;
    if ( WrkTControl is TWinControl ) = False then exit;

    WrkTWincontrol := TWincontrol( WrkTControl );

    if WrkTWincontrol <> Self.Parent then
      Self.Parent := WrkTWincontrol;
  end;
  if Assigned( FDebugMemo ) = True then
    FDebugMemo.Lines.Add(  IntToStr( FDebugMemo.Lines.Count ) + 'AfterConstruction PA=' + Self.Parent.Name );
end;


Mr.XRAY  URL  2013-04-21 11:47:17  No: 44376

ありゃ.

>の書き込みを参考にして AfterConstruction イベントを捕まえて
>無理矢理 parent をセットしました。

これって,設計時に,コンポーネントを貼り付ける時に,Parent を設定,
ということですか ?

勘違いしていました.
「設計時に,コンポーネントをドラッグして,Parentを設定できるコンポ」
という仕様だと勝手に解釈してしまいました.
何か意味のないレスになってしまい.スミマセンでした.


KHE00221  2013-04-21 17:41:37  No: 44377

>今回のコンポは Tedit + TSpeedButton + ListView の合体で
普通こーゆうの作るときは  親を Panel にして
その上に TEdit TSpeedButton TListview 乗せるんだけどね・・・


Mr.XRAY  URL  2013-04-21 19:24:39  No: 44378

いろいろ書いてしまい,掲示板をご覧の方々を混乱させてしまいました.
今回の snail さんの場合は特別な場合だと思いますが,普通は,以下のようにして
コントロール (コンポーネント) の親,つまり,Parent を変更できます.

[設計時に,コンポーネントの親 ( Parent) を変更する]
http://ht-deko.minim.ne.jp/delphiforum/?vasthtmlaction=viewtopic&t=1071.0


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加