• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:targetのCloneを作成したい)

targetのCloneを作成してDrag&Dropしたい

このQ&Aのポイント
  • Rectangleで色を塗ったComponentをDrag&Dropするため、targetのCloneを作成したい。現在うまくいかず困っています。
  • 移動時の関数内でComponentを作成して移動しているが、うまくいっていない。
  • 初心者向けの質問ですが、誰か教えていただけないでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • kacchann
  • ベストアンサー率58% (347/594)
回答No.5

症状、了解しました。 とりあえずこれを試してみてください。 (1)MyPainコンストラクタ内で「独自の」LayoutManagerを  作成し設定しているが、それをやめる。 つまりMyPainにはLayoutManagerを設定しない。   (2)とりあえず「引数なしバージョンのMyComponentコンストラクタ」も 用意する。内部処理は、とりあえずなにもしなくてよい。 (これはドロップ先に貼り付けるインスタンス作成のために使うため。 本質的には重要ではない) (3)現在、はじめに表示されているMyComponentインスタンスのサイズを setPreferredSize() で"設定"しているが、それをやめて、かわりに setSize() で設定する。(この処理を既存のMyComponentコンストラクタに含めてもよい) --- これが前準備。 で、次にドロップ先の処理。 (4) drop()メソッドの中のif-elseブロックの中味をこうする。 単にインスタンスを生成してaddするだけ。 if(……){ JComponent c = new MyComponent();//引数なしバージョン c.setSize(50,50);//※ c.setOpaque(true);//※ c.setBackground(Color.blue);//※ add(c); c.setLocation(e.getLocation()); e.dropComplete(true); }else{e.dropComplete(false);} //「※マーク」の行の処理は、 //コンストラクタ内に含めておくのもよいかも --- とりあえずこんなところです。 MyComponentが「表示されなかった」一番の原因は おそらく「sizeが0だったから」、では? 質問者さんのソースコード見る限り、 setPreferredSize()メソッドに対する認識が 間違っているように思います。 setPreferredSize()を呼んだところでコンポーネントのサイズが 「設定される」わけではありません。 基本的にこのメソッドは、 「使う必要がないなら使わない」 「とりあえず使わない」 という方針でいいと思います。 --- ちなみに本当に「クローン」(コピー)を生成する方法もあります。 この方法を使えば、上記の「sizeが0」という問題は起こりません。 (なぜなら、サイズがちゃんとあるインスタンスの「コピー」だから) http://www.asahi-net.or.jp/~dp8t-asm/java/tips/Cloneable.html 場合によっては「コピー」は便利ですので参考にしてください。

marie-kachi
質問者

お礼

ここの部分を変更しました。 public Object getTransferData(DataFlavor flavor){ //以下の「f,tile,str_」は広域変数としてprivate宣言してあります f = flag_mc; tile = this.tileEvents; str_ = new String(str); JComponent comp = new MyComponent(f,tile,str_); Point loc = tileEvents.target1.getLocation();      Color color = tileEvents.target1.getBackground(); comp.setSize(new Dimension(50,50)); comp.setLocation(loc); comp.setOpaque(true); comp.setBackground(color); p = tileEvents.p1; super.add(comp); comp.paintComponents(comp.getGraphics()); comp.addMouseListener(this); comp.addMouseMotionListener(this); this.dragSource = new DragSource(); this.dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, this); comp.validate(); return (comp); // return (this); } こんな感じなのです。 あまりにもトンチンカンなことをしているかもしれません…お恥ずかしながら たぶんこんな感じでディープコピーを作るのではないかな??とおもいまして 予想ではディープコピーなコンポーネントは作成されていると思います。ただ表示ができなくて困っています。 やっていることは、回答者様が教えてくださったことをMyComponentクラスで行っているように思います。 何かお気づきの点がありましたら教えていただきたくおもいます。

marie-kachi
質問者

補足

とりあえずやってみました!…だめでした。 Dragした際にエラーメッセージを吐き出してしまいました…うふふ、出来損ないですみません 実はあれからクローンを作ろうと必死こいてみたのです。 MyComponentクラスの public Object getTransferData(DataFlavor flavor){} というクラスで自分自身をMyPainクラスのdrop()関数内 MyComponent comp = (MyComponent) e.getTransferable().getTransferData(MyComponent.compFlavor); に転送していることに最近気づきました…遅い そこで転送するものを自分自身ではなく、自分のコピーにしようと思い、 public Object getTransferData(DataFlavor flavor){}の中をreturn(this);ではなく、 MyComponent c = (MyComponent)this.clone(); return (c); で行ってみました。見事表示され自分のクローンが移動できたのですが…クローンを動かすと自分自身も動いてしまい、もどかしい思いをしました。(シャローコピーだったようです) 別々の動きをしたい場合はディープコピーでないといけないらしく、それを作成したつもりで移動してみると…今度はクローンが表示できませんでした。 たぶん最初の質問と同じような現象が起こっているように思われます。 ちらっと見ていただいてよろしいですかね? なんかほんといっぱい聞いてしまって申し訳ありません…

その他の回答 (9)

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.10

#1です。 とりあえずわかったこと…。(※謝罪) 「シャローコピーの件」ですが、 どうもうまくいかないようです。 ぼく始めに試した時は「ちゃんと」動くように見えたのですが、 別バージョンのJavaランタイムで動かしたら、 「元インスタンスとdrop先インスタンスが一緒に動く(ように見える)」 症状になりました…。 (※どうも表示がおかしくなってるんじゃないか…と思うのですが) ということで、「シャローコピーの件」は こうなってしまうともう、手に負えそうもないです。 (Componentクラスの構造が複雑なので、ここから 「ディープコピー」に修正するのもちょっとムリっぽい 感じもします) --- こうなると、あとは 「新規インスタンス作成」という普通の方法しかないような。 でも、それでうまくいかないんですよね。 だとすると、ちょっとぼくには解決法が思い浮かびません。 --- ところで、 前にぼくは 「(#5の『お礼欄』のソースコードは)ディープコピーではない」 と書きましたが、 表現がよくありませんでした。 「この方法を、ことさら『ディープコピー』という呼び方は しないだろう」と言うべきでした。 (実質上ディープコピーによるインスタンス生成と同じですよね) --- 最後に…。アドバイス(かな?)。 質問者さんご自身で、 「もっと短いコード」を別に作って実際に書いて動かしてみたりして、 つまりコードを細分していって、「問題箇所」を切り分けていかないと、 原因を突き止めるのは、むずかしいんじゃないかな? それは逆にいえば、 そういう短い完全なコードを掲載してくれれば、 より有用な回答が得られたかも。

marie-kachi
質問者

お礼

はい、わかりました。 私事に長い間お付き合いしてくださって本当にありがとうございました。とりあえずもうちょっとがんばってみます! ほんともう、こんな親切な方がいらっしゃることに大変驚きました。 回答者様には1000ポイントぐらい差し上げたいほどです(泣) また何か進歩できましたらご報告したいとおもいます。 本当にありがとうございました☆

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.9

#7補足欄のソースコード自体に とくに問題となる箇所はないように思います。 --- これまで「掲示してくれたソースコード」には、 「それ自体とくに問題となる箇所」はなさそうです。

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.8

あ、ごめん。 #5でぼくが書いた方法で「エラーがでる」とのことです。 MyComponentクラスのdragGestureRecognized()の内部処理なんですけど、 これを public void dragGestureRecognized(DragGestureEvent e){ if((e.getDragAction()|DnDConstants.ACTION_COPY_OR_MOVE)!=0){ e.startDrag(DragSource.DefaultCopyDrop, this, null); } } とすれば、とりあえず(#5で書いた僕の方法で)動くかも。 気づいたのでとりあえず報告。

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.7

#1です >たぶんこんな感じでディープコピーを作るのではないかな?? …違います(~。~) #5の「補足欄」に書かれているソースコードは、 これ、ディープコピーではありませんよ。 思いっきり普通の「新規インスタンス作成」です。 話がややこしくなるので、「ディープコピー」のことは とりあえず置いておくことにしましょう。 (※ディープコピーのやり方は教えませんので あきらめてください(*^^*)) --- 「シャローコピー」か「ディープコピー」か「新規インスタンス」かの違いは 関係ないはず。問題は「インスタンス生成法の違い」にあるのではなく、 別のところにある気がします。 あと 「getTransferData()で、自身を返すか、それともコピーを返すか」 の違いも、その違い自体はどちらでもいいはずで、 問題はべつの箇所にある気がします。 (※自身を返す場合は、データ受け取り側つまりdrop()内で、 そこではじめて自身の「コピー」を作成すればいいだけだから。 つまり「始めにコピーするか」と「後でコピーするか」の違い) --- とりあえず、話をシンプルにしましょう。 「シャローコピー」で"一応"うまくいったのですから、 まず、そのソースコードを手がかりに考えてみることにしましょう。 「シャローコピー」で"一応"うまくいった(、けれど元のインスタンスも動いてしまう)時の、 ・MyComponentクラスのclone()メソッド全部 ・getTransferData()メソッド全部 ・drop()メソッド全部 ・MyPainクラスのコンストラクタ ・MyComponentクラスのコンストラクタ のソースコードを教えてください。 (※全部同時に教えてもらわないことには、回答つけようがないので。 一部だけを見て回答できないので)

marie-kachi
質問者

補足

とりあえずこんな感じです↓ //MyComponentのクラス public class MyComponent extends JComponent implements Transferable, DragGestureListener, MouseListener, MouseMotionListener, Cloneable{ public Object getTransferData(DataFlavor flavor){ try{ MyComponent comp = (MyComponent)this.clone(); return(comp); }catch(CloneNotSupportedException e){} } //MyPainのクラス   public void drop(DropTargetDropEvent e){    e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);    try{  if((e.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0){         MyComponent comp = (MyComponent) e.getTransferable().getTransferData(MyComponent.compFlavor);     Container cont = comp.getParent();     cont.repaint(); Point location = e.getLocation(); super.add(comp); comp.setLocation(location); comp.revalidate(); super.getParent().repaint(); e.dropComplete(true); } else{ e.dropComplete(false); } } catch(Exception ex){ e.dropComplete(false); } } こんな感じです。MyPainクラスのLayoutの部分はすでに削除してあります。よろしくお願いしますm(._.)m

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.6

#1です #5のところで 「setPreferredSize()メソッドに対する認識が間違っているように思う」 と書きましたが、 それは「勝手な言い過ぎ」でした。 ごめんなさい。 むしろ、よくご存知なのかもしれませんね。 いろいろ反省・・・。 --- #5のやりかたで不都合があれば言ってください。 (ぼくは勝手にレイアウトマネージを削除する方針をとりましたが、 それで構わなかったでしょうか)

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.4

#1です。「import文は省略」とか「やっぱ書いて」とか 二枚舌なこと(?)を言ってごめんなさい。 よく考えたら、import文自体、 たいした分量にはなるわけないことに気づきました。 「import文は省略」と言ったことは、言いすぎ(ぼくが 口出しするようなことではなかった)でした。 反省。 --- ソースコード動かさせていただきました。 おお、Drag&Dropだ…。 --- >初めはこの関数の中でもう1度Componentを作成してしまおう >かという力技を試みましたが、失敗しました >そこでCloneを作成したいのですが、うまくいきません うまくいかない、というのは、 「どのようにうまくいかない」のですか。 ぼくがやってみたところ、普通に 「単にMyComponentインスタンスを、コンストラクタ使って作成して 親コンポーネント上にぺタっとaddして表示」 することはできました。 これはぼくには一見「うまくいった」ようにも見えるのですが、 これでは「失敗」なのですか? ・どうダメなのか ・親コンポーネント上にaddした新規インスタンスの、 どのような振る舞いがダメなのか ・実はたんに「新規インスタンスが表示されない」だけである。 など、そのへんの具体的な「症状」の説明よろしく。 (「別インスタンスを作成したい」と言わず、「Cloneを作成したい」 というように、あえて「Clone」という言葉を使ったのには理由がある みたいですが、どうですか?)

marie-kachi
質問者

補足

私の症状は「実は単に新規インスタンスが表示されない」レベルの問題です T_T 自分で、「Dragを実際行なうクラスで新規コンポーネントを作成し、それをDropEndした場所に表示しようとした」のですが…できませんでした。 今私がやりたいことは、親コンポーネントをDragして、DropEnd先にその親コンポーネントのコピー(これを指す為に私はCloneと使いました)を表示させたいのです。(親コンポーネントはその場に表示されたまま) 自分で別インスタンスが作成できなかったため、Cloneと使いました…申し訳ありません、特にCloneにこだわりはありませんです 親コンポーネント上に新規インスタンスをaddするとは、どのクラスで行なったのでしょうか??教えていただけるとむちゃくちゃ嬉しいです(>_<)

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.3

「補足欄」だけでなく 「お礼欄」にも書き込める(つまり両方に書き込める)…と思うノデ活用しましょう。 --- あと、 分割してお書きになっているので、 けっきょく字数制限はそれほど厳しくなくなったことになるので、 「必要なimport文」の記入もよろしく。

marie-kachi
質問者

補足

import java.applet.*; import java.awt.*; import java.awt.datatransfer.*; import java.awt.dnd.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import java.lang.*; はい…何せ不慣れなものでどうしてよいものかわかりませんでしたm(_ _)mとりあえずこのような感じになっております。

回答No.2

その続きは??

marie-kachi
質問者

補足

//(2)コンポーネント作成クラス public class MyComponent extends JComponent implements Transferable, DragGestureListener, MouseListener, MouseMotionListener { public static DataFlavor compFlavor = new DataFlavor("application/x-java-object", "Object"); Point draggedPoint = null; private Point pressedPoint = null; private DragSource dragSource = null; private String str; TileEvents tileEvents; public MyComponent(TileEvents tileEvents){ super(); this.tileEvents = tileEvents;    super.addMouseListener(this);   super.addMouseMotionListener(this); this.dragSource = new DragSource(); this.dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_COPY_OR_MOVE, this); } public void paint(Graphics g){ super.paint(g); Dimension sz = super.getSize(); } //不透明なJComponentなので背景を自分で描画する protected void paintComponent(Graphics g){ super.paintComponent(g); if(super.isOpaque()){ Dimension sz = super.getSize(); g.setColor(super.getBackground()); g.fillRect(0, 0, sz.width-1, sz.height-1); } } public Object getTransferData(DataFlavor flavor){ return this; } public DataFlavor[] getTransferDataFlavors(){ DataFlavor[] f = new DataFlavor[1]; f[0] = this.compFlavor; return f; } public boolean isDataFlavorSupported(DataFlavor flavor){ if(flavor.getHumanPresentableName().equals ("Object")){ return true; }else{ return false; } } public void dragGestureRecognized(DragGestureEvent e){ Dimension sz = super.getSize(); Rectangle b = new Rectangle(2, 2, sz.width-3, sz.height-3);   if((e.getDragAction() |   DnDConstants.ACTION_COPY_OR_MOVE) != 0){ MouseEvent me = (MouseEvent) e.getTriggerEvent(); this.draggedPoint = new Point(me.getX(), me.getY()); MyPain pain = (MyPain) super.getParent(); tileEvents.ta.append("タイル移動\n"); } }   e.startDrag(DragSource.DefaultMoveDrop,   this, pain); } //(3)Dragイベントが起こると呼び出されるクラス class MyPain extends JComponent implements DragSourceListener, DropTargetListener{   private DropTarget dropTarget = null;   TileEvents tileEvents;   private String panel; public MyPain(String title, TileEvents tileEvents){ super(); this.tileEvents = tileEvents; panel = title; super.setLayout(new LayoutManager(){ public void layoutContainer(Container target){ Component comp = target.getComponent(i); Dimension sz = comp.getPreferredSize(); comp.setSize(sz); } }); super.setBackground(Color.white); super.setOpaque(true); this.dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY, this, true); } //不透明なJComponentなので背景を自分で描画する protected void paintComponent(Graphics g){ super.paintComponent(g); if(super.isOpaque()){ Dimension sz = super.getSize(); g.setColor(super.getBackground()); g.fillRect(0, 0, sz.width, sz.height); } } //ドロップターゲット側(p1)のイベントハンドラ public void dragEnter(DropTargetDragEvent e){ e.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE); } //ドロップターゲット側でドロップが実行された時に呼ばれる public void drop(DropTargetDropEvent e){ e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); try{ if((e.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0){ MyComponent comp = (MyComponent) e.getTransferable().getTransferData(MyComponent.compFlavor); Container cont = comp.getParent(); cont.remove(comp); cont.repaint(); Point location = e.getLocation(); super.add(comp); comp.setLocation(location); comp.revalidate(); super.getParent().repaint(); e.dropComplete(true); }else{e.dropComplete(false);} }catch(Exception ex){e.dropComplete(false);} }

  • kacchann
  • ベストアンサー率58% (347/594)
回答No.1

>現在target自体をDragしているのを >Cloneを作成したいのですが、うまくいきません。 その「現在うまくいっている」というやつの、 かつ、枝葉(重要でない部分)をバッサリ削ぎ落とし、 なおかつ、コンパイル可能・稼動可能なものの ソースコードを 載せてください。 字数制限にひっかかるなら とりあえずimport文は省略。

marie-kachi
質問者

補足

クラス3つ分あり、全てを表示できないため分割して書き込みます… 見にくいかも知れませんがよろしくお願いします //(1)mainとなる関数 public class TileEvents extends Applet{ TextArea ta; MyPain p1,p2; MyComponent target1; TextField begin; public void init(){ MenuFrame mf = new MenuFrame("TileProgram",this); mf.setSize(800,500); MyPain p1 = new MyPain("p1",this); MyPain p2 = new MyPain("p2",this); p1.setPreferredSize(new Dimension(200,300)); p2.setPreferredSize(new Dimension(200,300)); MyComponent target1 = null;//アイコン作成 target1 = new MyComponent(this); p1.add(target1); target1.setPreferredSize(new Dimension(50,50)); target1.setLocation(25,25); target1.setOpaque(true); target1.setBackground(Color.blue); mf.getContentPane().add(p1); mf.getContentPane().add(p2); Container cp = mf.getContentPane(); cp.add(sp); mf.show(); ta = new TextArea(16,65); this.add(ta); } }

関連するQ&A