mousedraw.java_使用Draw方便的进行绘图

1.[代码][Java]代码

package crazyMonkey.draw;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.awt.image.*;

import java.io.*;

import java.net.*;

import java.util.LinkedList;

import java.util.TreeSet;

import javax.imageio.ImageIO;

import javax.swing.*;

import java.util.ArrayList;

/**

* 绘图类,此类实例提供基本的绘图支持,包括:

*

*

基本几何图形

*

图片

*

文本

*

*

*

此类对象提供对基本事件的支持,例如鼠标移动,键盘按键处理等事件。用例只需要实现{@link DrawListener}接口,

* 就可以完成对基本事件的处理。另外,此类实例提供了将画布上的图像保存为实际图片的功能。

*

* @author crazyMonkey

*/

public final class Draw implements ActionListener, MouseListener,

MouseMotionListener, KeyListener {

/*

* 预定义颜色

*/

public static final Color BLACK = Color.BLACK;

public static final Color BLUE = Color.BLUE;

public static final Color CYAN = Color.CYAN;

public static final Color DARK_GRAY = Color.DARK_GRAY;

public static final Color GRAY = Color.GRAY;

public static final Color GREEN = Color.GREEN;

public static final Color LIGHT_GRAY = Color.LIGHT_GRAY;

public static final Color MAGENTA = Color.MAGENTA;

public static final Color ORANGE = Color.ORANGE;

public static final Color PINK = Color.PINK;

public static final Color RED = Color.RED;

public static final Color WHITE = Color.WHITE;

public static final Color YELLOW = Color.YELLOW;

/*

* 演示用蓝色 RGB值 (9, 90, 166)

*/

public static final Color BOOK_BLUE = new Color(9, 90, 166);

/*

* 算法演示用色 暗红 RGB值 (173, 32, 24)

*/

public static final Color BOOK_RED = new Color(173, 32, 24);

// 默认画笔颜色

private static final Color DEFAULT_PEN_COLOR = BLACK;

private static final Color DEFAULT_CLEAR_COLOR = WHITE;

// 画布边界宽度,默认占画布宽度的 5%

private static final double BORDER = 0.05;

private static final double DEFAULT_XMIN = 0.0;

private static final double DEFAULT_XMAX = 1.0;

private static final double DEFAULT_YMIN = 0.0;

private static final double DEFAULT_YMAX = 1.0;

// 默认的画布大小

private static final int DEFAULT_SIZE = 512;

// 默认画笔半径

private static final double DEFAULT_PEN_RADIUS = 0.002;

// 默认字体

private static final Font DEFAULT_FONT = new Font("SansSerif", Font.PLAIN, 16);

// 当前画笔颜色

private Color penColor;

// 画布大小

private int width = DEFAULT_SIZE;

private int height = DEFAULT_SIZE;

// 当前画笔半径

private double penRadius;

// 用于标识是否立即绘制画面,或者等待到下一次绘制时

private boolean defer = false;

private double xmin, ymin, xmax, ymax;

// 窗口默认标题

private String name = "Draw";

// 同步对象

private Object mouseLock = new Object();

private Object keyLock = new Object();

// 当前字体

private Font font;

// 缓冲绘制对象

private BufferedImage offscreenImage, onscreenImage;

private Graphics2D offscreen, onscreen;

// 绘制面板框架

private JFrame frame = new JFrame();

// 鼠标状态参数

private boolean mousePressed = false;

private double mouseX = 0;

private double mouseY = 0;

// 键盘按键状态集

private LinkedList keysTyped = new LinkedList();

private TreeSet keysDown = new TreeSet();

// 基本的事件监听类列表

private ArrayList listeners = new ArrayList();

/**

* 创建一个默认的绘图对象

*/

public Draw() {

init();

}

/**

* 创建一个指定标题的绘图对象

*

* @param name 绘图窗口标题

*/

public Draw(String name) {

this.name = name;

init();

}

/*

* 框架、面板、画布等初始化

*/

private void init() {

if (frame != null) frame.setVisible(false);

frame = new JFrame();

offscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

onscreenImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

offscreen = offscreenImage.createGraphics();

onscreen = onscreenImage.createGraphics();

setXscale();

setYscale();

offscreen.setColor(DEFAULT_CLEAR_COLOR);

offscreen.fillRect(0, 0, width, height);

setPenColor();

setPenRadius();

setFont();

clear();

// 抗锯齿处理

RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);

offscreen.addRenderingHints(hints);

// 填充框架

ImageIcon icon = new ImageIcon(onscreenImage);

JLabel draw = new JLabel(icon);

draw.addMouseListener(this);

draw.addMouseMotionListener(this);

frame.setContentPane(draw);

frame.addKeyListener(this);

frame.setResizable(false);

// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

frame.setTitle(name);

frame.setJMenuBar(createMenuBar());

frame.pack();

frame.requestFocusInWindow();

frame.setVisible(true);

}

/**

* 设置绘图窗口在屏幕的位置,窗口左上角为参考点,以屏幕左上角为基准。默认的为(0,0)

*

* @param x 距离屏幕左侧的像素

* @param y 距离屏幕上侧的像素

* @throws 运行时异常,参数为负时产生

*/

public void setLocation(int x, int y) {

frame.setLocation(x, y);

}

/**

* 设置绘图窗口的大小

*

* @param w 窗口的宽度

* @param h 窗口的高度

* @throws 行时异常,参数为负或者为0时产生

*/

public void setCanvasSize(int w, int h) {

if (w < 1 || h < 1) throw new RuntimeException("宽度和高度必须为正数!");

width = w;

height = h;

init();

}

/**

* 为面板设置菜单栏

* @param menuBar 菜单栏

*/

public void setJMenuBar(JMenuBar menuBar){

if(menuBar == null)

frame.setJMenuBar(createMenuBar());

frame.setJMenuBar(menuBar);

init();

}

// 创建菜单栏

private JMenuBar createMenuBar() {

JMenuBar menuBar = new JMenuBar();

JMenu menu = new JMenu("文件");

menuBar.add(menu);

JMenuItem menuItem1 = new JMenuItem(" 保存为... ");

menuItem1.addActionListener(this);

menuItem1.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,

Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));

menu.add(menuItem1);

return menuBar;

}

/*

* 屏幕画布等坐标参数设置

*/

/**

* 将x坐标比例尺设置为默认(0.0~1.0)

*/

public void setXscale() { setXscale(DEFAULT_XMIN, DEFAULT_XMAX); }

/**

* 将y坐标比例尺设置为默认(0.0~1.0)

*/

public void setYscale() { setYscale(DEFAULT_YMIN, DEFAULT_YMAX); }

/**

* 设置画布x坐标比例尺,系统默认的画布带有10%的边界区域

* @param min x坐标的最小值

* @param max x坐标的最大值

*/

public void setXscale(double min, double max) {

double size = max - min;

xmin = min - BORDER * size;

xmax = max + BORDER * size;

}

/**

* 设置画布y坐标比例尺,系统默认的画布带有10%的边界区域

* @param min y坐标的最小值

* @param max y坐标的最大值

*/

public void setYscale(double min, double max) {

double size = max - min;

ymin = min - BORDER * size;

ymax = max + BORDER * size;

}

// 有关坐标参数的帮助函数

private double scaleX(double x) { return width * (x - xmin) / (xmax - xmin); }

private double scaleY(double y) { return height * (ymax - y) / (ymax - ymin); }

private double factorX(double w) { return w * width / Math.abs(xmax - xmin); }

private double factorY(double h) { return h * height / Math.abs(ymax - ymin); }

private double userX(double x) { return xmin + x * (xmax - xmin) / width; }

private double userY(double y) { return ymax - y * (ymax - ymin) / height; }

/**

* 将画布内容清除,画布背景色设置为默认白色

*/

public void clear() { clear(DEFAULT_CLEAR_COLOR); }

/**

* 将画布内容清除,画布背景色设置为指定颜色

* @param color 指定的画布背景色

*/

public void clear(Color color) {

offscreen.setColor(color);

offscreen.fillRect(0, 0, width, height);

offscreen.setColor(penColor);

draw();

}

/**

* 获取当前画笔半径

*/

public double getPenRadius() { return penRadius; }

/**

* 设置画笔半径为默认值 (.002)

*/

public void setPenRadius() { setPenRadius(DEFAULT_PEN_RADIUS); }

/**

* 设置画笔半径为指定的值

* @param r 待设置的画笔半径值

* @throws RuntimeException 运行时异常,参数为负时

*/

public void setPenRadius(double r) {

if (r < 0) throw new RuntimeException("画笔半径必须为正数!");

penRadius = r * DEFAULT_SIZE;

BasicStroke stroke = new BasicStroke((float) penRadius, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);

offscreen.setStroke(stroke);

}

/**

* 获取当前画笔颜色

*/

public Color getPenColor() { return penColor; }

/**

* 设置画笔颜色为默认颜色 黑色

*/

public void setPenColor() { setPenColor(DEFAULT_PEN_COLOR); }

/**

* 设置画笔颜色为指定颜色

* @param color 指定的画笔颜色

*/

public void setPenColor(Color color) {

penColor = color;

offscreen.setColor(penColor);

}

public void xorOn() { offscreen.setXORMode(DEFAULT_CLEAR_COLOR); }

public void xorOff() { offscreen.setPaintMode(); }

/**

* 获取当前字体

*/

public Font getFont() { return font; }

/**

* 设置当前字体为默认(sans serif, 16 px).

*/

public void setFont() { setFont(DEFAULT_FONT); }

/**

* 设置当前字体为指定字体

* @param f 指定的字体

*/

public void setFont(Font f) { font = f; }

/*

* 几何图形绘制

*/

/**

* 由指定的起点坐标(x0, y0) 和终点坐标 (x1, y1) 绘制一条直线

* @param x0 起点的横坐标

* @param y0 起点的纵坐标

* @param x1 终点的横坐标

* @param y1 终点的纵坐标

*/

public void line(double x0, double y0, double x1, double y1) {

offscreen.draw(new Line2D.Double(scaleX(x0), scaleY(y0), scaleX(x1), scaleY(y1)));

draw();

}

/**

* 由指定的坐标(x, y)绘制一个像素

* @param x 点的横坐标

* @param y 点的纵坐标

*/

private void pixel(double x, double y) {

offscreen.fillRect((int) Math.round(scaleX(x)), (int) Math.round(scaleY(y)), 1, 1);

}

/**

* 由指定的坐标(x, y)绘制一个点

* @param x 点的横坐标

* @param y 点的纵坐标

*/

public void point(double x, double y) {

double xs = scaleX(x);

double ys = scaleY(y);

double r = penRadius;

if (r <= 1) pixel(x, y);

else offscreen.fill(new Ellipse2D.Double(xs - r/2, ys - r/2, r, r));

draw();

}

/**

* 绘制一个以(x, y)为圆心。r为半径的圆环

* @param x 圆心横坐标

* @param y 圆心纵坐标

* @param r 圆的半径

* @throws RuntimeException 指定的圆心或者半径参数为负

*/

