TImageをマウスで移動するには?

解決


HMMA  2008-03-02 18:00:07  No: 29982

Form1にImage1を置き、マウスでクリックした位置にImage1を移動させたくて、
次のように書いたのですが、Image1の外(Form1上)では、動いてくれません。
TForm1MouseDownでは、肝心なImage1の上で動いてくれません。
こんな場合は、どうしたら良いものでしょう。?
また、下の「var I:Integer」は、procedure TForm1.Image1MouseDownの中に書くと、
認識しない(使えない)ようです。何故でしょう?
よろしくお願いします。delphi6pro+xp

var
Pxy:array[0..1] of TPoint;
Tx,Ty:Integer;
I:Integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Image1.Width:=200;
  Image1.Height:=200;
  with Image1.Canvas do
    begin
    Rectangle(0,0,200,200);
    Rectangle(50,50,150,150);
    MoveTo(0,100);
    LineTo(200,100);
    MoveTo(100,0);
    LineTo(100,200);
    end;
  end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);

begin
  Pxy[I].x:=x;  Pxy[I].y:=y;
  
  //座標確認用
  Label1.Caption:='座標 : '+IntToStr(I)+':  '+IntToStr(Pxy[I].x)+' , '+IntToStr(Pxy[I].y) ;
  I:=I+1;
  If I>1 then  Begin
  Tx:=Pxy[1].x-Pxy[0].x;
  Ty:= Pxy[1].y-Pxy[0].y;

  //座標確認用
   Label2.Caption:='Top,Left : '+ IntToStr(Image1.Top)+' , '+IntToStr(Image1.Left);

   Image1.Top:=Image1.Top+ Ty;
   Image1.Left:=Image1.Left+Tx;
   I:=0;
   end;
end;

end.


表裏未里  URL  2008-03-02 18:17:17  No: 29983

TForm1MouseDownに書いて、Image1.Enableをfalseにしてやるってのはどうでしょうか?


KHE00221  URL  2008-03-02 19:41:44  No: 29984

>Image1の外(Form1上)では、動いてくれません。
>TForm1MouseDownでは、肝心なImage1の上で動いてくれません。

Image1MouseDown は Image1でクリックすると実行されるので
Form1でクリックしても実行されない

TForm1MouseDown は Form1上でクリックすると実行されるので
Image1でクリックしても実行されない

という事は・・・・・両方設定すればいいんだけど?

ほかにコンポーネント等が増えると全てのコンポーネントに
設定しなくてはいけなくなるので

procedure TForm1.ApplicationMessage(var Message: TMSG; var Handled: Boolean);
var
    PT: TPoint;
begin
    inherited;

    if Message.message = WM_LBUTTONDOWN then
    begin
      PT := ScreenToClient(Message.pt);
      Image1.Left := PT.x;
      Image1.Top  := PT.y;
    end;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
    Application.OnMessage := ApplicationMessage;
end;

こんな感じにするといい感じ?


HMMA  2008-03-02 21:03:49  No: 29985

表裏未里さん、KHE00221さん  いつもありがとうございます。
 
>TForm1MouseDownに書いて、Image1.Enableをfalse
>という事は・・・・・両方設定
>procedure TForm1.ApplicationMessage

どれも望みの動きをしてくれました。
Enableをfalseにすることで画像を表示したままで、下のFormの座標を取得できる事など、思いもしませんでした。
Messageの方は、私にとってはブラックボックスで、新しい課題と成りましたが・・・。

いつも、あまりにも早く教えていただけて、簡単に解ったような気になり、解決ボタンを押した後で、同じことが聞き難くなり後悔しています。

最初の例で、変数「I」は、ここでしか使っていないので・・・

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
I:Integer; ・・・・・・・・・・・宣言の位置を変更
begin
以下省略

とすると・・・
[ヒント] Unit1.pas(67): 'I' に代入された値は使われていません
[警告] Unit1.pas(55): 変数 'I' は初期化されない場合があります

[警告]は良いにしても、Imageは移動してくれません。何故でしょう?
タイトルの質問とは別の問題なような気もしますが「Image1MouseDown」つながりという事で、これも宜しくお願いします。


もにゃ  2008-03-03 00:53:02  No: 29986

