想实现一个画板,那请你想想要分几步骤呢?
第一:画板是不是要有大致的样子呢?
第二:画板是不是要有属于它的组件呢?
第三:画板是不是要实现功能呢?
第四:画板的完善工作
根据上面几个步骤,一起来思考该怎么实现画板吧!
第一步:
新建一个窗体,在窗体上实现布局,布局就要用到面板,那么在这里我就在窗体上添加三个面板,他们分别是jpwest(放在窗体左边的面板)、jpsouth(放在窗体下面的面板)、jpcenter(放在窗体中间的面板),他们分别是类Jpwest、Jpsouth、Jpcenter的一个实例对象,这三个类是继承了JPanel的子类
三个面板的类分别为:
public class Jpwest extends JPanel{}
public class Jpsouth extends JPanel {}
public class Jpcenter extends JPanel {}
三个类的构造函数大家就自己写吧
创建面板对象,将对象添加到窗体上
Jpwest jpwest = new Jpwest();
Jpsouth jpsouth = new Jpsouth();
Jpcenter jpcenter = new Jpcenter();
//窗体添加面板
this.add(jpwest,BorderLayout.WEST);
this.add(jpsouth,BorderLayout.SOUTH);
this.add(jpcenter);
//可调用面板的函数
jpwest.initpanel();
jpsouth.initpanel();
jpcenter.initpanel();
第二步:
给窗体添加相应的组件:按钮等等
这里只是给出参照的部分代码
package DrawBorder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class Jpwest extends JPanel{
public ButtonGroup bg = new ButtonGroup();
public void initpanel(){
this.setBackground(Color.pink);//设置面板的背景颜色
//设置面板的大小
Dimension dim = new Dimension(50,70);
this.setPreferredSize(dim);
//设置面板的布局
FlowLayout fl = new FlowLayout(FlowLayout.CENTER,0,0);
this.setLayout(fl);
//创建按钮组件
for(int i=0;i<16;i++){
JRadioButton jrb = new JRadioButton();//兴趣小问题:为什么这里用JRadioButton而不是Button?
this.add(jrb);
//给按钮设置命令
jrb.setActionCommand("images"+i);
bg.add(jrb);
//给按钮插入图片,每个按钮有四种状态图片
ImageIcon icon1 = new ImageIcon("image/draw"+i+".jpg");
ImageIcon icon2 = new ImageIcon("image/draw"+i+"-1.jpg");
ImageIcon icon3 = new ImageIcon("image/draw"+i+"-2.jpg");
ImageIcon icon4 = new ImageIcon("image/draw"+i+"-3.jpg");
//添加状态图片
jrb.setIcon(icon1);
jrb.setRolloverIcon(icon2);
jrb.setPressedIcon(icon3);
jrb.setSelectedIcon(icon4);
jrb.setBorder(null);
}
}
}
窗体左边的面板加上了按钮之后,还要给窗体下面部分的面板添加颜色按钮
(这里我只添加一个颜色按钮,只是做一个技术上的示范)
package DrawBorder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
public class Jpsouth extends JPanel {
//利用构造函数传递对象
public DrawBorder db;
public Jpsouth(DrawBorder db1){
db = db1;
}
//面板类中将被用来调用的函数
public void initpanel(){
//设置面板额颜色和大小
this.setBackground(Color.gray);
Dimension dim = new Dimension(50,70);
this.setPreferredSize(dim);
//创建颜色按钮
final JButton jb1 = new JButton();
jb1.setPreferredSize(new Dimension(20,20));
//给按钮设置颜色,代表这种颜色按钮
jb1.setBackground(Color.green);
//创建设置按钮阴影的对象
BevelBorder bb = new BevelBorder(1,Color.white,Color.gray);
//在按钮上添加这个对象,实现按钮下凹的效果
jb1.setBorder(bb);
//在这个面板上添加上颜色按钮,这里只创建了一个按钮,剩下的按钮自己可以去实现,同时可以思考用什么方法可以简便的实现所以的按钮
this.add(jb1);
//设置监听
//ActionListener action = new ActionListener(){
//public void actionPerformed(ActionEvent e){
// db.color = jb1.getBackground();
// }
//};
//按钮添加监听
//jb1.addActionListener(action);
}
}
掌握了基本的组件创建和添加技术的人可以试着去美化或设计自己的画板基本模样
第三步:实现画板的各种功能(最关键的一步)
想实现画板的功能其实就是实现各种组件的功能,那么这里就需要用到很多监听的技术了;要实现画板功能我们第一时间想到的是不是画画需要什么,是的,画画需要的是画笔,那么思考要怎么得到画笔呢?
在这里大家可以去了解一下
类 Graphics
package DrawBorder;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.text.Collator;
import java.util.ArrayList;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.BevelBorder;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import java.awt.Dimension;
public class DrawBorder extends JFrame{
public Color color = Color.green;
public ArrayList<Shapes> ShapesList = new ArrayList<Shapes>();
public static void main(String[] args){
DrawBorder db = new DrawBorder();//创建画板的窗体对象
db.initFrame();
}
public void initFrame(){
//窗体的基本设置
this.setSize(500,500);//设置窗体大小this。setSize()
this.setDefaultCloseOperation(3);//窗体关闭设置
BorderLayout bl = new BorderLayout();//边框布局
this.setLayout(bl);//设置窗体的布局
//添加面板Jpanel
Jpwest jpwest = new Jpwest();
Jpsouth jpsouth = new Jpsouth(this);//将db这个对象以this的形式作为形参传给面板
Jpcenter jpcenter = new Jpcenter(this);//将db这个对象以this的形式作为形参传给面板
//窗体添加面板
this.add(jpwest,BorderLayout.WEST);
this.add(jpsouth,BorderLayout.SOUTH);
this.add(jpcenter);
//可调用面板的函数
jpwest.initpanel();
jpsouth.initpanel();
jpcenter.initpanel();
//设置可见
this.setVisible(true);
//visible后面要做的事
final Graphics g = jpcenter.getGraphics();//用一个Graphics的类的对象存放一个铅笔。问题是为什么要用final修饰
DrawListener dl = new DrawListener(g,jpwest.bg,this);//创建DrawListener对象
jpcenter.addMouseListener(dl);//在面板上添加鼠标监听
jpcenter.addMouseMotionListener(dl);//给面板添加监听对象
}
}
这里有几个小问题,大家有兴趣的可以去思考一下:为什么不创建画笔对象,而只是给个存储对象?为什么得到画笔的前面要用final修饰?为什么得到画笔要放在this.setVisible(true)之后?
画笔得到了,接下来实现画图的功能,要在面板上画图,鼠标的移动就相当于画笔的移动,那么在这里就需要对鼠标添加监听,最后在相应的类里面设置好按钮的监听,这里用到的是MouseListener和MouseMotionListener这两个接口,在这里几不再重复接口的特点和注意事项了,如果不清楚的话可以看上一篇博客,“Java小基础”里有详细的介绍
这里要注意:保证监听的坐标系和绘图的坐标系一致
package DrawBorder;
import java.awt.AWTException;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
public class DrawListener implements MouseListener,MouseMotionListener{
public int x1,y1,x2,y2,x3,y3,x4,y4;//坐标
public Graphics2D g;//画笔
public String command;
public ButtonGroup bg;//按钮组
public DrawBorder db;//用来接受传递过来的DrawBorder对象
boolean flag = true;
public Random ran = new Random();//创建随机对象
//构造函数
public DrawListener(Graphics g1,ButtonGroup bg1,DrawBorder db1){
Graphics2D g2 = (Graphics2D)g1;
bg = bg1;
g = g2;
db = db1;
}
//实现鼠标的拖拉
public void mouseDragged(MouseEvent e) {
//若鼠标点击的是图片6的按钮,实现画直线的功能
if("image6".equals(command)){
//得到点的坐标
x2 = e.getX();
y2 = e.getY();
//画直线
g.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
}
//若鼠标点击的是图片7的按钮
else if("image7".equals(command)){
//构造一个具有指定线条宽度以及 cap 和 join 风格的默认值的实心 BasicStroke
Stroke strock =new BasicStroke(10);
g.getStroke();
//得到点的坐标
x2 = e.getX();
y2 = e.getY();
//画直线
g.drawLine(x1, y1, x2, y2);
x1 = e.getX();
y1 = e.getY();
strock = new BasicStroke(1);
g.setStroke(strock);
}
//若鼠标点击的是图片2的按钮
else if("image2".equals(command)){
//构造一个具有指定线条宽度以及 cap 和 join 风格的默认值的实心 BasicStroke
Stroke strock = new BasicStroke(10);
g.setStroke(strock);
//获取画笔的颜色
Color color = g.getColor();
g.setColor(Color.white);
//获取点的坐标
x2 = e.getX();
y2 = e.getY();
//画直线
g.drawLine(x1, y1, x2, y2);
//转换坐标
x1 = x2;
y1 = y2;
//构造一个具有指定线条宽度以及 cap 和 join 风格的默认值的实心 BasicStroke
strock = new BasicStroke(1);
g.setStroke(strock);
//获取颜色
g.setColor(color);
}
//若鼠标点击的是图片8的按钮,实现喷漆
else if("image8".equals(command)){
x2 = e.getX();
y2 = e.getY();
//喷漆是许多小点组成的
for(int i=0;i<200;i++){
int value1 = ran.nextInt(30)-15;//获取圆心
int value2 = ran.nextInt(30)-15;
//画直线
g.drawLine(x2+value1, y2+value2, x2+value1, y2+value2);
}
}
}
//鼠标的点击
public void mouseClicked(MouseEvent e) {
int count = e.getClickCount();//获取鼠标点击的次数
//判断鼠标点击的次数是否等于2,
if(count==2){
//判断鼠标点击的是图片13的按钮
if("image13".equals(command));{
//获取点的坐标
x2 = e.getX();
y2 = e.getY();
//画直线
g.drawLine(x4, y4, x2, y2);
//将flag标志改变
flag = true;
}
}
}
//鼠标按下
public void mousePressed(MouseEvent e) {
//获取鼠标按下的点的坐标
x1 = e.getX();
y1 = e.getY();
ButtonModel bm = bg.getSelection();//ButtonModel是一个接口,在按钮的上方按下鼠标使得模型既被选中又被按下
command = bm.getActionCommand();//获得command
g.setColor(db.color);
}
public void mouseReleased(MouseEvent e) {
//获得鼠标释放的点的坐标
x2 = e.getX();
y2 = e.getY();
//若鼠标点击的是图片10的按钮
if("image10".equals(command)){
g.drawLine(x1, y1, x2, y2);
}
//若鼠标点击的是图片12的按钮,实现画矩形
else if("image12".equals(command)){
g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2), Math.abs(y1-y2));
}
//若鼠标点击的是图片14的按钮,实现画椭圆
else if("image14".equals(command)){
g.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1-x2), Math.abs(y1-y2));
}
//若鼠标点击的是图片13的按钮,实现画多边形
else if("image13".equals(command)){
//根据flag判断是否要进行多边形最后的封闭
if(flag){
g.drawLine(x1, y1, x2, y2);
x4 = x1;
y4 = y1;
flag = false;
}
else{
g.drawLine(x3, y3, x2, y2);
}
x3 = x2;
y3 = y2;
}
//若鼠标点击的是图片4的按钮
else if("image4".equals(command)){
//获得屏幕上的坐标
x2 = e.getYOnScreen();
y2 = e.getYOnScreen();
try {
Robot robot = new Robot();
//创建矩形对象
Rectangle rect = new Rectangle(x2,y2,1,1);
//根据矩形获取缓冲截图
BufferedImage bi = robot.createScreenCapture(rect);
//获取当前图片 像素颜色
int c = bi.getRGB(0, 0);
//把int表示的值再转化为颜色Color
Color color = new Color(c);
g.setColor(color);
//g.drawImage()
} catch (AWTException e1) {
e1.printStackTrace();
}
}
}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
第四步:完善
实现画板的功能后,会出现这样的问题:将你画了图形的画板最小化或影藏一部分,再拖出来的时候被隐藏的图形会不见了,这关系到的欧式内存方面的问题
1.paint方法的认识
硬盘(持久化存储机制):容量大,存储速度慢
内存(运行程序数据存储机制):容量微大,速度居中
闪存(cpu处理数据临时存储机制):容量小,速度快
paint:用于绘制组件,应用于组件显示:执行从内存调用数据到闪存
2.图形的保存(继承的使用)
Shapes类封装属性
ArrayList保存多个图形
那么,要怎么使用paint方法呢?大家可以看看下面的部分代码
<pre name="code" class="html">package DrawBorder;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Jpcenter extends JPanel {
DrawBorder db;
public Jpcenter(DrawBorder db1){
db = db1;
}
public void initpanel(){
this.setBackground(Color.white);
}
//paint方法的实现
public void paint(Graphics g){
super.paint(g);
//这里将将所画的图形都存放在队列里面
//要使得图形不消失,那么就要调用paint方法,遍历队列,从内存中还原图形
for(int i = 0;i<db.ShapesList.size();i++){
Shapes shape = db.ShapesList.get(i);
g.setColor(shape.color);
//判断图形的形状
if(shape.type ==10){
g.drawLine(shape.x1,shape.y1, shape.x2, shape.y2);
}else if(shape.type == 12){
g.drawRect(Math.min(shape.x1, shape.x2), Math.min(shape.y1, shape.y2), Math.abs(shape.x1-shape.x2), Math.abs(shape.y1-shape.y2));
}
}
}
}
初步了解了关于画板的一些知识可能还不能很好地去真正掌握那些技巧和方法,跪在坚持学,多想想有木有其他的解决办法,尝试就会有收获!