public void circle(double x, double y, double r) {

if (r < 0) throw new RuntimeException("圆的半径不能为负数!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*r);

double hs = factorY(2*r);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一个以(x, y)为圆心。r为半径的圆面

* @param x 圆心横坐标

* @param y 圆心纵坐标

* @param r 圆的半径

* @throws RuntimeException 指定的圆心或者半径参数为负

*/

public void filledCircle(double x, double y, double r) {

if (r < 0) throw new RuntimeException("circle radius can't be negative");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*r);

double hs = factorY(2*r);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一个指定长半轴和短半轴并以(x,y)为椭圆圆心的椭圆环

* @param x 圆心横坐标

* @param y 圆心纵坐标

* @param 椭圆长半轴大小

* @param 椭圆短半轴大小

* @throws RuntimeException 参数指定错误,半轴长为负值

*/

public void ellipse(double x, double y, double semiMajorAxis, double semiMinorAxis) {

if (semiMajorAxis < 0) throw new RuntimeException("椭圆半轴长为负值!");

if (semiMinorAxis < 0) throw new RuntimeException("椭圆半轴长为负值!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*semiMajorAxis);

double hs = factorY(2*semiMinorAxis);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.draw(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一个指定长半轴和短半轴并以(x,y)为椭圆圆心的椭圆面

* @param x 圆心横坐标

* @param y 圆心纵坐标

* @param 椭圆长半轴大小

* @param 椭圆短半轴大小

* @throws RuntimeException 参数指定错误,半轴长为负值

*/

public void filledEllipse(double x, double y, double semiMajorAxis, double semiMinorAxis) {

if (semiMajorAxis < 0) throw new RuntimeException("椭圆半轴长为负值!");

if (semiMinorAxis < 0) throw new RuntimeException("椭圆半轴长为负值!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*semiMajorAxis);

double hs = factorY(2*semiMinorAxis);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.fill(new Ellipse2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一段圆弧,该弧形半径为r,以(x,y)为弧形弧心,起始角度为 angle1 终止角度为 angle2

* @param x 圆弧中心横坐标

* @param y 圆弧中心纵坐标

* @param r 圆弧半径

* @param 圆弧起始角度,0为水平

* @param 圆弧终止角度,90为竖直

* @throws RuntimeException 半径为负值时产生

*/

public void arc(double x, double y, double r, double angle1, double angle2) {

if (r < 0) throw new RuntimeException("圆弧半径不能为负!");

while (angle2 < angle1) angle2 += 360;

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*r);

double hs = factorY(2*r);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.draw(new Arc2D.Double(xs - ws/2, ys - hs/2, ws, hs, angle1, angle2 - angle1, Arc2D.OPEN));

draw();

}

/**

* 绘制一个以(x,y)为中心,边长为2r的正方形

* @param x 正方形中心的横坐标

* @param y 正方形中心的纵坐标

* @param r 正方形的半长

* @throws RuntimeException 半径为负值

*/

public void square(double x, double y, double r) {

if (r < 0) throw new RuntimeException("正方形边长不能为负!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*r);

double hs = factorY(2*r);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一个以(x,y)为中心,边长为2r的正方形,并予以填充

* @param x 正方形中心的横坐标

* @param y 正方形中心的纵坐标

* @param r 正方形的半长

* @throws RuntimeException 半径为负值

*/

public void filledSquare(double x, double y, double r) {

if (r < 0) throw new RuntimeException("正方形边长不能为负!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*r);

double hs = factorY(2*r);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一个以(x,y)为中心,宽为2*halfWidth,高为2*halfHeight的长方形

* @param x 长方形中心的横坐标

* @param y 长方形中心的纵坐标

* @param halfWidth 长方形的半宽

* @param halfHeight 长方形的半高

* @throws RuntimeException 半高或者半宽为负值

*/

public void rectangle(double x, double y, double halfWidth, double halfHeight) {

if (halfWidth < 0) throw new RuntimeException("宽度不能为负值!");

if (halfHeight < 0) throw new RuntimeException("高度不能为负值!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*halfWidth);

double hs = factorY(2*halfHeight);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 绘制一个以(x,y)为中心,宽为2*halfWidth,高为2*halfHeight的长方形,并予以填充

* @param x 长方形中心的横坐标

* @param y 长方形中心的纵坐标

* @param halfWidth 长方形的半宽

* @param halfHeight 长方形的半高

* @throws RuntimeException 半高或者半宽为负值

*/

public void filledRectangle(double x, double y, double halfWidth, double halfHeight) {

if (halfWidth < 0) throw new RuntimeException("宽度不能为负值!");

if (halfHeight < 0) throw new RuntimeException("高度不能为负值!");

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(2*halfWidth);

double hs = factorY(2*halfHeight);

if (ws <= 1 && hs <= 1) pixel(x, y);

else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs));

draw();

}

/**

* 由指定的坐标参数 (x[i], y[i]) 绘制一个正多边形

* @param x 正多边形的所有横坐标

* @param y 正多边形的所有纵坐标

*/

public void polygon(double[] x, double[] y) {

int N = x.length;

GeneralPath path = new GeneralPath();

path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));

for (int i = 0; i < N; i++)

path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));

path.closePath();

offscreen.draw(path);

draw();

}

/**

* 由指定的坐标参数 (x[i], y[i]) 绘制一个正多边形并予以填充

* @param x 正多边形的所有横坐标

* @param y 正多边形的所有纵坐标

*/

public void filledPolygon(double[] x, double[] y) {

int N = x.length;

GeneralPath path = new GeneralPath();

path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0]));

for (int i = 0; i < N; i++)

path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i]));

path.closePath();

offscreen.fill(path);

draw();

}

/*

* 绘制图像

*/

// 由指定文件获取图像

private Image getImage(String filename) {

// 读取文件

ImageIcon icon = new ImageIcon(filename);

// 尝试从URL中获取图像

if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {

try {

URL url = new URL(filename);

icon = new ImageIcon(url);

} catch (Exception e) { /* 非URL */ }

}

if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) {

URL url = Draw.class.getResource(filename);

if (url == null) throw new RuntimeException("图像 " + filename + " 未找到");

icon = new ImageIcon(url);

}

return icon.getImage();

}

