<一> 画图板的简介
画图板是一种很实用的画图工具。它的界面如下:
-------------------------------------------- 1 --------------------------------------------------------------------------------------------------------
<二> java语言实现它
画图板大致可以分为三个部分:左侧工具面板、中间面板和底部颜色面板。
在构架画图板时,就必须得构建一个窗体,3个面板。考虑到程序的可维护
性和职责分离,以及提高效率,在实现画图板时将其抽象为5个类。
在构建窗体和面板时,直接通过继承相应的类,如JFrame、JPanel。在
具体的类中,可以用 this.属性或方法 来替代直接new一个对象.属性或方法。
接下来,具体讲每个类的实现。
第一部分 DrawBoard.java 类
package cn.huaxin.ui2.layer;
import java.awt.BorderLayout;
import java.awt.Graphics2D;
import javax.swing.JFrame;
public class DrawBoard {
JFrame jfDrawFrame = null;// 全局变量
// ------------------------------------------------------------------------------
// 构造方法
public DrawBoard() {
/** 第一步:设置窗体属性:大小、位置、标题、可见(必须要最后(add后)设置)、释放 **/
setFrameParams();// 调用了自己的方法
/** 第二步: add 控件 **/
// 左边面板
PanelLeft panelLeft = new PanelLeft(null);
jfDrawFrame.add(panelLeft, BorderLayout.WEST);
// 中间面板
PanelCenter panelCenter = new PanelCenter(panelLeft, null);
jfDrawFrame.add(panelCenter, BorderLayout.CENTER);
// 设置底部的面板
PanelBottom panelBottom = new PanelBottom(panelLeft, null);
jfDrawFrame.add(panelBottom, BorderLayout.SOUTH);
/** 第三步: 事件 **/
jfDrawFrame.setAlwaysOnTop(true);
jfDrawFrame.setVisible(true);
// 必须在获得画笔:
Graphics2D graphics2 = (Graphics2D) panelCenter.getGraphics();// 获得画笔
// TODO 要给左边面板的g赋值
panelLeft.graphics = graphics2;
panelCenter.graphics = graphics2;
panelBottom.graphics = graphics2;
}
/** 第一步:设置窗体属性:大小、位置、标题、可见(必须要最后(add后)设置)、释放 **/
public void setFrameParams() {
jfDrawFrame = new JFrame();
jfDrawFrame.setSize(500, 500);
jfDrawFrame.setLocationRelativeTo(null);
jfDrawFrame.setTitle("画图板");
jfDrawFrame.setDefaultCloseOperation(3);
jfDrawFrame.setLayout(new BorderLayout());// 布局
// null 空布局直接:给x,y坐标(屏幕适配有问题,做桌面程序没什么影响)
}
}
在DrawBoard类中,分为属性和方法。构造函数中,主要是建立窗体和面板,以及获得画笔。大致分为三步:
(1)为窗体设置属性
(2)为窗体添加面板
(3)事件
在构建窗体时,一定要注意一个“先”和一个“后”。标准就是窗体的可见性。
先: 设置窗体其他属性要先于可见性(this.setVisible());
在窗体上添加面板要先于可见性(this.setVisible());
后: 获得画笔和为面板添加画笔要后于可见性(this.setVisible());
画笔
Graphics2D继承自抽象类
Graphics。它的用法在下面面板的应用中讲解
第二部分 PanelLeft.java 类
package cn.huaxin.DrawBoard; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Stroke; 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 { public int pressedCount;// 按下的次数 int pressedCount=0 public String currentComman = "line"; // 默认一开始就是直线 public Color currentColor = Color.black; public Graphics2D graphics = null; public PanelLeft(Graphics2D g) { graphics = g; // 左边 Dimension dSizie = new Dimension(70, 100); // 尺寸 this.setPreferredSize(dSizie);// 设置大小 this.setBackground(Color.black);// 设置背景颜色 // 添加jbutton 添加图片 String[] images = { "airbrush", "brush", "color_picker", "curve", "dot_rect", "eraser", "fill", "line", "magnifier", "oval", "pencil", "polygon", "rect", "round_rect", "star", "word" }; // 1.先要有监听器 :一个类implements ActionListener ;; // 接口不能new,有一个普通类,没有类名-》匿名类 =>匿名内部类 ActionListener actionListener = new ActionListener() { // 重写了接口的抽象方法 // 事件触发 public void actionPerformed(ActionEvent e) { System.out.println("监听到了~~~"); pressedCount = 0; // 区分是哪个按钮? currentComman = e.getActionCommand();// 获得当前触发按钮的命令 if ("eraser".equals(currentComman)) { // 设置橡皮的颜色:白色 graphics.setColor(Color.WHITE); // 接口 s = 子类; 子类 s = 接口; Stroke s = new BasicStroke(10); // BasicStroke ss = (BasicStroke) s; // 接口 赋值给 子类 graphics.setStroke(s); } else if ("brush".equals(currentComman)) { // 设置刷子的颜色 graphics.setColor(currentColor); // 接口 s = 子类; 子类 s = 接口; Stroke s = new BasicStroke(10); // BasicStroke ss = (BasicStroke) s; // 接口 赋值给 子类 graphics.setStroke(s); } else if ("line".equals(currentComman)) { // 设置直线的颜色 graphics.setColor(currentColor);// ???不能写死 // 接口 s = 子类; 子类 s = 接口; Stroke s = new BasicStroke(1); graphics.setStroke(s); } else { // 设置白色 graphics.setColor(currentColor);// ???不能写死 // 接口 s = 子类; 子类 s = 接口; Stroke s = new BasicStroke(1); graphics.setStroke(s); } } }; for (int i = 0; i < images.length; i++) { ImageIcon imageIcon = new ImageIcon("images/" + images[i] + ".jpg"); JButton btnIcon = new JButton(imageIcon); Dimension preferredSize = new Dimension(25, 25); btnIcon.setPreferredSize(preferredSize); this.add(btnIcon); // 2.给按钮添加监听 btnIcon.addActionListener(actionListener);// // 3.给触发按钮设置一个命令 btnIcon.setActionCommand(images[i]);// } } }
通过继承JPanel,可以直接用this来代替:PanelLeft 的对象。
在设置构件大小时,一定要注意:除了JFrame可以直接通过 (new JFrame()).setSize(int length,int width)外,其他的一般通过Dimension来间接设置大小。如:
Dimension dSizie = new Dimension(70, 100);
this.setPreferredSize(dSizie);
实现左侧面板的大致思想是:
(1)建立左侧面板是,设置属性
(2)为面板添加按钮
(3)位每个按钮添加事件(得先建一个监听器才能添加监听器)
添加事件需要设置监听器和命令。由于ActionListener是接口,不能继承,在此用了一个懒办法:匿名内部类。它要求实现ActionListener里的抽象方法。BasicStroke()为Graphics2D里的设置画笔宽度的方法。
第三部分 PanelCneter.java 类
package cn.huaxin.DrawBoard;
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 { public PanelLeft panelLeft; public Graphics2D graphics; int polygonMiddleX; int polygonMiddleY; // 坐标 int xStart = 0; int yStart = 0; int xEnd = 0; int yEnd = 0; // 多边形 int polygonStartX; // 起点 收尾相连的时候用 int polygonStartY; Random random = new Random();// 随机数生成器 public PanelCenter(PanelLeft pl, Graphics2D g) { this.panelLeft = pl; graphics = g; // 1.1有个一个监听器;匿名内部类 MouseListener mouseListener = new MouseListener() { @Override public void mouseClicked(MouseEvent e) { int clickCount = e.getClickCount(); System.out.println("点击了" + clickCount); if ("polygon".equals(panelLeft.currentComman)) { if (clickCount == 1) { // 画直线 graphics.drawLine(polygonMiddleX, polygonMiddleY, e.getX(), e.getY()); // 交换中间点 polygonMiddleX = e.getX(); polygonMiddleY = e.getY(); } else if (clickCount == 2) { // 收尾相连 graphics.drawLine(polygonStartX, polygonStartY, polygonMiddleX, polygonMiddleY); // 还原点击次数 panelLeft.pressedCount = 0; } } } @Override public void mousePressed(MouseEvent e) { System.out.println("按下了"); // 起始点 xStart = e.getX(); yStart = e.getY(); if ("polygon".equals(panelLeft.currentComman)) {// 多边形 // 第一次 if (panelLeft.pressedCount == 0) { polygonStartX = xStart; polygonStartY = yStart; } } } @Override public void mouseReleased(MouseEvent e) { System.out.println("释放了"); xEnd = e.getX(); yEnd = e.getY(); // 画 if ("line".equals(panelLeft.currentComman)) // 区分 直线 还是椭圆??? // 通过命令区分 { // 当前是画直线 graphics.drawLine(xStart, yStart, xEnd, yEnd); } else if ("oval".equals(panelLeft.currentComman)) { // 反着画 : xStart>xEnd width<0 // TODO x较小的 y较小的 :绝对值:xEnd - xStart graphics.drawOval(xStart, yStart, xEnd - xStart, yEnd - yStart); } else if ("rect".equals(panelLeft.currentComman)) { // 反着画 : xStart>xEnd width<0 // TODO x较小的 y较小的 :绝对值:xEnd - xStart graphics.drawRect(xStart, yStart, xEnd - xStart, yEnd - yStart); } else if ("round_rect".equals(panelLeft.currentComman)) { graphics.drawRoundRect(xStart, yStart, xEnd - xStart, yEnd - yStart, 100, 100); } else if ("polygon".equals(panelLeft.currentComman)) {// 多边形 // 画第一条线 if (panelLeft.pressedCount == 0) { graphics.drawLine(xStart, yStart, xEnd, yEnd); polygonMiddleX = xEnd; polygonMiddleY = yEnd; panelLeft.pressedCount++; } } } @Override public void mouseEntered(MouseEvent e) { System.out.println("进入了"); } @Override public void mouseExited(MouseEvent e) { System.out.println("退出了"); } }; // 1.2鼠标拖动的事件监听器 MouseMotionListener mouseMotionListener = new MouseMotionListener() { // public void mouseDragged(MouseEvent e) { // System.out.println("鼠标拖动~~"); int x1 = e.getX(); int y1 = e.getY(); if ("pencil".equals(panelLeft.currentComman)) { // graphics.drawLine(x1, y1, x1, y1);// 不能画圆点 graphics.drawLine(xStart, yStart, x1, y1); xStart = x1; yStart = y1; } else if ("eraser".equals(panelLeft.currentComman)) { // System.out.println("~~~~"); graphics.drawLine(xStart, yStart, x1, y1); xStart = x1; yStart = y1; } else if ("brush".equals(panelLeft.currentComman)) { // System.out.println("~~~~"); graphics.drawLine(xStart, yStart, x1, y1); xStart = x1; yStart = y1; } else if ("airbrush".equals(panelLeft.currentComman))// 喷枪 { for (int i = 0; i < 30; i++) { // 生成的随机数 int nextInt = random.nextInt(8) - 4;// [0,9]->[-5,4] int nextInt2 = random.nextInt(8) - 4;// [0,9]->[-5,4] System.out.println(nextInt); graphics.drawLine(x1 + nextInt, y1 + nextInt2, x1 + nextInt, y1 + nextInt2);// 画点 } } } public void mouseMoved(MouseEvent e) { // System.out.println("鼠标移动"); } }; this.setBackground(Color.WHITE); // 2.给panel添加监听器 this.addMouseListener(mouseListener); this.addMouseMotionListener(mouseMotionListener); } }
中间面板,主要就是通过鼠标在面板上操作。所以,这里涉及到鼠标事件。
鼠标事件有:进入,按下,点击,释放,退出,拖动,移动。
监听器分为两种:MouseListener 和 MouseMotionListener
具体的每个按钮对应的事件如图所示。
第四部分 PanelBotton.java 类
package cn.huaxin.DrawBoard; 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 { // 1 默认颜色的数组 Color[] colors = { Color.red, Color.black, Color.blue, Color.yellow }; PanelLeft panelLeft; public Graphics2D graphics; 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(i); Color color = colors[i]; graphics.setColor(color);// 改了颜色 panelLeft.currentColor = color; if ("eraser".equals(panelLeft.currentComman))// 橡皮檫的时候颜色还原 { 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); } } }