画板总结
今天,画板项目终于告一段落了。说句实在话,我觉得这个项目搞的时间实在是太长了。我第一天到蓝杰来就开始搞画图板,我大概是去年11月份来的吧,而现在却已经是2月份了。不过,虽然这个画板项目的时间比较长,但是我在其中的收获还是对的起这段时间的付出的。下面就来总结下我做画板这个项目所学到的东西和一些经验教训吧。
一、 对类的理解更加深入,逐渐养成了面向对象编程的思路。
做为一名计算机科学与技术的学生,我以前是接触过其他的编程语言的。我在来蓝杰学习之前学习过C,C++两门编程语言。上课时,C++老师虽然在上面讲了类的重载,继承,多态等等的东西,但是虽然我在上课是好像听懂了,下课后自己想用C++编一个什么什么东西来还是觉得无法下手。而且在C++里面的指针弄的我有点头痛,自己写完一个C++程序一运行,一般就会报N条红字出来。自从来这边接触JAVA之后我很快就感觉到它比C++更容易上手一些,学习C++时新手们看到指针就头痛了,而java 屏蔽了指针,这样至少对新手来说编程就变得容易一点了。以前学的C和C++两门语言中,我对C语言熟悉一些,我觉得好像像C++一样弄一个类把数据包装起来有些多余,我觉得很多东西,我用C就可以直接解决。所以,我编程思想一直停留在面向过程的编程方式上。接触了JAVA后一开始觉得什么都用对象,写程序有点不顺手。后来,代码写多了之后,我发现类的继承,重载,多态等一系列操作确实是编程更加人性化,更加简单了。
就拿重载来说吧,以前在C里面写程序时 如果要求两个数的最大值,int 型的数要写一个函数,FLOAT类型的数要写个名字不同的函数,调用时还要手动的调用INT类型的函数或者FLOAT类型的函数,显得比较麻烦。而利用JAVA或者C++里面的重载特性,
只需要写一个相同函数名的重载函数,然后调用时系统会自动的帮你调用INT 类型或者是FLOAT类型的那个函数,这就方便多了。所以从面向过程到面向对象,确实是一大进步。
二、 学会调用java API。
以前学C++时我对如何编一个界面非常感兴趣,但就是不知道如何去编。我还觉得编写一个界面是什么了不得的事情。但是我接触JAVA的API后才发现,编写一个界面是如此简单的事情。所有的组件你都可以在JAVA API中找到,你只需要注意它们调用的方法就可以编出你想要的界面了。
三、 形成了良好的编程习惯,和自己的编程风格。
以前我写代码时从来不会写注释,有时候程序出错回头检查时,自己都头晕。斌哥和龙哥每次看到我的代码没写注释,都反复强调要求我把注释写上。后来我强制要求自己写一些注释,慢慢的我开始习惯写注释了。而且我发现一点,就是在写注释的过程中,我脑海里就已经有了程序的框架,这样程序的思路就清晰了,写起来也不会因为前面写得不好卡住而觉得写不下去了。
还有就是编程风格,以前写代码的变量名定义是一天一个规范,每次都不同,造成了自己回看代码还要翻到前面变量定义那里去看看,才知道那个变量是做什么的。自从自己在网上看到别人用的命名定义方法,和龙哥又讲了一遍所谓驼峰法的命名规则之后,我为了使自己的代码更加规范。每次定义变量都严格按照规则来定义,比如说类的定义每个单词首字母都大写,其余小写。变量名或者方法名是首字母小写,后面的单词首字母大写,常量大写。这样我看到变量名就知道那个变量大概是做什么的。大大提高了代码的可读性。
上面那三点,是我做画板所提高的软实力。也就是好像感觉不那么重要的东西,其实我还是觉得比较重要的,一个良好的习惯,胜过一切其他技术方面的东西。习惯一养成,就很难去更改了,但是技术不知道,还可以重新学习。但是技术也是很重要的,所以下面我来谈一谈我从无到有做画板的经历吧。以下是我从无到有做学习做画板的过程。
1) 画板界面制作
2) 监听器的使用
3) 界面的美化
4) 图像的重绘
5) BMP文件的保存
1. 画板界面制作。这个到现在来说真的感觉没什么好说的,因为这没牵涉到算法,而且凡事有一定编程经验的看看系统API就会,关键是个熟练度的问题,你要把那些方法适用范围和调用方法注意一下就行了。我以前就是对着API里的类,接口自己实践的,熟能生巧。
// 主窗体 public void drawUI() { // 设置窗体大小 this.setSize(600, 500); // 设置窗体标题 this.setTitle("仿XP画板"); // 设置窗体在屏幕上居中 this.setLocationRelativeTo(null); // 设置窗体默认退出操作为关闭 this.setDefaultCloseOperation(3); // 设置窗体布局模式 BorderLayout bdlot = new BorderLayout(); this.setLayout(bdlot); // 设置窗体可见 this.setVisible(true); }
?
2. 监听器的使用。界面做好之后,我那个程序还不能画东西出来。没有实习画板的基本要求,正在这个时候,龙哥教了我要程序怎么画一个想要的东西到画板的界面上。
首先,创建一个鼠标监听器,用来监听鼠标事件。然后充主界面获取画布,通过监听器的构造器传入监听器中。最后只需在监听器相应的监听方法中用获得的画布画出相应的图形即可。
这里需要注意的是参数传递问题,和MouseListener里面方法执行的顺序
在java里基本类型参数是按值传递的,类类型是按引用传递(传地址)的
MouseListener里面的方法执行顺序依次是pressed? dragged? released? clicked
监听器类代码:
public class DrawListener extends java.awt.event.MouseAdapter { public DrawListener(java.awt.Graphics g) { this.g = (java.awt.Graphics2D)g; } }
?
创建监听器代码:
DrawListener dlis = new DrawListener(g);
?
画图代码:
public void mousePressed(MouseEvent e) { // 获取画布 g = (Graphics2D) drawPanel.getGraphics(); // 设置颜色 if (e.getButton() == 1) { g.setColor(leftClick.getBackground()); presentColor = leftClick.getBackground(); color = rightClick.getBackground(); } else if (e.getButton() == 3) { presentColor = rightClick.getBackground(); color = leftClick.getBackground(); g.setColor(rightClick.getBackground()); } // 得到动作指令 type = shapeGroup.getSelection().getActionCommand(); style = listLis.getStyle(); x1 = e.getX(); y1 = e.getY(); if (type.equals("duobianxing")) { if (flag == false) { firstx = x1; firsty = y1; flag = true; } else { x1 = x2; y1 = y2; } } } public void mouseReleased(MouseEvent e) { x2 = e.getX(); y2 = e.getY(); if (type.equals("cut")) { } else if (type.equals("select")) { } else if (type.equals("fill")) { } else if (type.equals("line")) { // 设置笔画轮廓 BasicStroke stroke = new BasicStroke(style + 1); g.setStroke(stroke); g.drawLine(x1, y1, x2, y2); // 重置笔画轮廓 stroke = new BasicStroke(0); g.setStroke(stroke); } else if (type.equals("quxian")) { } else if (type.equals("rect")) { if (style == 0) { g.drawRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } else if (style == 1) { g.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } else if (style == 2) { // 把颜色调成反色 g.setColor(color); g.fillRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); // 把颜色调回去 g.setColor(presentColor); } } else if (type.equals("oval")) { if (style == 0) { g.drawOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } else if (style == 1) { g.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); } else if (style == 2) { g.setColor(color); g.fillOval(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2)); g.setColor(presentColor); } } else if (type.equals("duobianxing")) { g.drawLine(x1, y1, x2, y2); if (e.getClickCount() >= 2) { g.drawLine(firstx, firsty, x1, y1); flag = false; } } else if (type.equals("roundrect")) { if (style == 0) { g.drawRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 10, 10); } else if (style == 1) { g.fillRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 10, 10); } else if (style == 2) { g.setColor(color); g.fillRoundRect(Math.min(x1, x2), Math.min(y1, y2), Math.abs(x1 - x2), Math.abs(y1 - y2), 10, 10); g.setColor(presentColor); } } // 每次释放后截屏 image.saveImage(drawPanel); } public void mouseDragged(MouseEvent e) { if (type.equals("penwrite")) { int x2 = e.getX(); int y2 = e.getY(); g.drawLine(x1, y1, x2, y2); x1 = x2; y1 = y2; } else if (type.equals("penqiang")) { int x2 = e.getX(); int y2 = e.getY(); // 设置打点范围 int size = (style + 1) * 5; // 创建随机生成数对象 Random rd = new Random(); // 在size范围内随机打点 for (int i = 0; i < 4; i++) { int rdx = rd.nextInt(size); int rdy = rd.nextInt(size); g.drawLine((rdx - size / 2) + x2, (rdy - size / 2) + y2, (rdx - size / 2) + x2, (rdy - size / 2) + y2); } } else if (type.equals("eraser")) { g.setColor(color); BasicStroke stroke = new BasicStroke(8, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL); g.setStroke(stroke); int x2 = e.getX(); int y2 = e.getY(); g.drawLine(x1, y1, x2, y2); x1 = x2; y1 = y2; // 重置颜色 g.setColor(presentColor); } else if (type.equals("brush")) { BasicStroke stroke = new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND); g.setStroke(stroke); int x2 = e.getX(); int y2 = e.getY(); g.drawLine(x1, y1, x2, y2); x1 = x2; y1 = y2; } }?
/** * 创建左面板 * * @return 容器 */ private JPanel leftPanel() { // 创建容器 JPanel left = new JPanel(); left.setPreferredSize(new Dimension(80, 500)); // 设置为流式布局,水平垂直间距均为0 left.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); // 创建风格选择框 JList<ImageIcon> list = new JList<ImageIcon>(); list.setPreferredSize(new Dimension(40, 60)); // 设置边框 list.setBorder(new BevelBorder(BevelBorder.LOWERED, Color.WHITE, Color.GRAY)); // 创建JList监听器 listLis = new ListListener(list); // 添加监听器 list.addMouseListener(listLis); // 创建按钮组 shapeGroup = new ButtonGroup(); // 创建 动作指令字符串 String str[] = { "cut", "select", "eraser", "fill", "xiguan", "view", "penwrite", "brush", "penqiang", "word", "line", "quxian", "rect", "duobianxing", "oval", "roundrect" }; // 创建绘画风格监听器 StyleListener stlLis = new StyleListener(list); for (int i = 0; i < str.length; i++) { // 添加图片网络路径 URL butUrl = DrawFrame.class .getResource("images/draw" + i + ".jpg"); URL butRolloverUrl = DrawFrame.class.getResource("images/draw" + i + "-1.jpg"); URL butPressedUrl = DrawFrame.class.getResource("images/draw" + i + "-2.jpg"); URL butSelectedUrl = DrawFrame.class.getResource("images/draw" + i + "-3.jpg"); // 创建图标对象 ImageIcon but = new ImageIcon(butUrl); ImageIcon butRollover = new ImageIcon(butRolloverUrl); ImageIcon butPressed = new ImageIcon(butPressedUrl); ImageIcon butSelected = new ImageIcon(butSelectedUrl); // 创建单选按钮 JRadioButton radioButton = new JRadioButton(); // 设置按钮图标 radioButton.setIcon(but); radioButton.setRolloverIcon(butRollover); radioButton.setPressedIcon(butPressed); radioButton.setSelectedIcon(butSelected); // 设置动作指令 radioButton.setActionCommand(str[i]); // 设置默认选中按钮为铅笔 if (radioButton.getActionCommand().equals("penwrite")) { radioButton.setSelected(true); } // 给按钮添加风格监听器 radioButton.addActionListener(stlLis); // 添加按钮到按钮组 shapeGroup.add(radioButton); // 添加按钮到左面板上 left.add(radioButton); } // 添加按钮到左面板上 left.add(list); return left; }?
public void paint(Graphics g) { super.paint(g); // 重绘代码 if (CatchScrn.a != null) { for (int i = 0; i < CatchScrn.a.length; i++) { for (int j = 0; j < CatchScrn.a[0].length; j++) { // 取点 int point = CatchScrn.a[i][j]; if (point != this.getBackground().getRGB()) { // 设置颜色 g.setColor(new Color(point)); // 画点 g.drawLine(j, i, j, i); } } } } }?
?
?
?