/**

* 绘制一幅以(x, y)为中心的图片,格式为(gif, jpg, or png)

* @param x 图片中心横坐标

* @param y 图片中心纵坐标

* @param s 图片名称

* @throws RuntimeException 图片文件损坏

*/

public void picture(double x, double y, String s) {

Image image = getImage(s);

double xs = scaleX(x);

double ys = scaleY(y);

int ws = image.getWidth(null);

int hs = image.getHeight(null);

if (ws < 0 || hs < 0) throw new RuntimeException("图片 " + s + " 损坏!");

offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);

draw();

}

/**

* 绘制一幅以(x, y)为中心的图片,逆时针旋转角度为degrees ,格式为(gif, jpg, or png)

* @param x 图片中心横坐标

* @param y 图片中心纵坐标

* @param s 图片名称

* @param degrees 逆时针旋转角度

* @throws RuntimeException 图片文件损坏

*/

public void picture(double x, double y, String s, double degrees) {

Image image = getImage(s);

double xs = scaleX(x);

double ys = scaleY(y);

int ws = image.getWidth(null);

int hs = image.getHeight(null);

if (ws < 0 || hs < 0) throw new RuntimeException("图片 " + s + " 损坏!");

offscreen.rotate(Math.toRadians(-degrees), xs, ys);

offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null);

offscreen.rotate(Math.toRadians(+degrees), xs, ys);

draw();

}

/**

* 绘制一幅以(x, y)为中心的图片(gif, jpg, or png),并且指定图片的宽度和高度

* @param x 图片中心横坐标

* @param y 图片中心纵坐标

* @param s 图片名称

* @param w 图片宽度

* @param h 图片高度

* @throws RuntimeException 图片文件损坏

*/

public void picture(double x, double y, String s, double w, double h) {

Image image = getImage(s);

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(w);

double hs = factorY(h);

if (ws < 0 || hs < 0) throw new RuntimeException("文件" + s + " 损坏!");

if (ws <= 1 && hs <= 1) pixel(x, y);

else {

offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),

(int) Math.round(ys - hs/2.0),

(int) Math.round(ws),

(int) Math.round(hs), null);

}

draw();

}

/**

* 制一幅以(x, y)为中心的图片(gif, jpg, or png),并且指定图片的宽度和高度以及逆时针旋转的角度

* given number of degrees, rescaled to w-by-h.

* @param x 图片中心横坐标

* @param y 图片中心纵坐标

* @param s 图片名称

* @param w 图片宽度

* @param h 图片高度

* @param degrees 逆时针旋转角度

* @throws RuntimeException 图片文件损坏

*/

public void picture(double x, double y, String s, double w, double h, double degrees) {

Image image = getImage(s);

double xs = scaleX(x);

double ys = scaleY(y);

double ws = factorX(w);

double hs = factorY(h);

if (ws < 0 || hs < 0) throw new RuntimeException("图片 " + s + " 损坏!");

if (ws <= 1 && hs <= 1) pixel(x, y);

offscreen.rotate(Math.toRadians(-degrees), xs, ys);

offscreen.drawImage(image, (int) Math.round(xs - ws/2.0),

(int) Math.round(ys - hs/2.0),

(int) Math.round(ws),

(int) Math.round(hs), null);

offscreen.rotate(Math.toRadians(+degrees), xs, ys);

draw();

}

/*

* 绘制文本

*/

/**

* 在画布上绘制一个以(x,y)为中心的指定的字符串

* @param x 文本中心的横坐标

* @param y 文本中心的纵坐标

* @param s 文本内容

*/

public void text(double x, double y, String s) {

offscreen.setFont(font);

FontMetrics metrics = offscreen.getFontMetrics();

double xs = scaleX(x);

double ys = scaleY(y);

int ws = metrics.stringWidth(s);

int hs = metrics.getDescent();

offscreen.drawString(s, (float) (xs - ws/2.0), (float) (ys + hs));

draw();

}

/**

* 在画布上绘制一个以(x,y)为中心的并且指定旋转角度的字符串

* @param x 文本中心的横坐标

* @param y 文本中心的纵坐标

* @param s 文本内容

* @param degrees 文本逆时针旋转的角度

*/

public void text(double x, double y, String s, double degrees) {

double xs = scaleX(x);

double ys = scaleY(y);

offscreen.rotate(Math.toRadians(-degrees), xs, ys);

text(x, y, s);

offscreen.rotate(Math.toRadians(+degrees), xs, ys);

}

/**

* 以当前字体绘制一串文本并且以(x, y)左对齐

* @param x 文本横坐标

* @param y 文本纵坐标

* @param s 文本内容

*/

public void textLeft(double x, double y, String s) {

offscreen.setFont(font);

FontMetrics metrics = offscreen.getFontMetrics();

double xs = scaleX(x);

double ys = scaleY(y);

int hs = metrics.getDescent();

offscreen.drawString(s, (float) (xs), (float) (ys + hs));

show();

}

/**

* 显示屏幕内容,并且暂停t毫秒。通过此方法可以将绘图模式转为动画模式(清空屏幕,绘制图形,在屏幕上显示指定的时间,重复)

* @param t 屏幕显示的毫秒数

*/

public void show(int t) {

defer = false;

draw();

try { Thread.sleep(t); }

catch (InterruptedException e) { System.out.println("休眠错误!"); }

defer = true;

}

/**

* 显示屏幕内容,关闭动画模式,这是默认的显示方式

*/

public void show() {

defer = false;

draw();

}

private void draw() {

if (defer) return;

onscreen.drawImage(offscreenImage, 0, 0, null);

frame.repaint();

}

/*

* 将画布上的图像保存到文件中

*/

/**

* 保存到指定的位置,文件格式必须为( png, jpg, gif)中的一种

* @param filename 文件全名,需要指定格式

*/

public void save(String filename) {

File file = new File(filename);

String suffix = filename.substring(filename.lastIndexOf('.') + 1);

// png

if (suffix.toLowerCase().equals("png")) {

try { ImageIO.write(offscreenImage, suffix, file); }

catch (IOException e) { e.printStackTrace(); }

}

// jpg

else if (suffix.toLowerCase().equals("jpg")) {

WritableRaster raster = offscreenImage.getRaster();

WritableRaster newRaster;

newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2});

DirectColorModel cm = (DirectColorModel) offscreenImage.getColorModel();

DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),

cm.getRedMask(),

cm.getGreenMask(),

cm.getBlueMask());

BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);

try { ImageIO.write(rgbBuffer, suffix, file); }

catch (IOException e) { e.printStackTrace(); }

}

else {

System.out.println("不合法的文件格式: " + suffix);

}

}

/**

* 此方法用于处理事件,不能被直接调用

*/

public void actionPerformed(ActionEvent e) {

FileDialog chooser = new FileDialog(frame, "使用 .png 或者 .jpg 扩展名", FileDialog.SAVE);

chooser.setVisible(true);

String filename = chooser.getFile();

if (filename != null) {

save(chooser.getDirectory() + File.separator + chooser.getFile());

}

}

/*

* 基于事件的交互处理

*/

