重なったコントロールのうち、下のコントロールのクリックを取得するには?

解決


デル太  2006-03-24 02:02:24  No: 20662

2つのPaintBoxを配置して、それらが重なっているところをクリックすると、
上にあるPaintBoxでクリックが起こり、下のPaintBoxでは起きないみたいです。
下のPaintBoxでもクリックを処理することができるでしょうか?
または、重なっているすべてのPaintBoxにクリックが起きるという形でもよいのですが・・。

FAQのようにも感じるのですが、Googleなどで適当な表現で検索できなかったようで、見つけられませんでした。
また、お力添えいただけると幸いです。

今回は、次のようなコードでテストしました。

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    PaintBox1: TPaintBox;
    PaintBox2: TPaintBox;
    procedure PaintBox1Click(Sender: TObject);
    procedure PaintBox2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.PaintBox1Click(Sender: TObject);
begin
  showmessage('Paintbox1');
end;

procedure TForm1.PaintBox2Click(Sender: TObject);
begin
  showmessage('Paintbox2');
end;

end.


えーと  2006-03-24 02:28:11  No: 20663

下のコントロールはクリックされてないので、単独で知ることはできません。
クリックされたコントロールが、親コントロールを通じて、親の座標でクリック
された位置を教えて、自分がその下にいるかどうか判断しなければなりませんね。
かなり面倒です。


デル太  2006-03-24 04:15:55  No: 20664

えーとさん、いつもありがとうございます。
今回の件は、先日ご指導いただいた件の延長なんです。
どうぞ、また相談にのってください。

えーとさんが前回サンプルで提示されたTLineにあたるものをTPaintBoxから派生させて作ることを考えています。
クリックを受け取りたいため、TPaintBoxから派生することを考えました。
複数のTlineインスタンスを生成して、各インスタンスごとにクリックした箇所の描画色を調べたいと思っています。

先日の例では次のようなクラス階層でした。

  TZukei ← TLine・・・(A)

この場合のTZukeiが親コントロールとなりますよね?
あれ?そういえばえーとさんはこの関係を「上位クラス」と表現なさいますね・・。
すると、親コントロールはTLineのインスタンスを登録した

  ZukeiList:  TObjectList・・・(B)

の方でしょうか?

それとも、Parentプロパティで指定する「親」のことかもしれませんね。

  ALine.Parent := Panel1 の場合はPanel1  ・・・(C)

  ※生成した複数のTLineは配置用のPanel上に配置する予定です。

こうやって整理すると、えーとさんがおっしゃているのは(C)のようです。
(B)でも代用できそうですね。
(C)と考えて続けます。

  1)クリックを受けたTLineのインスタンスが親コンポーネントにクリック位置の情報を渡す
  2)親コンポーネント(Panel1)がすべての子コントロールに対して、問合せ処理をする
    →TLine(Panel1.Controls[i]).AMethod(X,Y);
  3)該当する子コントロールは必要な処理をする

という感じをおっしゃっている気がします。

親の座標と子の座標の変換は、クリックを受け取った子のLeftやTopとクリック位置の情報から求められそうです。
また、別の子のLeftやTopを踏まえて、その子のクリック座標を求めることもできそうですね。
この判断は親ではなく、子が担当した方がスマートなのかもしれません。

この方向で考えて見ます。
実際にコードを作成して、報告または相談いたします。
そのときは、どうぞよろしくお願いいたします。


デル太  2006-03-24 05:53:16  No: 20665

えーとさん、ありがとうございました。
おかげで希望の処理ができました。

クリックされた子が親を見て、親が持つすべての子を処理しています。
形としてはクリックされた子がすべての処理をしている感じですね。
自分自身もその中に含まれます。
個人的にはちょっと不思議な感じで、こういう形でも問題ないのかわからずにとまどっています。
ご指導いただけると幸いです。

> この判断は親ではなく、子が担当した方がスマートなのかもしれません。

と思いつつも、作ってみたら、上記の形にはなっていませんでした。
チェックしているコードをTMyPaintBoxのメソッドにすればよいのかもしれませんね。
今後の課題にしようと思います。

-----
//重なったすべてのTPaintBoxでクリックを拾う実験20060323 byデル太
//結論:各インスタンスの領域内の座標に換算してクリックを拾うことができた
//TPaintBoxの場合、他のインスタンスが描画した場合でも、
//自分のインスタンス内の描画として判断される

//フォームにPanel1とButton1を配置して実行してください

unit Unit1;

interface

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

type
  TMyPaintBox = class(TPaintBox)
  private
  public
  protected
    procedure Paint; override;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Panel1: TPanel;
    procedure Button1Click(Sender: TObject);
    procedure MyPaintBoxMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
  //procedure MyPaintClick(
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;
  i: Integer; //描画する図形をずらすために使います

implementation

{$R *.dfm}

{ TMyPaintBox }

procedure TMyPaintBox.Paint;
begin
  inherited;
  with Self.Canvas do
  begin
    Pen.Width := 1;
    Brush.Style := bsClear;
    Rectangle(0,0,Width,Height);
    Pen.Width := 10;
    MoveTo(0,0);
    LineTo(100,100);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  AMyPaintBox: TMyPaintBox;
begin
  i := i + 1 ;
  AMyPaintBox := TMyPaintBox.Create(Form1);
  AMyPaintBox.Left := i * 20;
  AMyPaintBox.Top := i * 5;
  AMyPaintBox.Width := 100;
  AMyPaintBox.Height := 100;
  AMyPaintBox.Parent := Panel1; //表示
  AMyPaintBox.OnMouseDown:=MyPaintBoxMouseDown;
end;

procedure TForm1.MyPaintBoxMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  i: Integer;
  OyaX, OyaY: Integer; //親コンポーネントでのX,Y座標
  KoX, KoY:Integer; //子コントロールでのX,Y座標

begin
  OyaX := TMyPaintBox(Sender).Left + X;
  OyaY := TMyPaintBox(Sender).Top + Y;
  for i := 0 to Panel1.ControlCount -1 do
  begin
    with TMyPaintBox(Panel1.Controls[i]) do
    begin
      ShowMessage('今は奥から'+IntToStr(i) + '番目の図形をチェック中...');
      KoX := OyaX - Left;
      KoY := OyaY - Top;
      if Canvas.Pixels[KoX,KoY] = clBlack then
      begin
        ShowMessage('そこは黒です!');
      end;
    end;
  end;
end;

end.


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

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






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