Javaでお絵書きしてみる (4)


マウスのイベントを受け取って処理するプログラムを作成する。 ユーザからの入力に反応するプログラムを作成できる。


マウス入力を扱う例(1)

描画するウィンドウに対するマウス操作のイベントを受け取るクラスは、 ToyGraphics の(正確にはその祖先の java.awt.Component の) subclassである必要があります。

生成したウィンドウへのマウス操作のイベントを受け取るためには、 MouseLisenter インターフェイスを implements して addListener(MouseListener) を呼び出す必要があります。




Sample08.java
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;

public class Sample4 extends ToyGraphics implements MouseListener {
    public Sample4() { super(640,480); }
    public void run() {
	addMouseListener(this);  // ウィンドウに対するMouseイベントを自分で受け取る
	g2d.setPaint(Color.white);
	g2d.fill(new Rectangle2D.Double(0, 0, width, height));  // ウィンドウ全体を黒で塗りつぶす
	repaint(0,0,width,height); // 範囲を指定して再描画する (これが無いと変更が反映されない)
    }
    public void mouseClicked(MouseEvent e) { System.err.println("mouseClicked"); }
    public void mousePressed(MouseEvent e) {
	int mx = e.getX(), my = e.getY();
	System.err.println("mousePressed " + mx + " " + my);
	int w=10, h=10, x=mx-w/2, y=my-h/2;
	g2d.setPaint(Color.blue);
	g2d.fill(new Rectangle2D.Double(x,y,w,h));  // (x,y)の回りを10x10の青色の四角で塗りつぶす
	repaint(x,y,w,h);
    }
    public void mouseReleased(MouseEvent e) {
	int mx = e.getX(), my = e.getY();
	System.err.println("mouseReleased " + mx + " " + my);
	int w=10, h=10, x=mx-w/2, y=my-h/2;
	g2d.setPaint(Color.red);
	g2d.fill(new Rectangle2D.Double(x,y,w,h));  // (x,y)の回りを10x10の赤色の四角で塗りつぶす
	repaint(x,y,w,h);
    }
    public void mouseEntered(MouseEvent e) { System.err.println("mouseEntered"); }
    public void mouseExited(MouseEvent e) { System.err.println("mouseExited"); }


    public static void main(String[] args) {
	Sample4 app = new Sample4();
	app.run();
    }
}


Sample08.java の実行例
% java Sample3      
mouseEntered
mousePressed 104 83
mouseReleased 192 170
mousePressed 276 201
mouseReleased 236 295
mousePressed 394 395
mouseReleased 397 227






マウス入力を扱う例(2)




WinDraw.java
import java.util.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;

public class WinDraw extends ToyGraphics implements MouseListener {
    static final int RECTANGLE = 1;
    static final int CIRCLE = 2;

    boolean isDragging = false;
    int sx, sy, ex, ey; // Mouse pressed (sx,sy), released (ex,ey)
    Color strokeColor = Color.red;
    int shapeType = RECTANGLE;

