- ベストアンサー
長方形を描いて、それを移動させるアップレット
- Javaアップレットについて質問です。マウスをドラッグすると、マウスによって指定した位置に長方形を描き、Shiftキーを押したまま描かれた長方形の内部でドラッグすると、マウスを移動した距離だけ長方形を移動させる、というプログラムを作りたいのですがShiftキーを押したまま長方形の内部でドラッグすると、描いた長方形が消えてしまいます。
- どうしていいかわからないので、改善点がありましたら教えてください。なお、最初に長方形を描くところはできています。
- 以下のプログラムは、Javaアップレットを使用してマウスをドラッグして長方形を描くプログラムです。Shiftキーを押しながら長方形の内部でドラッグすると、長方形が消えてしまいます。長方形を移動させるためには、マウスをドラッグして移動距離を計算し、長方形の位置を更新する必要があります。解決策として、マウスのドラッグ開始位置と終了位置を記録し、その差を長方形の位置に加えることで移動させることができます。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
まずpaint()メソッドの中で表示と操作が混ざってしまっているのが問題ですね。 paint()メソッドはウィンドウが重なってて上になった時などその瞬間の表示を するために呼び出されます。 したがって表示のみを行います。現在のr1の表示、drawRectだけすればいいわけです。 そしてマウスのイベントのところでr1を変更し、最後にrepaint()すれば四角の表示が 更新されていきます。r1を変更することが操作になるわけです。 今回は(1)「新規に四角を書く」という操作と(2)「既存の四角を移動させる」という操作があります。 ユーザの操作としてはmousePressedのタイミングで(1)か(2)が決まりますのでフラグ変数を セットしてmouseDraggedやmouseReleasedで条件分岐するとわかりやすいでしょう。 四角形の移動ですが、座標Aでボタンを押し座標Bをとおって座標Cと移動させたとき、座標ABの 差分が移動量になります。Rectangleクラスのtranslate()メソッドを使うと Rectangleオブジェクトに対して移動量を指定することができます。 そして次回のために座標Bを示すp2をp1にコピーし、次回の始点としておきます。 次に座標Cに移動したときには座標BCの差分を求めますので座標Cをp2とすればまた移動量が 求められます。 蛇足ですが移動かどうかを判断するメソッドを作ってすっきりさせることもできます。 たとえばこんな感じ。(操作の違いを色で分かるようにしてみました) 元のプログラムを利用していますので、新規に描画する際、マウスを左上にドラッグすると 右下に大きくなるのは次の課題ですかね(^^; public class RectFrame <略>{ //移動として操作中かどうか boolean isDragged = false; //長方形 Rectangle r1 = new Rectangle(0,0,0,0); //Shiftキーを押したまま、マウスを押した位置と離した位置 Point p1; Point p2; //確認用の色指定 Color col; public void init(){ addMouseListener(this); addMouseMotionListener(this); col = Color.black; //既定値を黒 } public void paint(Graphics g){ //表示処理のみ行う g.setColor(col); g.drawRect(r1.x, r1.y, r1.width, r1.height); } //移動操作かどうかの判定用メソッド private boolean isDraggMode(MouseEvent e){ return ((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) == MouseEvent.SHIFT_DOWN_MASK) && r1.contains(e.getPoint()); } public void mousePressed(MouseEvent e){ //マウスが長方形の内部に入っているかどうか if(isDraggMode(e)){ //p1はマウスを押した位置, p2はnull p1 = e.getPoint(); p2 = null; isDragged = true; col = Color.red; }else{ r1.setLocation(e.getPoint()); r1.setSize(0,0); col = Color.green; } repaint(); } public void mouseDragged(MouseEvent e){ //マウスの位置 p2 = e.getPoint(); if(isDragged){ r1.translate((p2.x - p1.x),(p2.y - p1.y)); p1 = p2;//次回はこれが始点になる }else{ //最初に描く長方形のサイズを決める r1.setSize(Math.abs(e.getX() - r1.x), Math.abs(e.getY() - r1.y)); } repaint(); } public void mouseReleased(MouseEvent e){ //マウスを離す位置を指定 p2 = e.getPoint(); if(isDragged){ isDragged = false; r1.translate((p2.x - p1.x),(p2.y - p1.y)); p1 = null; p2 = null; }else{ //最初に描く長方形のサイズを決める r1.setSize(Math.abs(p2.x - r1.x), Math.abs(p2.y - r1.y)); } col = Color.black; repaint(); } <マウスリスナのメソッド略> }
その他の回答 (1)
- Ogre7077
- ベストアンサー率65% (170/258)
ぱっと見ただけですが プロパティ isS と enter は両方あわせて moving とでもすべきでは? プロパティ drawing も必要では? メソッド paint はシステム都合で呼ばれるので、プロパティ r1 を更新してはいけない メソッド mousePressed にてプロパティ r1 の初期化は drawing 時だけ メソッド mouseDragged にてプロパティ r1 の変更は drawing 時だけ メソッド mouseReleased の処理で moving や drawing を初期化
お礼
isSとenterを合わせること、paintでのr1の更新をしない、といった変更を加えたところ、ある程度改善しました。ありがとうございました。
お礼
うまくいきました。分かりやすい説明をありがとうございました。 paintは表示のみを行うこと、移動にtranslateを使うこと、などがよく分かりました。