dポイントプレゼントキャンペーン実施中!

Javaアップレットについて質問です。マウスをドラッグすると、マウスによって指定した位置に長方形を描き、Shiftキーを押したまま描かれた長方形の内部でドラッグすると、マウスを移動した距離だけ長方形を移動させる、というプログラムを作りたいのですが
Shiftキーを押したまま長方形の内部でドラッグすると、描いた長方形が消えてしまいます。
どうしていいかわからないので、改善点がありましたら教えてください。
なお、最初に長方形を描くところはできています。

プログラムは以下のとおり

import java.awt.*;
import java.applet.*;
import java.awt.event.*;

public class ex1123 extends Applet implements MouseListener, MouseMotionListener{
//Shiftキーを押しているかどうか
boolean isS = false;

//マウスが長方形の内部に入っているかどうか
boolean enter = false;

//長方形
Rectangle r1 = new Rectangle(0,0,0,0);

//Shiftキーを押したまま、マウスを押した位置と離した位置
Point p1;
Point p2;

public void init(){
addMouseListener(this);
addMouseMotionListener(this);
}

public void paint(Graphics g){
if(!r1.isEmpty()){
if(isS){
//マウスが長方形の内部にはいっていたら移動させる
if(enter){

//長方形の始点を移動させる
r1.x = r1.x + (p2.x - p1.x);
r1.y = r1.y + (p2.y - p1.y);
g.drawRect(r1.x, r1.y, r1.width, r1.height);
}
}

else{
g.drawRect(r1.x, r1.y, r1.width, r1.height);
}
}
}

public void mousePressed(MouseEvent e){
r1.setLocation(e.getPoint());
r1.setSize(0,0);
if((e.getModifiersEx() & MouseEvent.SHIFT_DOWN_MASK) ==
MouseEvent.SHIFT_DOWN_MASK){
isS = true;

//マウスが長方形の内部に入っているかどうか
enter = r1.contains(e.getPoint());
if(enter){

//p1はマウスを押した位置, p2はnull
p1 = e.getPoint();
p2 = null;
}
}

else{
isS = false;
}

repaint();
}

public void mouseDragged(MouseEvent e){
//マウスの位置
1if(enter)
p2 = e.getPoint();

//最初に描く長方形のサイズを決める
r1.setSize(Math.abs(e.getX() - r1.x), Math.abs(e.getY() - r1.y));
repaint();
}

public void mouseReleased(MouseEvent e){
//マウスを離す位置を指定
if(enter)
p2 = e.getPoint();

//最初に描く長方形のサイズを決める
r1.setSize(Math.abs(e.getX() - r1.x), Math.abs(e.getY() - r1.y));
repaint();
}

public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseMoved(MouseEvent e){}

}

A 回答 (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();
}
<マウスリスナのメソッド略>
}
    • good
    • 0
この回答へのお礼

うまくいきました。分かりやすい説明をありがとうございました。
paintは表示のみを行うこと、移動にtranslateを使うこと、などがよく分かりました。

お礼日時:2014/03/13 14:45

ぱっと見ただけですが



プロパティ isS と enter は両方あわせて moving とでもすべきでは?
プロパティ drawing も必要では?
メソッド paint はシステム都合で呼ばれるので、プロパティ r1 を更新してはいけない
メソッド mousePressed にてプロパティ r1 の初期化は drawing 時だけ
メソッド mouseDragged にてプロパティ r1 の変更は drawing 時だけ
メソッド mouseReleased の処理で moving や drawing を初期化
    • good
    • 0
この回答へのお礼

isSとenterを合わせること、paintでのr1の更新をしない、といった変更を加えたところ、ある程度改善しました。ありがとうございました。

お礼日時:2014/03/12 21:00

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!