1.创建一个窗体JFrame
1.1创建一个画图板的面板类DrawBoard1
1.2创建窗体方法,用来实现窗体化
/***************************窗体函数*******************************************/
public void setFrameParams(){
//设置窗体
jfDrawFrame = new JFrame("小安画图板");
jfDrawFrame.setSize(600, 400);//窗体大小
jfDrawFrame.setLocationRelativeTo(null);//窗体位置
//设置窗体默认关闭操作
jfDrawFrame.setDefaultCloseOperation(3);
//设置流式布局
jfDrawFrame.setLayout(new BorderLayout());
}
1.3创建构造方法,调用其他面板类
2.创建左边面板PanelLeft
2.1创建PanelLeft类,继承JPanel类
2.2根据左边面板图片添加按钮jbutton
// 添加jbutton 添加图片
String a[]={"star","dot_rect","eraser","fill",
"color_picker","magnifier","pencil","brush",
"airbrush","word","line","curve","rect",
"polygon","oval","round_rect"};
for(int i=0;i<16;i++){
ImageIcon imageIcon = new ImageIcon("images/"+a[i]+".jpg");
JButton btnIcon = new JButton(imageIcon);
//设置按键的大小
Dimension preferredSize = new Dimension(24,24);
btnIcon.setPreferredSize(preferredSize);
this.add(btnIcon);//把按键添加到面板
// 2.给按钮添加监听
btnIcon.addActionListener(actionListener);//
// 3.给触发按钮设置一个命令
btnIcon.setActionCommand(a[i]);//
}
2.3给按钮添加监听
3.创建中间面板PanelCenter
3.1给中间面板添加监听器
画笔Graphics2D
a.在按下监听获取他们的起始坐标
public void mousePressed(MouseEvent e) {
System.out.println("按下了");
//获取起始坐标
xStart=e.getX();
yStart=e.getY();
}
b.在释放监听获取他们的终点坐标
直线、椭圆、矩形、圆角矩形、多边形(多边形第一条线是在释放的时候完成的,后面的要在点击事件中完成)都是在释放监听下完成的
public void mouseReleased(MouseEvent e) {
System.out.println("释放了");
//获取终点坐标
xEnd=e.getX();
yEnd=e.getY();
//画
if ("line".equals(p.currentCommon)) // 区分 直线 还是椭圆??? 通过命令区分
{
// 当前是画直线
graphics.drawLine(xStart, yStart, xEnd, yEnd);
} else if ("oval".equals(p.currentCommon)) {
//当前画椭圆
// 反着画 : xStart>xEnd width<0
// x较小的 y较小的 :绝对值:xEnd - xStart
graphics.drawOval(Math.min(xStart,xEnd),Math.min(yStart,yEnd), Math.abs(xEnd - xStart),Math.abs(yEnd- yStart));
}else if("rect".equals(p.currentCommon)){
//当前画矩形
graphics.drawRect(Math.min(xStart,xEnd),Math.min(yStart,yEnd), Math.abs(xEnd - xStart),Math.abs(yEnd- yStart));
}else if("round_rect".equals(p.currentCommon)){
//当前画圆角矩形
graphics.drawRoundRect(Math.min(xStart,xEnd), Math.min(yStart,yEnd), Math.abs(xEnd - xStart), Math.abs(yEnd- yStart), 10, 10);
}else if("polygon".equals(p.currentCommon)){
//当前画多边形
if(p.exeCount==0){
//记录当前首条直线起始点
recordxStart=xStart;
recordyStart=yStart;
//记录当前首条直线终点
recordxEnd=xEnd;
recordyEnd=yEnd;
graphics.drawLine(xStart, yStart, xEnd, yEnd);
p.exeCount++;
}
}
}
c.尤其注意多边形,在释放监听时,它需要记录起始坐标和终点坐标,利用exeCount来判断释放和点击;在点击中,每单击一次就获取当前点击左边并且都要替换记录
终点坐标,双击时首尾相连,把exeCount初始化
public void mouseClicked(MouseEvent e) {
int xClick=e.getX();
int yClick=e.getY();
System.out.println("点击了");
int clickCount = e.getClickCount();
if("polygon".equals(p.currentCommon)){
if(clickCount==1)
{
//当前坐标与记录终点坐标相连
graphics.drawLine(recordxEnd,recordyEnd,xClick, yClick);
recordxEnd=xClick;
recordyEnd=yClick;
}
else if(clickCount==2)
{
//首位相连
graphics.drawLine(recordxEnd,recordyEnd,xClick, yClick);
graphics.drawLine(recordxStart,recordyStart,xClick, yClick);
p.exeCount=0;
}
}
}
3.2添加鼠标拖动监听器
铅笔、喷枪、橡皮擦、刷子都是在拖动监听下实现的
//添加鼠标拖动监听器
MouseMotionListener mouseMotionListener=new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
System.out.println("拖动了");
x1=e.getX();
y1=e.getY();
if("pencil".equals(p.currentCommon)){
//铅笔
graphics.drawLine(xStart, yStart, x1, y1);
xStart=x1;
yStart=y1;
}else if("airbrush".equals(p.currentCommon)){
//喷枪
for (int i = 0; i < 120; i++) {
// 生成的随机数
random=new Random();
int nextInt = random.nextInt(8) - 4;
int nextInt2 = random.nextInt(8) - 4;
System.out.println(nextInt);
graphics.drawLine(x1 + nextInt, y1 + nextInt2, x1+ nextInt, y1 + nextInt2);// 画点
}
} else if("eraser".equals(p.currentCommon)) {
//橡皮擦
BasicStroke basicStock2=new BasicStroke(30);
graphics.setStroke(basicStock2);
graphics.setColor(Color.white);
graphics.drawLine(xStart, yStart,x1, y1);
xStart=x1;
yStart=y1;
basicStock2=new BasicStroke();
graphics.setStroke(basicStock2);
}else if("brush".equals(p.currentCommon)) {
//刷子
BasicStroke basicStock1=new BasicStroke(10);
graphics.setStroke(basicStock1);
graphics.drawLine(xStart, yStart, x1, y1);
xStart=x1;
yStart=y1;
basicStock1=new BasicStroke();
graphics.setStroke(basicStock1);
}
}
@Override
public void mouseMoved(MouseEvent e) {
}
};
4.底部面板PanelBottom
4.1为面添加颜色JButton
Color[] colors = { Color.red, Color.black, Color.blue, Color.yellow ,Color.white};
/** 面板上面添加默认颜色的Button **/
// 1 默认颜色的数组
for (int i = 0; i < colors.length; i++) {
// 2创建Button
JButton button = new JButton();
button.setBackground(colors[i]);
Dimension dd = new Dimension(25, 25);
button.setPreferredSize(dd);
button.addActionListener(listener);
button.setActionCommand(i + "");
// 3.添加
this.add(button);
}
4.2创建按钮的点击事件
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("颜色选择了~~");
String actionCommand = e.getActionCommand();
int i = Integer.valueOf(actionCommand);// String -> int
// :Integer整数
System.out.println("cwt"+i);
Color color = colors[i];
graphics.setColor(color);
p.currentColor = color;
if("eraser".equals(p.currentCommon)){
graphics.setColor(Color.white);
}
}
};
源代码:
package lza_Draw2;
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import javax.swing.JFrame;
public class DrawBoard1 {
JFrame jfDrawFrame;//定义画图板窗体的全局变量
public DrawBoard1() {
setFrameParams();
//左边面板
PanelLeft pLeft =new PanelLeft(null);
jfDrawFrame.add(pLeft, BorderLayout.WEST);//把面板添加到窗体里
//中间面板
PanelCenter pCenter =new PanelCenter(pLeft,null);
jfDrawFrame.add(pCenter, BorderLayout.CENTER);//把面板添加到窗体里
//底部面板
PanelBottom pBottom =new PanelBottom(pLeft,null);
jfDrawFrame.add(pBottom, BorderLayout.SOUTH);
jfDrawFrame.setAlwaysOnTop(true);
jfDrawFrame.setVisible(true);
// 必须在获得画笔:
Graphics2D graphics2 = (Graphics2D) pCenter.getGraphics();// 获得画笔
// TODO 要给左边面板的g赋值
pLeft.graphics = graphics2;
pCenter.graphics = graphics2;
pBottom.graphics = graphics2;
}
/***************************窗体函数*******************************************/
public void setFrameParams(){
//设置窗体
jfDrawFrame = new JFrame("小安画图板");
jfDrawFrame.setSize(600, 400);//窗体大小
jfDrawFrame.setLocationRelativeTo(null);//窗体位置
//设置窗体默认关闭操作
jfDrawFrame.setDefaultCloseOperation(3);
//设置流式布局
jfDrawFrame.setLayout(new BorderLayout());
}
}
package lza_Draw2;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class PanelLeft extends JPanel{
private static final long serialVersionUID = 1L;
public String currentCommon = "line";// 默认一开始就是直线
public Graphics2D graphics = null;// 画笔
public int exeCount;//用来判断画多边形时,拖动时的操作还是点击时的操作,当execount==0则执行拖动时的操作,不为0则跳出去
public Color currentColor =Color.black;//记录初始颜色
public PanelLeft(Graphics2D g){
graphics=g;
//设置左边面板容器
Dimension dSizie = new Dimension(70, 100); //Dimension 类封装单个对象中组件的宽度和高度(精确到整数)
this.setPreferredSize(dSizie);//设置此组件的首选大小。如果 preferredSize 为 null,则要求 UI 提供首选大小。
this.setBackground(Color.lightGray);//设置面板的背景颜色
// 添加jbutton 添加图片
String a[]={"star","dot_rect","eraser","fill",
"color_picker","magnifier","pencil","brush",
"airbrush","word","line","curve","rect",
"polygon","oval","round_rect"};
// 1.先要有监听器 :一个类implements ActionListener ;;
// 接口不能new,有一个普通类,没有类名-》匿名类 =>匿名内部类
ActionListener actionListener = new ActionListener() {
// 重写了接口的抽象方法
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("监听到了~~~");
// 区分是哪个按钮?
currentCommon = e.getActionCommand();// 获得当前触发按钮的命令
graphics.setColor(currentColor);
exeCount=0;
}
};
for(int i=0;i<16;i++){
ImageIcon imageIcon = new ImageIcon("images/"+a[i]+".jpg");
JButton btnIcon = new JButton(imageIcon);
//设置按键的大小
Dimension preferredSize = new Dimension(24,24);
btnIcon.setPreferredSize(preferredSize);
this.add(btnIcon);//把按键添加到面板
// 2.给按钮添加监听
btnIcon.addActionListener(actionListener);//
// 3.给触发按钮设置一个命令
btnIcon.setActionCommand(a[i]);//
}
}
}
package lza_Draw2;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Random;
import javax.swing.JPanel;
public class PanelCenter extends JPanel{
private static final long serialVersionUID = 1L;
public PanelLeft pleft;
public Graphics2D graphics;// 画笔
//定义全局坐标变量
public int xStart ;//X起始点
public int yStart ;//Y的起始点
public int xEnd ;//X的终点
public int yEnd ;//Y的终点
public int recordxStart;//记录起始点x的值
public int recordyStart;//记录起始点y的值
public int recordxEnd;//记录终点x的值
public int recordyEnd;//记录终点y的值
public int x1, y1;//拖动时的坐标
public Random random;//定义随机数类的全局对象
public PanelCenter(PanelLeft p,Graphics2D g){
pleft=p;
graphics=g;
//给中间面板添加监听器
MouseListener mouseListener = new MouseListener(){
@Override
public void mouseClicked(MouseEvent e) {
int xClick=e.getX();
int yClick=e.getY();
System.out.println("点击了");
int clickCount = e.getClickCount();
if("polygon".equals(p.currentCommon)){
if(clickCount==1)
{
//当前坐标与记录终点坐标相连
graphics.drawLine(recordxEnd,recordyEnd,xClick, yClick);
recordxEnd=xClick;
recordyEnd=yClick;
}
else if(clickCount==2)
{
//首位相连
graphics.drawLine(recordxEnd,recordyEnd,xClick, yClick);
graphics.drawLine(recordxStart,recordyStart,xClick, yClick);
p.exeCount=0;
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
System.out.println("进入了");
}
@Override
public void mouseExited(MouseEvent e) {
System.out.println("退出了");
}
@Override
public void mousePressed(MouseEvent e) {
System.out.println("按下了");
//获取起始坐标
xStart=e.getX();
yStart=e.getY();
}
@Override
public void mouseReleased(MouseEvent e) {
System.out.println("释放了");
//获取终点坐标
xEnd=e.getX();
yEnd=e.getY();
//画
if ("line".equals(p.currentCommon)) // 区分 直线 还是椭圆??? 通过命令区分
{
// 当前是画直线
graphics.drawLine(xStart, yStart, xEnd, yEnd);
} else if ("oval".equals(p.currentCommon)) {
//当前画椭圆
// 反着画 : xStart>xEnd width<0
// x较小的 y较小的 :绝对值:xEnd - xStart
graphics.drawOval(Math.min(xStart,xEnd),Math.min(yStart,yEnd), Math.abs(xEnd - xStart),Math.abs(yEnd- yStart));
}else if("rect".equals(p.currentCommon)){
//当前画矩形
graphics.drawRect(Math.min(xStart,xEnd),Math.min(yStart,yEnd), Math.abs(xEnd - xStart),Math.abs(yEnd- yStart));
}else if("round_rect".equals(p.currentCommon)){
//当前画圆角矩形
graphics.drawRoundRect(Math.min(xStart,xEnd), Math.min(yStart,yEnd), Math.abs(xEnd - xStart), Math.abs(yEnd- yStart), 10, 10);
}else if("polygon".equals(p.currentCommon)){
//当前画多边形
if(p.exeCount==0){
//记录当前首条直线起始点
recordxStart=xStart;
recordyStart=yStart;
//记录当前首条直线终点
recordxEnd=xEnd;
recordyEnd=yEnd;
graphics.drawLine(xStart, yStart, xEnd, yEnd);
p.exeCount++;
}
}
}
};
//添加鼠标拖动监听器
MouseMotionListener mouseMotionListener=new MouseMotionListener(){
@Override
public void mouseDragged(MouseEvent e) {
System.out.println("拖动了");
x1=e.getX();
y1=e.getY();
if("pencil".equals(p.currentCommon)){
//铅笔
graphics.drawLine(xStart, yStart, x1, y1);
xStart=x1;
yStart=y1;
}else if("airbrush".equals(p.currentCommon)){
//喷枪
for (int i = 0; i < 120; i++) {
// 生成的随机数
random=new Random();
int nextInt = random.nextInt(8) - 4;
int nextInt2 = random.nextInt(8) - 4;
System.out.println(nextInt);
graphics.drawLine(x1 + nextInt, y1 + nextInt2, x1+ nextInt, y1 + nextInt2);// 画点
}
} else if("eraser".equals(p.currentCommon)) {
//橡皮擦
BasicStroke basicStock2=new BasicStroke(30);
graphics.setStroke(basicStock2);
graphics.setColor(Color.white);
graphics.drawLine(xStart, yStart,x1, y1);
xStart=x1;
yStart=y1;
basicStock2=new BasicStroke();
graphics.setStroke(basicStock2);
}else if("brush".equals(p.currentCommon)) {
//刷子
BasicStroke basicStock1=new BasicStroke(10);
graphics.setStroke(basicStock1);
graphics.drawLine(xStart, yStart, x1, y1);
xStart=x1;
yStart=y1;
basicStock1=new BasicStroke();
graphics.setStroke(basicStock1);
}
}
@Override
public void mouseMoved(MouseEvent e) {
}
};
this.setBackground(Color.white);
// 2.给panel添加监听器
this.addMouseListener(mouseListener);
this.addMouseMotionListener(mouseMotionListener);
}
}
package lza_Draw2;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class PanelBottom extends JPanel{
private static final long serialVersionUID = 533562196214049835L;
public PanelLeft panelLeft;
public Graphics2D graphics;
// 1 默认颜色的数组
Color[] colors = { Color.red, Color.black, Color.blue, Color.yellow ,Color.white};
public PanelBottom(PanelLeft p,Graphics2D g){
panelLeft=p;
graphics=g;
Dimension d = new Dimension(100, 70);
this.setPreferredSize(d);
/** 创建按钮的点击事件 **/
ActionListener listener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("颜色选择了~~");
String actionCommand = e.getActionCommand();
int i = Integer.valueOf(actionCommand);// String -> int
// :Integer整数
System.out.println("cwt"+i);
Color color = colors[i];
graphics.setColor(color);
p.currentColor = color;
if("eraser".equals(p.currentCommon)){
graphics.setColor(Color.white);
}
}
};
/** 面板上面添加默认颜色的Button **/
// 1 默认颜色的数组
for (int i = 0; i < colors.length; i++) {
// 2创建Button
JButton button = new JButton();
button.setBackground(colors[i]);
Dimension dd = new Dimension(25, 25);
button.setPreferredSize(dd);
button.addActionListener(listener);
button.setActionCommand(i + "");
// 3.添加
this.add(button);
}
}
}
测试类:
package lza_Draw2;
public class Test {
public static void main(String[] args) {
DrawBoard1 drawBoard1 =new DrawBoard1 ();
}
}
为了解决放大窗体时,所画的东西不被清除掉利用队列(用泛化数组)来记录所画的东西。
package lza_Draw2;
import java.awt.Graphics2D;
public class Queue<T> {
private int size;
private Object []queue=new Object[size];
public int getSize(){
return size;
}
//添加
public void add(T element){
Object []queue_new=new Object[size+1];
for(int i=0;i<size;i++){
queue_new[i]=queue[i];
}
queue_new[size]=element;
queue=queue_new;
size++;
}
//删除
public void delete(int index){
Object []queue_new=new Object[size-1];
for(int i=0;i<index;i++){
queue_new[i]=queue[i];
}
for(int i=index;i<size-1;i++){
queue_new[i]=queue[i+1];
}
queue=queue_new;
size--;
}
//修改
public void update(int index,T element){
queue[index] =element ;
}
//插入
public void insert(int index,T element){
Object []queue_new=new Object[size+1];
for(int i=0;i<index;i++){
queue_new[i]=queue[i];
}
queue_new[index]=element;
for(int i=index;i<size;i++){
queue_new[i+1]=queue[i];
}
queue=queue_new;
size++;
}
//查询
public T inquire(int a){
return (T) queue[a];
}
}
创建一个重绘的一个抽象父类,构造方法记录它们的坐标和颜色、宽度,重绘图像的方法
package lza_Draw2;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
public abstract class Shape {
public int x1,y1,x2,y2;
public Color color;
public Stroke stroke;
public Shape(int x1,int y1,int x2,int y2,Color color,Stroke stroke){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
this.color=color;
this.stroke=stroke;
}
public abstract void drawShape(Graphics2D g);
}
在中间画板处创建重绘方法
public void paint(Graphics g) {
super.paint(g);
System.out.println("~");
for(int i=0;i<queue.getSize();i++){
queue.inquire(i).drawShape((Graphics2D)g);
}
}
创建直线、椭圆、矩形、圆角矩形的重绘子类,继承Shape列举直线的重绘代码,其他的都是大同小异:
package lza_Draw2;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Stroke;
public class LineShape extends Shape{
public LineShape(int x1, int y1, int x2, int y2, Color color, Stroke stroke) {
super(x1, y1, x2, y2, color, stroke);
}
@Override
public void drawShape(Graphics2D g) {
g.setColor(color);
g.setStroke(stroke);
g.drawLine(x1, y1, x2, y2);
}
}
在中间面板中分别在他们的画中添加如下代码即可以
queue.add(new OvalShape(x1,y1,x2,y2, graphics.getColor(), new BasicStroke(1)));
比如直线:
if ("line".equals(p.currentCommon)) // 区分 直线 还是椭圆??? 通过命令区分
{
// 当前是画直线
graphics.drawLine(xStart, yStart, xEnd, yEnd);
//TODO
LineShape line = new LineShape(xStart, yStart, xEnd, yEnd, graphics.getColor(), new BasicStroke(1));
queue.add(line);
}
其运行结果截图: