再言画板的总结
??????依旧是画板,已经写到第七个版本了,与上篇所说的相比,除了界面加上了一个可变画图面板,代码上进行了一些优化以外,还加上了画板的重绘,这样,就不用担心窗体最小化之后所画图形未保存了。下面上代码。
package Draw20111020;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Cursor;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.Shape;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import javax.swing.JFrame;import javax.swing.JPanel;/** * 自制简单画图板,第七次修正 * @author 鲁大帅 */public class Draw05 extends JFrame {//参数private ImpList<NetJavaShape> shapes = new ImpList<NetJavaShape>();//定义一个队列用来存放数组对象private boolean isChange = false;//用于后面的判断private Graphics2D g;//画布定义成2D的,主要是因为加上了粗细这个参数/** 主函数 */public static void main(String[] args) {Draw05 htb = new Draw05();htb.showUI();}/** 实现界面的方法*/public void showUI() {this.setTitle("鲁大帅的画板");// 设置标题this.setSize(600, 430);// 设置窗体大小this.setDefaultCloseOperation(3);// 关闭的时候自动退出程序this.setLocationRelativeTo(null);// 窗体显示位置居中// 设置边框布局对象BorderLayout bl = new BorderLayout();this.setLayout(bl);/** 添加四个面板 */ToolBar tb = new ToolBar();// 工具栏MyMenuBar mb = new MyMenuBar();// 菜单栏ColorBox cp = new ColorBox();// 颜色栏final JPanel center = new JPanel();// 右边面板// //设置布局为流式,左对齐,上下,左右间距为5px,背景颜色为灰center.setLayout(new FlowLayout(0, 5, 5));center.setBackground(Color.GRAY);final JPanel dp = new JPanel(){public void paint(Graphics g){super.paint(g);//调用父类的方法来绘制窗体drawshape((Graphics2D)g);//调用绘制形状的方法}};// 设置画图的面板dp.setBackground(Color.WHITE);// 颜色为白色dp.setPreferredSize(new Dimension(400, 260));center.add(dp);/** 添加面板到窗体 */this.add(tb, BorderLayout.WEST);this.add(mb, BorderLayout.NORTH);this.add(cp, BorderLayout.SOUTH);this.add(center, BorderLayout.CENTER);this.setVisible(true);// 窗体可见MyListener ml = new MyListener(dp, tb, cp,shapes);// 实现鼠标监听dp.addMouseListener(ml);dp.addMouseMotionListener(ml);// 拖动改变画布大小的实现// 在匿名内部类中使用外面的局部变量,一定要定义成finalMouseAdapter ms = new MouseAdapter() {int cursors;//移动到右下角时改变光标的形状public void mouseMoved(MouseEvent e) {int x = e.getX();int y = e.getY();if (x > dp.getPreferredSize().getWidth()&& x < dp.getPreferredSize().getWidth() + 10&& y > dp.getPreferredSize().getHeight()&& y < dp.getPreferredSize().getHeight() + 10) // 改变光标的形状{center.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));cursors = 1;isChange = true;//右边和下面中点的情况} else if (x > dp.getPreferredSize().getWidth()/2&& x < dp.getPreferredSize().getWidth()/2 + 10&& y > dp.getPreferredSize().getHeight()&& y < dp.getPreferredSize().getHeight() + 10){center.setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));cursors = 2;isChange = true;}else if(x > dp.getPreferredSize().getWidth()&& x < dp.getPreferredSize().getWidth() + 10&& y > dp.getPreferredSize().getHeight()/2&& y < dp.getPreferredSize().getHeight()/2 + 10){center.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));cursors = 3;isChange = true;}else {// 设置为默认光标center.setCursor(Cursor.getDefaultCursor());isChange = false;}}public void mouseReleased(MouseEvent e) {int x = e.getX();int y = e.getY();int x1 = (int) dp.getPreferredSize().getWidth();int y1 = (int) dp.getPreferredSize().getHeight();if (isChange) {if(cursors == 1){// 设置画布面板的大小dp.setPreferredSize(new Dimension(x - 5, y - 5));}else if(cursors == 2){dp.setPreferredSize(new Dimension(x1,y -5));}else if(cursors == 3){dp.setPreferredSize(new Dimension(x-5,y1));}// 刷新javax.swing.SwingUtilities.updateComponentTreeUI(dp);center.setCursor(Cursor.getDefaultCursor());isChange = false;}}};center.addMouseListener(ms);center.addMouseMotionListener(ms);dp.addMouseMotionListener(ms);}private void drawshape(Graphics2D g) {//遍历队列for(int i=0;i<shapes.size();i++){NetJavaShape ss = shapes.get(i);ss.draw(g); }}}??
???? ?以上是主函数,有些地方还是看起来很累赘,但目前能做的只有这样了。画板实现了主界面添加菜单栏,工具栏,颜色栏,可改变画布大小以及画布重绘等功能。工具栏和颜色栏虽有有些稍微的区别,但大体构架还是一样的,下面只说颜色栏。代码如下:
package Draw20111020;import java.awt.Color;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;import javax.swing.JButton;import javax.swing.JPanel;import javax.swing.JToolBar;/** * 颜色栏外加颜色监听 * @author Administrator * */public class ColorBox extends javax.swing.JToolBar{//设置参数private int col;//用于后面左右键的判断private Color color;//点击左右键所得的颜色private Color lcolor=Color.BLACK;private Color rcolor=Color.WHITE;public ColorBox(){colorchoose();}/**获得左右键颜色的值的方法*/public Color getlColor(){return lcolor;}public Color getrColor(){return rcolor;}/**选择颜色的方法*/public void colorchoose(){/** * color面板设置大小、颜色、流式布局 */this.setName("颜色");this.setPreferredSize(new Dimension(600,90));//设置大小FlowLayout g0 = new FlowLayout(FlowLayout.LEFT);this.setLayout(g0);/** * 创建一个工具条,2个面板,jp1放置颜色监听,jp2放置颜色面板 */JPanel jtb = new JPanel();JPanel jp1 = new JPanel();JPanel jp2 = new JPanel();jp1.setPreferredSize(new Dimension(41,41));//设置大小jp1.setLayout(null);jp1.setBackground(Color.WHITE);jp2.setPreferredSize(new Dimension(282,41));//设置大小/**对于jp1,设置front、back两面板,自由布局*/final JButton front = new JButton();final JButton back = new JButton();//新建两按钮front.setPreferredSize(new Dimension(15,15));//面板大小back.setPreferredSize(new Dimension(15,15));front.setBounds(10,10,15,15);back.setBounds(16,16,15,15);//设置locationfront.setBackground(Color.BLACK);back.setBackground(Color.WHITE);//设置初始背景色back.addActionListener(new ActionListener(){public void actionPerformed(ActionEvent e){showColorSelecter();}});//匿名内部类给back添加动作监听,点击调出颜色选择器jp1.add(front);jp1.add(back);//添加两面板/**添加鼠标监听器*/MouseAdapter al=new MouseAdapter(){// 点击时返回对象数值public void mouseClicked(MouseEvent e) {//获得点击的值以判断左右键col = e.getButton();//获得对象Object obj = e.getSource();//强制转型JButton but = (JButton)obj;//获得color的值color = but.getBackground();//判断,如果点击左键,则设置front颜色;如果是右键,则设置back颜色if(col==1){front.setBackground(color);lcolor=color;}else if(col==3){back.setBackground(color);rcolor=color;}} };/**对于jp2,用于装颜色面板*///定义一个Color数组Color colorbox[]={Color.BLACK,new Color(128,128,128),new Color(128,0,0),new Color(128,128,0),new Color(0,128,0),new Color(0,128,128),new Color(0,0,128),new Color(128,0,128),new Color(128,128,64),new Color(0,64,64),new Color(0,128,255),new Color(0,64,128),new Color(128,0,255),new Color(128,64,0), Color.WHITE,new Color(192,192,192),new Color(255,0,0),new Color(255,255,0),new Color(0,255,0),new Color(0,255,255),new Color(0,0,255), new Color(255,0,255),new Color(255,255,128),new Color(0,255,128),new Color(128,255,255),new Color(128,128,255),new Color(255,0,128),new Color(255,128,64)};//通过for循环添加数组中按钮for(int i=0;i<28;i++){JButton btn = new JButton();btn.setBackground(colorbox[i]);btn.setPreferredSize(new Dimension(15,15));btn.addMouseListener(al);jp2.add(btn);}//将面板加到工具条上jtb.add(jp1);jtb.add(jp2); // 将工具条加到大面板上 this.add(jtb);}/**调出颜色选择器的方法*/private void showColorSelecter(){this.color = javax.swing.JColorChooser.showDialog(null, "请选择颜色", java.awt.Color.BLACK);}}???????? 完成了各个面板,接下来就是将他们连接起来的监听器了,来看看这个:
public class MyListener extends MouseAdapter{/** * 定义参数 */private int x1,y1,x2,y2;private Color color;private Graphics2D g;private String command="pencil";private ToolBar tb;private ColorBox cp;private int col;private JPanel dp;//定义一个队列用来保存绘制的形状private ImpList<NetJavaShape> shapes ;public MyListener(JPanel dp,ToolBar tb,ColorBox cp,ImpList<NetJavaShape> shapes){this.dp = dp;this.tb = tb;this.cp = cp;this.shapes = shapes;}//鼠标按下事件,取得起始坐标public void mousePressed(MouseEvent e) {g = (Graphics2D)dp.getGraphics();//col作为判断左右键颜色的依据,获得color值col=e.getButton();if(col==1){color = cp.getlColor();}else if(col==3){color=cp.getrColor();} x1 = e.getX(); y1 = e.getY(); } //鼠标拖拽事件,画曲线 public void mouseDragged(MouseEvent e){x2=e.getX();y2=e.getY(); command = tb.getCommand(); //从tb中获得command的值 NetJavaShape s1= null; /**曲线的画法*/ if(command.equals("pencil")){ s1= new Impline(x1,y1,x2,y2,1,color); s1.draw(g);x1=x2;y1=y2; }else if(command.equals("eraser")){ /**橡皮*/ s1= new Imperaser(x1,y1,x2,y2,10,Color.WHITE); s1.draw(g);x1=x2;y1=y2; } shapes.add(s1); } //鼠标按下得到终点坐标 public void mouseReleased(MouseEvent e) { x2 = e.getX(); y2 = e.getY(); NetJavaShape s2=new Impline(x1,y1,x2,y2,1,color);if(command.equals("line")){s2 = new Impline(x1, y1, x2, y2,1,color); //直线 }else if(command.equals("rect")){ s2 = new Imprect(x1, y1, x2, y2,1,color); //矩形 }else if(command.equals("oval")){ s2 = new Impoval(x1, y1, x2, y2,1,color); //椭圆 }else if(command.equals("rounded_rect")){ s2= new ImpRoundRect(x1, y1, x2, y2,1,color); //圆角矩形 }else if(command.equals("polygon")){ s2 = new Impjt(x1, y1, x2, y2,1,color); //三角形 } s2.draw(g); dp.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); shapes.add(s2); }}?????? 监听器从主函数得到了画布对象和队列,又从颜色面板得到了画笔的颜色,这样一来,就可以通过监听和判断绘制图形了。本人不才,仅仅只实现了画曲线、直线、矩形、椭圆、圆角矩形、一个坑爹的三角形和橡皮。对与这些图形的画法,首先定义了一个抽象类NetJavaShape,所有的形状画法皆继承于此,绘制的方法大同小异。下面以矩形为例。下面有三种画法:第一种为最复杂,也最易理解,即分四种情况讨论x1、x2,y1、y2的大小。
if(x1<x2&&y1<y2){g.drawRect(x1, y1, x2-x1, y2-y1); }else if(x1<x2&&y1>y2){g.drawRect(x1, y2, x2-x1, y1-y2);} else if(x1>x2&&y1<y2){g.drawRect(x2, y1, x1-x2, y2-y1);} else if(x1>x2&&y1>y2){g.drawRect(x2, y2, x1-x2, y1-y2);} ???
???? ?第二种是我自己的囧方法,即把边界通过画直线四点连接起来,这里就不说了。第三种是来自龙哥的很巧妙方法,看似简单,对我这种初学者来说确实很难想到。
g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2));
????? 一个小小的矩形就有这样不同的的写法,这说明要实现目标,方法是很多的。套用一句话:“没有做不到,只有想不到。”的确如此。只要多思考,然后付诸实践,很多问题都能解决的。好的想法应该是成功的第一步吧。当然,要成功中间还有很长的路要走,但只要坚持下去,别放弃,一定能行的。即使失败了,也绝不后悔。
???? 至于队列的实现,这里就不写了。最后,再贴张图吧。

?