? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?画图板初步
? ?从只是一个窗口,到画图板各种组件一步一步的齐全。先说一下我最大的收获,也是以后要注意的。
一:设定参数变量的时候,变量名一定要起好,要有规律...不然的话自己都很难找。
二:传值的时候一定要小心,(例如在界面和监听器中传值),漏传,传错等,皆是空值。
?
?
?
心得总结:
?
通过这次的画图板,让我初步体会到了 做一个大的程序的一些经验。
?
以前学的只是一个个小的程序,变量不多,但是真正的大程序,数据繁琐,必须要做到每一步的清晰(尤其是我错了n次的传值)。
?
其次,一定要把同一部分的内容放在一起,不然会使程序显得十分凌乱不堪,一旦出错,会花上更多的精力去寻找。
?
最后,是关于空指针和空值的处理。
?
最有用的方法,无非就是一行一行的打印,当然,当我们遇到没用过不理解的方法的时候,也是要用到打印的方法去理解。
?
我所遇到的空值,主要是两种错误:
?
1:传值的时候出错。
2:声明了多次,无法识别。
?
?
下面,开始就自己的体会,详细分析画图板。
我的画图板,是就windows自带的画图板进行模仿。windows自带画图板,主要有以下几个部分组成,我们可以将其分区,分为centre,left,foot三个部分。其中,centre主要是画板以及背景,left主要是形状的工具条,而foot就比较复杂,有颜色的工具条,以及坐标。(这里是主要部分,其他小附件先略过)
?
主要分为画图板部分和重绘保存部分
?
先来画图板部分
?
创建界面,代码如下:
?
public class Draw extends JFrame { /** * drawlistener要在第一个class中声明 创立监听器对象 */ Drawlistener drawlistener; // 主函数 public static void main(String args[]) { // 创建窗体对象,打开画板对象,固定格式 Draw draw = new Draw(); draw.draw1(); } /** * 初始化窗体 */ public void draw1() { this.setTitle("画图板"); this.setSize(600, 500); this.setBackground(java.awt.Color.gray); // 居中显示 this.setLocationRelativeTo(null); // 关闭方式 this.setDefaultCloseOperation(3); // 设置画板的布局格式 // 切记BorderLayout是java.awt.BorderLayout下面的要在前面引入 BorderLayout borderlayout = new BorderLayout(); this.setLayout(borderlayout);?
这样就初步做好了我们的登陆界面
?
这里要注意的是,1,最好要居中显示,不然自动默认到左上角。2,记得要有关闭方式,不然仍然存在在系统内存里面。3,记得要设置布局模式,在此处,我用的是BorderLayout。4,主函数主要起得是一个引入的作用里面不要放太多的东西。
?
再来简单介绍下BorderLayout:
?
这是一个布置容器的边框布局,它可以对容器组件进行安排,并调整其大小,使其符合下列五个区域:北、南、东、西、中。每个区域最多只能包含一个组件,并通过相应的常量进行标识:NORTH
、SOUTH
、EAST
、WEST
、CENTER
。当使用边框布局将一个组件添加到容器中时,要使用这五个常量之一,例如:
Panel p = new Panel(); p.setLayout(new BorderLayout()); p.add(new Button("Okay"), BorderLayout.SOUTH);
?
?
设置下左边的工具条:
?
/** * 开始工具条 左边 */ // 创建左边的工作条,默认是水平的,我们此处要改成垂直的--vertical javax.swing.JToolBar left = new javax.swing.JToolBar( javax.swing.JToolBar.VERTICAL); // 创建尺寸对象 记着要设计其长宽 java.awt.Dimension dimension1 = new java.awt.Dimension(70, 400); // 设置大小 其传入的值是对象,所以传入dimension1 left.setPreferredSize(dimension1); // 加在画板上面 this.add(left, BorderLayout.WEST);
这里加在画板上的时候,要小心是在WEST~~
?
对比windows画板可知,左边的工具条是有很多按钮的,于是,我们在左边工具条上加一个buttongroup,并且设置布局,如代码所示:
?
left.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); // 按钮分组 javax.swing.ButtonGroup group = new ButtonGroup(); // 大小 Dimension dimension2 = new Dimension(30, 30);
?这里将其布局设置为流式布局~
下面,加按钮:
?
// 直线的 // 加单选按钮 JRadioButton line = new JRadioButton("直线"); // 设置其动作命令 line.setActionCommand("line"); // 设置默认选中 line.setSelected(true); // 放在组里面 group.add(line); left.add(line); // 矩形~ JRadioButton rectangle = new JRadioButton("矩形"); rectangle.setActionCommand("rectangle"); // 放在组里面 group.add(rectangle); left.add(rectangle);?
?
这里我只贴出直线和矩形的,其他的方法一样,复制即可,就不贴出来了~~
需要注意的是,要有个默认选中,我的默认选中是直线。
?
?
下面是centre的部分。
中间要创建两个Jpanel,先是背景的,要注意设置其背景颜色为灰色,不要忘了,还有要记得布局是centre
?
// 创建中间的panel javax.swing.JPanel cjp = new JPanel(); // 设置中间的背景颜色 cjp.setBackground(java.awt.Color.gray); // 加在画板上 都是borderlayout的 this.add(cjp, BorderLayout.CENTER);
?再来是画板的
?
/** * 给中间加绘制的面板 jpanel */ // 设置布局 流式中间左对齐 FlowLayout center = new FlowLayout(FlowLayout.LEFT); this.setLayout(center); // 创建面板对象 javax.swing.JPanel jp = new Panel1(); // 设置大小 jp.setPreferredSize(new Dimension(450, 350)); // 设置背景颜色 jp.setBackground(java.awt.Color.WHITE); // 加 cjp.add(jp);?
注意:1,要设置为左对齐。2,背景颜色为白色。
?
下面是底部
由于底部由两部分组成,颜色的工具条和坐标,因此我们要在底部设置一个Jpanel
?
?
javax.swing.JPanel southjp = new javax.swing.JPanel(); // 设置底部面板的大小 southjp.setPreferredSize(new java.awt.Dimension(100, 60)); // 加在画板上面 this.add(southjp, BorderLayout.SOUTH); // 设置底部面板的布局 southjp.setLayout(new BorderLayout());?
?
底部的颜色条因为和形状的工具条基本相同,就不贴代码了~
?
然后就是坐标滴,坐标也是一个Jpanel~,上面主要显示为两部分~
1:坐标移动的显示
2:显示出画图二字
?
// 再设置一个jpanel... javax.swing.JPanel zhuangtailan = new javax.swing.JPanel(); // 设置底部面板的大小 zhuangtailan.setPreferredSize(new java.awt.Dimension(600, 30)); // 设置背景色 zhuangtailan.setBackground(java.awt.Color.white); // 加在画板上面 southjp.add(zhuangtailan, BorderLayout.CENTER); // 加label label,标签 JLabel left1 = new JLabel("画板"); JLabel center1 = new JLabel(""); JLabel right = new JLabel(""); // 加在zhuangtailan(jpanel) zhuangtailan.add(left1); zhuangtailan.add(center1); zhuangtailan.add(right);?
最后一步 就是传值和显示~~
传值这里要格外小心,要传入的值有graphics, center1, group1, group
且在监听器出要一一对应
?
// 显示 this.setVisible(true); // 这些要放在setvisible之后~! // 从jp上获取画布对象 java.awt.Graphics graphics = jp.getGraphics(); // 创建监听器对象 // 在第23行已经定义了drawlistener,这里就不需要再定义,不然会 出现空值 drawlistener = new Drawlistener(graphics, center1, group1, group); // 给jp加鼠标监听器 jp.addMouseListener(drawlistener); jp.addMouseMotionListener(drawlistener); }?
其余注释以及注意事项皆在代码里面
?
?
监听器
?
?
监听器要继承MouseListener, MouseMotionListener 两个接口
注意要实现接口中的所有方法
同时,一定要声明以及定义,具体如代码:
?
public class Drawlistener implements MouseListener, MouseMotionListener { // 定义x1,x2,y1,y2 private int x1, x2, y1, y2; // 声明Graphics 是画直线的~画图~ private java.awt.Graphics g1; // 声明ButtonGroup // 颜色的 private javax.swing.ButtonGroup color_group; // 形状的 private javax.swing.ButtonGroup group; // line,RoundRect;rectangle private String type = "line"; private String type1 = "black"; // 声明JLabel private javax.swing.JLabel centerjl;?
?
接下来是传值
传值的时候一定要小心~~
不然会空值!!!!!!!!这里出错了n次~
?
// 说明下Graphics g1,JLabel centerjl,ButtonGroup gl, ButtonGroup group public Drawlistener(java.awt.Graphics g1, javax.swing.JLabel centerjl, ButtonGroup gl, ButtonGroup group) { // 传值 // 设数值的时候一定要要小心啊 this.g1 = g1; this.color_group = gl;// 传入选择颜色的group this.group = group;// 传入选择图形的group // 记得把JLabel的值传过来 不然又是空指针 this.centerjl = centerjl;
?
下面主要就是方法
先来介绍下MouseListener, MouseMotionListener 两个接口的方法以及我们所需要的
MouseListener:
方法摘要 void
mouseClicked(MouseEvent e)
void
mouseEntered(MouseEvent e)
void
mouseExited(MouseEvent e)
void
mousePressed(MouseEvent e)
void
mouseReleased(MouseEvent e)
?
MouseMotionListener:
?
方法摘要 void
mouseDragged(MouseEvent e)
void
mouseMoved(MouseEvent e)
?
?
?
其中,我们主要用到的方法有:
?
?mousePressed(MouseEvent e){颜色 吸管}
?mouseReleased(MouseEvent e) {形状,重绘保存}
?mouseMoved(MouseEvent e), mouseExited(MouseEvent e)?{坐标的移动}
?
剩下的三个方法放在后面即可,不用~~
?
颜色 ,形状差不多
下面就贴出形状的代码
?
/** * 形状 */ // 在绘制前获取 javax.swing.ButtonModel buttonmodel = group.getSelection(); // 得到按钮模型的动作命令 type = buttonmodel.getActionCommand(); System.out.println(type); // 得到鼠标按下时候的光标的坐标 用x1,y1来表示相对于画布 x1 = e.getX(); y1 = e.getY(); /** * mouseReleased 鼠标释放 主要是画形状和截图保存 */ public void mouseReleased(MouseEvent e) { // 得到鼠标释放的时候光标的坐标用x2,y2来表示 x2 = e.getX(); y2 = e.getY(); /** * 画形状 */ // 开始画~ 直线 if (type.equals("10")) { // 这是是固定格式 // 这里点的获取要小心~(x1,y1) g1.drawLine(x1, y1, x2, y2); } // 矩形 if (type.equals("12")) { g1.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); System.out.print(g1 + "reck"); } // 圆角矩形 if (type.equals("15")) { g1.drawRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 35, 35); } // 弧线 if (type.equals("11")) { g1.drawArc(x1, y1, 200, 200, 150, 150); }?
这里可以看到,我type.equals后面跟的不是前面定义的变量名,这个会在后面解释,主要是牵涉到我们把按钮变成和windows画图板一样的图标
?
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
?
?
下面是重绘部分
?
重绘有两种方法。
?
一:队列
二:数组:1:二位数组
? ? ? ? ? ? ? ?2:直接截图保存
但是,如果我们想把数据储存在硬盘里面,只能用二位数组的保存方法
?
?
下面详解用二维数组的保存方法
?
?
在界面里:
?
?
现在主函数里面声明drawlistener
接着 我们在写一个class
也即嵌套一个class
代码如下
?
class Panel1 extends javax.swing.JPanel { /** * */ private static final long serialVersionUID = 1L; // 重写绘制方法 // 当改变时自动调用 // 重写paint,参数从ava.awt.Graphics graphics 调用 public void paint(java.awt.Graphics graphics) { // 调用父类方法 此时不可用this 要用super super.paint(graphics); // if循环 // 在监听器中创建的二维数组 // drawlistener,drawlistener.keep不是空值的时候进入循环 if (drawlistener != null && drawlistener.keep != null) { // 遍历 for (int i = 0; i < drawlistener.keep.length; i++) { for (int j = 0; j < drawlistener.keep[i].length; j++) { // 取颜色 int cNum = drawlistener.keep[i][j]; // 若储存颜色变 了,就在绘制一次 if (cNum != this.getBackground().getRGB()) { // 数字转颜色~强制转型 Color color = new Color(cNum); // 绘制点 graphics.setColor(color); graphics.drawLine(j, i, j, i); } } } } } } }?
?
1:这里的原理,就是把整幅图保存在内存里面,依据是其颜色的改变
2:关键字这里不可再用this,要用super~
?
下面是监听器
?
首先,声明保存的二维数组,在创建一个robot对象
?
*/ // 声明保存的二维数组(绘制区域) int[][] keep; // 声明robot java.awt.Robot robot;?
robot要写在public drawlistener里面
添加后代码如下
?
public Drawlistener(java.awt.Graphics g1, javax.swing.JLabel centerjl, ButtonGroup gl, ButtonGroup group) { // 传值 // 设数值的时候一定要要小心啊 this.g1 = g1; this.color_group = gl;// 传入选择颜色的group this.group = group;// 传入选择图形的group // 记得把JLabel的值传过来 不然又是空指针 this.centerjl = centerjl; // robot /** * 报错出现Unhandeled Exception...要加上try{}catch{} 这里就是个格式~ */ try { robot = new java.awt.Robot(); } catch (Exception ef) { ef.printStackTrace(); } }?
?
1:try...catch是固定的格式
2:关于报错 如果出现Syntax error on token(s)...表示要加()
?
主要写在mouseReleased(MouseEvent e)里面 具体代码如下
?
?
Object object = e.getSource(); // object一定是中间绘制的面板将jpanel对象---jp~ javax.swing.JPanel jp = (javax.swing.JPanel) object; // 得到jp左上角坐标,获取相对屏幕的坐标 java.awt.Point leftpoint = jp.getLocationOnScreen(); // 得到宽度 高度 java.awt.Dimension dimension1 = jp.getPreferredSize(); // 创建截取的区域对象,以jp左上角为起点,jp的大小 // 区域对象是长方形 所以用rectangle java.awt.Rectangle rectangle = new java.awt.Rectangle(leftpoint, dimension1); // 截图 java.awt.image.BufferedImage image = robot .createScreenCapture(rectangle); /** * 创建二维数组 */ keep = new int[image.getHeight()][image.getWidth()]; // 写两个for循环 for (int i = 0; i < keep.length; i++) { for (int j = 0; j < keep[i].length; j++) { // 获取图像对应坐标点颜色,储存在数组中,对应的下标位置 /** * 这里要小心 联系线代 i=y,j=x 不然就会弄反 */ keep[i][j] = image.getRGB(j, i); } } }
?
?
1:i=y,j=x,这里一定要注意!
2:截图只要是截的是矩形的区域
?
这样~~我们基本的架构已经做完啦~~
?
最后一步,就是美化一下~~
将按钮变成图标
主要也是用数组
?
?
首先,先要截好图~~(按钮的图片)
在将其放在代码所在的文件夹下面
?
先屏蔽掉以前的
新代码如下~
?
String[] commands = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16" }; for (int i = 0; i < commands.length; i++) { // 单选按钮 JRadioButton shape = new JRadioButton(); // 设置大小 // 小心这里传值又别弄错了!!! shape.setPreferredSize(dimension2); // 设置内边距 shape.setMargin(new java.awt.Insets(0, 0, 0, 0)); // 因为鼠标按下时候有4种形态 // 创建4个图标ImageIcon---图标对象 javax.swing.ImageIcon image1 = new javax.swing.ImageIcon( "images/draw" + i + ".jpg"); javax.swing.ImageIcon image2 = new javax.swing.ImageIcon( "images/draw" + i + "-1.jpg"); javax.swing.ImageIcon image3 = new javax.swing.ImageIcon( "images/draw" + i + "-2.jpg"); javax.swing.ImageIcon image4 = new javax.swing.ImageIcon( "images/draw" + i + "-3.jpg"); // 设置4种形态 shape.setIcon(image1); shape.setRolloverIcon(image2); shape.setPressedIcon(image3); shape.setSelectedIcon(image4); // 动作命令 shape.setActionCommand(commands[i]); if (i == 6) shape.setSelected(true); // 放进组 group.add(shape); // 加在左边的工具条上 left.add(shape); }?
?
现在,知道我前面监听器里面的11等数字的代表了吧~~~
?
?
画图板总体的架构已经完成,剩余的,就是其他功能的实现~~
?
?
?
?