弄了一天,基本实现了一般绘图软件的绘制矩形选择框的功能。
一共两个类:
PointRectangle
扩展了AWT的Rectangle类,按左上角和右下角两个坐标点来定义矩形(AWT默认是按左上角坐标和长宽来定义矩形的)。
SelectableCanvas
扩展了AWT的Canvas,用来充当画板。
考虑到可能有底图存在,这里没用到Double Buffering,每次画图前先按像素级精确擦除前一祯绘制的矩形的手柄,实际效果很理想,基本看不到闪烁。
package com.fancy.picture.test; import java.awt.Rectangle; public class PointRectangle extends Rectangle { private static final long serialVersionUID = -2465363144347743255L; int x1, x2, y1, y2; public PointRectangle(int x1, int y1, int x2, int y2) { this.x1 = x = x1; this.x2 = x2; this.y1 = y = y1; this.y2 = y2; width = x2 - x1; height = y2 - y1; if (x2 < x1) { x = x2; width = x1 - x2; } if (y2 < y1) { y = y2; height = y1 - y2; } } public PointRectangle(Rectangle rectangle) { super(rectangle.x, rectangle.y, rectangle.width, rectangle.height); this.x1 = rectangle.x; this.y1 = rectangle.y; this.x2 = rectangle.x + rectangle.width; this.y2 = rectangle.y + rectangle.height; } } package com.fancy.picture.test; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Canvas; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.geom.Area; public class SelectableCanvas extends Canvas { private static final long serialVersionUID = -7159915510292362753L; boolean selecting;// 是否正在拖拽矩形 int x, y;// 矩形原点坐标 PointRectangle selection;// 当前绘制的矩形 int activeHandle = -1;// 激活的Resize手柄 Rectangle[] handles = new Rectangle[8];// 8个Resize手柄 public SelectableCanvas() { addMouseListener(new MouseAdapter() { @Override public void mouseReleased(MouseEvent e) { if (selecting || activeHandle >= 0) { wipeSelection(); confirmSelection(selection); selecting = false; activeHandle = -1; setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } @Override public void mousePressed(MouseEvent e) { x = e.getX(); y = e.getY(); } }); addMouseMotionListener(new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { for (int i = 0; i < handles.length; i++) { if (handles[i] != null && handles[i].contains(e.getX(), e.getY())) { activeHandle = i; switch (i) { case 0: case 4: setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR)); break; case 1: case 5: setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR)); break; case 2: case 6: setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR)); break; case 3: case 7: setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)); break; } return; } } activeHandle = -1; setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } public void mouseDragged(MouseEvent e) { if (selection != null) wipeSelection(); if (activeHandle >= 0) { switch (activeHandle) { case 0: selection = new PointRectangle(e.getX(), e.getY(), selection.x2, selection.y2); break; case 1: selection = new PointRectangle(selection.x1, e.getY(), selection.x2, selection.y2); break; case 2: selection = new PointRectangle(selection.x1, e.getY(), e.getX(), selection.y2); break; case 3: selection = new PointRectangle(selection.x1, selection.y1, e.getX(), selection.y2); break; case 4: selection = new PointRectangle(selection.x1, selection.y1, e.getX(), e.getY()); break; case 5: selection = new PointRectangle(selection.x1, selection.y1, selection.x2, e.getY()); break; case 6: selection = new PointRectangle(e.getX(), selection.y1, selection.x2, e.getY()); break; case 7: selection = new PointRectangle(e.getX(), selection.y1, selection.x2, selection.y2); break; } drawSelection(selection); } else { selection = new PointRectangle(x, y, e.getX(), e.getY()); drawSelection(selection); selecting = true; setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } } }); } // 清除选择的矩形 public void clearSelection() { selection = null; selecting = false; activeHandle = -1; for (int i = 0; i < handles.length; i++) handles[i] = null; } // 清除上次的绘制的矩形 private void wipeSelection() { Graphics2D graphics = (Graphics2D) getGraphics().create();// 初始化绘图上下文 // 定义擦除区域 Area area = new Area(new Rectangle(selection.x, selection.y, selection.width + 1, selection.height + 1)); area.subtract(new Area(new Rectangle(selection.x + 1, selection.y + 1, selection.width - 1, selection.height - 1))); area.add(new Area(new Rectangle(selection.x - 2, selection.y - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x + selection.width / 2 - 2, selection.y - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x + selection.width - 2, selection.y - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x + selection.width - 2, selection.y + selection.height / 2 - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x + selection.width - 2, selection.y + selection.height - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x + selection.width / 2 - 2, selection.y + selection.height - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x - 2, selection.y + selection.height - 2, 5, 5))); area.add(new Area(new Rectangle(selection.x - 2, selection.y + selection.height / 2 - 2, 5, 5))); graphics.setClip(area);// 应用擦除区域 update(graphics);// 用背景擦除 } //画虚线矩形 private void drawSelection(Rectangle selection) { Graphics2D graphics = (Graphics2D) getGraphics().create();// 初始化绘图上下文 graphics.setPaint(Color.WHITE);// 设置边框颜色 graphics.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1f, new float[] { 5 }, 0));// 设置边框笔触 graphics.draw(selection);// 绘制选择边框 } //画带手柄的矩形 private void confirmSelection(Rectangle selection) { this.selection = new PointRectangle(selection); Graphics2D graphics = (Graphics2D) getGraphics();// 绘图上下文 if (selection.isEmpty()) { clearSelection(); return; } graphics.setStroke(new BasicStroke(1));// 设置选择框底色笔触 graphics.setPaint(Color.BLUE);// 设置边框底色颜色 graphics.draw(selection);// 绘制选择边框底色 graphics.setPaint(Color.WHITE);// 设置边框颜色 graphics.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1f, new float[] { 5 }, 0));// 设置边框笔触 graphics.draw(selection);// 绘制选择边框 // 定义手柄 handles[0] = new Rectangle(selection.x - 2, selection.y - 2, 4, 4); handles[1] = new Rectangle(selection.x + selection.width / 2 - 2, selection.y - 2, 4, 4); handles[2] = new Rectangle(selection.x + selection.width - 2, selection.y - 2, 4, 4); handles[3] = new Rectangle(selection.x + selection.width - 2, selection.y + selection.height / 2 - 2, 4, 4); handles[4] = new Rectangle(selection.x + selection.width - 2, selection.y + selection.height - 2, 4, 4); handles[5] = new Rectangle(selection.x + selection.width / 2 - 2, selection.y + selection.height - 2, 4, 4); handles[6] = new Rectangle(selection.x - 2, selection.y + selection.height - 2, 4, 4); handles[7] = new Rectangle(selection.x - 2, selection.y + selection.height / 2 - 2, 4, 4); graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));// 设置填充不透明 graphics.setPaint(Color.WHITE);// 设置手柄填充颜色 // 填充手柄 for (Rectangle handle : handles) graphics.fill(handle); graphics.setPaint(Color.BLACK);// 设置手柄边框颜色 graphics.setStroke(new BasicStroke(1f));// 设置实线笔触 // 绘制手柄边框 for (Rectangle handle : handles) graphics.draw(handle); } //返回当前有效的矩形 public Rectangle getSelection() { return selection; } }
更多精彩原创文章请关注笔者的原创博客:http://www.coolfancy.com