/**

* 为框架添加监听器

* @param listener 绘图监听器

*/

public void addListener(DrawListener listener) {

// 确保有窗口存在

show();

listeners.add(listener);

frame.addKeyListener(this);

frame.addMouseListener(this);

frame.addMouseMotionListener(this);

frame.setFocusable(true);

}

/*

* 鼠标系列事件

*/

/**

* 鼠标按键

* @return true 或者 false

*/

public boolean mousePressed() {

synchronized (mouseLock) {

return mousePressed;

}

}

/**

* 获取鼠标的横坐标

* @return 鼠标的横坐标

*/

public double mouseX() {

synchronized (mouseLock) {

return mouseX;

}

}

/**

* 获取鼠标的纵坐标

* @return 鼠标的纵坐标

*/

public double mouseY() {

synchronized (mouseLock) {

return mouseY;

}

}

/**

* 此方法不能被用户直接调用

*/

public void mouseClicked(MouseEvent e) { }

/**

* 此方法不能被用户直接调用

*/

public void mouseEntered(MouseEvent e) { }

/**

* 此方法不能被用户直接调用

*/

public void mouseExited(MouseEvent e) { }

/**

* 鼠标按键事件(按下)处理,此方法不能被用户直接调用

*/

public void mousePressed(MouseEvent e) {

synchronized (mouseLock) {

mouseX = userX(e.getX());

mouseY = userY(e.getY());

mousePressed = true;

}

if (e.getButton() == MouseEvent.BUTTON1) {

for (DrawListener listener : listeners)

listener.mousePressed(userX(e.getX()), userY(e.getY()));

}

}

/**

* 鼠标按键事件(松开)处理,此方法不能被用户直接调用

*/

public void mouseReleased(MouseEvent e) {

synchronized (mouseLock) {

mousePressed = false;

}

if (e.getButton() == MouseEvent.BUTTON1) {

for (DrawListener listener : listeners)

listener.mouseReleased(userX(e.getX()), userY(e.getY()));

}

}

/**

* 鼠标按键事件(鼠标拖动)处理,此方法不能被用户直接调用

*/

public void mouseDragged(MouseEvent e) {

synchronized (mouseLock) {

mouseX = userX(e.getX());

mouseY = userY(e.getY());

}

for (DrawListener listener : listeners)

listener.mouseDragged(userX(e.getX()), userY(e.getY()));

}

/**

* 鼠标按键事件(鼠标移动)处理,此方法不能被用户直接调用

*/

public void mouseMoved(MouseEvent e) {

synchronized (mouseLock) {

mouseX = userX(e.getX());

mouseY = userY(e.getY());

}

}

/*

* 键盘系列事件

*/

/**

* 确认用户是否按下一个按键

* @return true 按下, false 未按下

*/

public boolean hasNextKeyTyped() {

synchronized (keyLock) {

return !keysTyped.isEmpty();

}

}

/**

* 获取用户按键

* @return 下一个用户按键字符

*/

public char nextKeyTyped() {

synchronized (keyLock) {

return keysTyped.removeLast();

}

}

/**

* 确认指定键码的按键是否被按下,此方法可以处理方向键、功能键、以及修饰按键

* @return true 如果指定按键被按下, false 指定按键未被按下

*/

public boolean isKeyPressed(int keycode) {

synchronized (keyLock) {

return keysDown.contains(keycode);

}

}

/**

* 此方法不能被用户直接调用

*/

public void keyTyped(KeyEvent e) {

synchronized (keyLock) {

keysTyped.addFirst(e.getKeyChar());

}

// 唤醒所有监听者

for (DrawListener listener : listeners)

listener.keyTyped(e.getKeyChar());

}

/**

* 键盘事件(按下)处理,此方法不能被用户直接调用

*/

public void keyPressed(KeyEvent e) {

synchronized (keyLock) {

keysDown.add(e.getKeyCode());

}

}

/**

* 键盘事件(松开)处理,此方法不能被用户直接调用

*/

public void keyReleased(KeyEvent e) {

synchronized (keyLock) {

keysDown.remove(e.getKeyCode());

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值