    int[][] menuArea = {
	{0,0,100,30},
	{0,30,100,30},
	{0,60,100,30},
	{0,90,100,30},
	{0,120,100,30},
    };
    String[] menuString = { "Redraw", "Red", "Blue", "Rectangle", "Circle" };
    ArrayList<Shape> shapes;
    public WinDraw() { this(1280,720); }
    public WinDraw(int w,int h) {
	shapes = new ArrayList<Shape>();
	addMouseListener(this);
    }
    public void run() {
	redraw();
    }
    boolean inArea(int mx,int my,int x,int y,int w,int h) {
	return (mx >= x && mx < x+w && my >= y && my < y+h);
    }
    boolean inArea(int mx,int my,int[] r) {
	int x=r[0], y=r[1], w=r[2], h=r[3];
	return (mx >= x && mx < x+w && my >= y && my < y+h);
    }
    boolean checkMenu(int sx,int sy) {
	for (int i = 0; i<menuArea.length; i++) {
	    int[] r= menuArea[i];
	    if (inArea(sx,sy,r)) {
		System.err.println("menu "+i);
		switch (i) {
		case 0: redraw(); break;
		case 1: strokeColor = Color.red; break;
		case 2: strokeColor = Color.blue; break;
		case 3: shapeType = RECTANGLE; break;
		case 4: shapeType = CIRCLE; break;
		default: System.err.println("no menu"); System.exit(-1);break;
		}
		return true;
	    }
	}
	return false;
    }
    void redraw() {
	g2d.setPaint(Color.black);
	g2d.fill(new Rectangle2D.Double(0,0,width,height));
	drawMenu();
	for (Shape shape: shapes) { shape.draw(g2d); }
	repaint(0,0,width,height);
    }
    void drawMenu() {
	for (int i=0; i<menuArea.length; i++) {
	    int[] r = menuArea[i];
	    Rectangle2D shape = new Rectangle2D.Double(r[0],r[1],r[2],r[3]);
	    g2d.setPaint(Color.white);
	    g2d.fill(shape);
	    g2d.setPaint(Color.black);
	    g2d.draw(shape);
	    g2d.drawString(menuString[i], r[0]+5, r[1]+20);
	    repaint(r[0],r[1],r[2],r[3]);
	}
    }
    public void mouseClicked(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {
	sx = e.getX(); sy = e.getY();
	System.err.println("Pressed " + sx + " " + sy);
	isDragging = !checkMenu(sx,sy);
    }
    public void mouseReleased(MouseEvent e) {
	ex = e.getX();
	ey = e.getY();
	System.err.println("Released " + ex + " " + ey);
	if (! isDragging) return; // select menu
	int x = Math.min(sx,ex), y = Math.min(sy,ey), w = Math.abs(ex-sx), h = Math.abs(ey-sy);
	Shape shape;
	if (shapeType == RECTANGLE) {
	    shape = new Rect(x,y,w,h,3,strokeColor,null);
	} else {  // (shapeType == CIRCLE) 
	    shape = new Circle(x,y,w,h,3,strokeColor,null);
	}
	shape.draw(g2d);
	repaint(x,y,w,h);
	shapes.add(shape);
    }
    public void mouseEntered(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {}

    public static void main(String[] args) {
	WinDraw wd = new WinDraw();
	wd.run();
    }
}


Shape.java
import java.awt.*;

public abstract class Shape {
    int x, y;
    Color strokeColor, fillColor;
    abstract void draw(Graphics2D g2d);
}


Rect.java
import java.awt.*;
import java.awt.geom.*;

public class Rect extends Shape {
    int w, h, lineWidth;
    public Rect(int x,int y,int w,int h,int lineWidth,Color strokeColor,Color fillColor) {
	this.x = x; this.y = y; this.w = w; this.h = h; this.lineWidth = lineWidth;
	this.strokeColor = strokeColor; this.fillColor = fillColor;
    }
    void draw(Graphics2D g2d) {
	Rectangle2D shape = new Rectangle2D.Double(x,y,w,h);
	if (fillColor != null) {
	    g2d.setPaint(fillColor);
	    g2d.fill(shape);
	}
	if (strokeColor != null) {
	    g2d.setStroke(new BasicStroke((float) lineWidth));
	    g2d.setPaint(strokeColor);
	    g2d.draw(shape);
	}
    }
}


Circle.java
import java.awt.*;
import java.awt.geom.*;

public class Circle extends Shape {
    int w, h, lineWidth;
    public Circle(int x,int y,int w,int h,int lineWidth,Color strokeColor,Color fillColor) {
	this.x = x; this.y = y; this.w = w; this.h = h; this.lineWidth = lineWidth;
	this.strokeColor = strokeColor; this.fillColor = fillColor;
    }
    void draw(Graphics2D g2d) {
	Arc2D shape = new Arc2D.Double(x,y,w,h,0,360,Arc2D.OPEN);
	if (fillColor != null) {
	    g2d.setPaint(fillColor);
	    g2d.fill(shape);
	}
	if (strokeColor != null) {
	    g2d.setStroke(new BasicStroke((float) lineWidth));
	    g2d.setPaint(strokeColor);
	    g2d.draw(shape);
	}
    }
}


WinDraw.java の実行例
% javac WinDraw.java
% java WinDraw
Pressed 11 46
menu 1
Released 11 46
Pressed 65 103
menu 3
Released 65 103
Pressed 251 163
Released 430 315
Pressed 54 131
menu 4
Released 56 132
Pressed 683 272
Released 967 479
Pressed 30 74
menu 2
Released 31 74
Pressed 372 120
Released 683 382
Pressed 73 109
menu 3
Released 73 109
Pressed 135 273
Released 609 582

敢えて、ToyGraphicsの生成する1つのウィンドウだけで作ってみた「お絵描きツール」です。 ウィンドウの中に領域を定義してメニューとして何か表示して、それをクリックすることで状態を変化させます。 メニュー以外のウィンド領域はマウスボタンの「押す」「放す」イベントにより図形を配置します。

もっとオブジェクト指向らしいプログラムの書き方はありえますが、 ここでは「敢えて」目先の単純さを優先したプログラム例を示していると理解して下さい。 改善策はいろいろあります。特に「メニュー」回りの扱いは大いに改善の余地があることでしょう。


課題4

ウス入力を扱うJavaのプログラムを作成して下さい。 ファイル名は GReport04.java としましょう。

正しく動作するプログラムのみを提出すること。

作成したプログラムが正しく動作することを確認したら、 「宿題提出Web:1年ゼミ:課題4」 http://nw.tsuda.ac.jp/class/1semi/local/handin/up.php?id=kadai4 から提出して下さい。 提出ページの 「提出ファイル」に自分が作成した GReport04.java を指定し、 「コメント欄」には何の絵であるかの説明を記入して下さい。

提出した後は、正しく提出されていることを http://nw.tsuda.ac.jp/class/1semi/local/handin/list.php?id=kadai4 で必ず確認しておいて下さい。

〆切は1週間後の10:30です。