暇なので支援。
Panel1,Image1は画面上に貼り付けてやってください。

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Panel1: TPanel;  //障害物として用意
    Image1: TImage;  //今回のターゲット
    procedure FormCreate(Sender: TObject);
  private
    { Private 宣言 }
    procedure ApplicationMessage(var Message: TMSG; var Handled: Boolean);

  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.ApplicationMessage(var Message: TMSG;
  var Handled: Boolean);
var
    PT: TPoint;
begin
  //アプリケーションに来るメッセージをすべてチェック
  inherited; //子コントロールにもメッセージを流す
  //左マウスボタンを押した時の動作を記述
  if Message.message = WM_LBUTTONDOWN then
  begin
    //messageの中にはメッセージにより様々なデータが格納されている
    //今回はWM_LBUTTONDOWN
    //中身はMSDNを調べてください。
    PT := ScreenToClient(Message.pt);
    Image1.Left := pt.X - (Image1.Width  div 2);
    Image1.Top  := pt.Y - (Image1.Height div 2);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //アプリケーションに通るメッセージを閲覧
  Application.OnMessage := ApplicationMessage;
  //イメージの設定
  Image1.Width:=200;
  Image1.Height:=200;
  with Image1.Canvas do
    begin
    Rectangle(0,0,200,200);
    Rectangle(50,50,150,150);
    MoveTo(0,100);
    LineTo(200,100);
    MoveTo(100,0);
    LineTo(100,200);
    end;
end;

end.


HMMA  2008-03-03 02:08:35  No: 29987

もにゃさん、お暇とはいえ、ご支援ありがとうございます。

しかも、詳細解説。
 //中身はMSDNを調べてください。・・・はい。

障害物を2重3重に用意して見ましたが、教えていただいたどの例も、障害を物ともせず貫通しました。

後はvar I の疑問だけなのですが・・・


もにゃ  2008-03-03 02:37:36  No: 29988

変数の宣言については、やはり入門書を読むことをお勧めします。
入門書が理解できていれば、この問題はすんなり解決するでしょう。
procedureの中でI:integerを宣言すること自体は全く問題ありません。
ためしに、新規プロジェクトを作って、MouseDownでIを参照させてみてください。
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  I:Integer;
begin
  //以下二つの動作がないと警告、ヒントがでるはずです。
  I:=10; //Iの初期化
  caption:=IntToStr(I); //Iの参照
end;

>>[警告] Unit1.pas(55): 変数 'I' は初期化されない場合があります
Iの値が決められていない状態でIの値を参照しているのは大問題です。

>>[ヒント] Unit1.pas(67): 'I' に代入された値は使われていません
Iを一度も使用しないでいることです。
つまり、Iはあってもなくてもプログラムは同じ動作をすることを意味します。


HMMA  2008-03-03 03:19:11  No: 29989

先に、解決ボタンを押した後で、同じことが聞き難くなり後悔していると書いたばかりなのに、また、つい押してしまい後悔しています。

タイトルの問題は解決したものの、var I に付いて疑問を持ったのは、私にとっては正解で、もにゃさんがお暇だった事は、私に取って幸運でした。

>変数の宣言については、やはり入門書を読むことをお勧めします。
・・・と言われて、何冊もない手持ちの入門書を見てみましたが、すぐには解りません。

すいませんが、もにゃさん、もう少し教えてください。

>ためしに、新規プロジェクトを作って、MouseDownでIを参照させてみてください。
ここで、 caption:=IntToStr(I); は問題なく「10」が表示されましたが、
「Iを参照させてみて」が解りません。


HMMA  2008-03-03 07:36:35  No: 29990

ようやく仰る意味がわかりました。

「I:=10; //Iの初期化」をコメントアウトすると「1074822732」と意味不明な数値。

変数は初期化しないでは使えない、解っていたつもりが・・・

ブロックの中で I:Integer=0;  とすると、
[エラー] Unit1.pas(52): ローカル変数は初期化できません

begin 以降でI:=Integer=0;としても、クリックのたびIが0になる、
それで、ブロックの外で var I:Integer を宣言したのですが、たまたま「I」が上手く機能してくれたのか、
ブロックの外で var I:Integer とした時は、I:=Integer=0;と理解してくれたのか、いずれにしても、
変数は初期化しないでは使えないものだと、改めて認識できました。

もにゃさん、皆さん本当に有難うございました。本当に解決です。


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

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






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