`
joe243634401
  • 浏览: 6345 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

画板总结

阅读更多

画板总结
今天,画板项目终于告一段落了。说句实在话,我觉得这个项目搞的时间实在是太长了。我第一天到蓝杰来就开始搞画图板,我大概是去年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;
}
}
 
3. 界面的美化。这个主要是利用布局管理器,在主界面上把按钮,容器等组件按一定顺序布置好,按钮设置好图标,其余组件设置好背景颜色等操作。
/**
* 创建左面板
* 
* @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;
}
 
4. 图像的重绘。因为屏幕上的图像都是保存在缓存区内的,如果屏幕的图像被覆盖或者是没有在屏幕上显示完全,或者是改变了窗体大小,图像在缓存区的数据都会发生变化,甚至消失。正因如此,所以我们需要在窗体发生改变是重新绘制原来的数据,让它不至于消失掉。这个很简单,重写画布对象的paint方法即可,因为每次窗体发生变化是系统会自动调用它的paint方法。代码如下:
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);
}
}
}
}
} 
 
5. BMP文件的保存。这个东西是最近开始做的,目前我只能完美写入24位的位图。
但是其他的比如说1 ,4, 8位位图的数据结构和储存原理我全部掌握了,写的话只是时间问题了。这个首先得讲下BMP文件结构。BMP有4部分组成。分别是文件头,信息头,调色板和数据域。
文件头:

信息头:

调色板:只有位深度低于24位的位图才有。
数据域:存储一个像素点的空间大小为位深度/8个字节,如果宽*位深度%4不为0则在宽度后补0,使宽*位深度能被4整除
注意事项:1:机器字节序列(一般是小端存储)这意味着你不能直接用writeInt()或者是writeShort()直接写入2:图像宽高要设置正确(宽度不包括补零项)3:文件偏移量bfOffBits要设置正确,24位为54(文件头14+信息头40),小于24位则还要加上颜色板数组长度4:位深度要设置正确5:文件一定要写完整6:其它的有硬性规定的就按照上面的表设置值,没有的可以直接写0进去。
以上就是我画板的总结了。做这个做了这么久,也是有点小感慨的。我拿我以前没来蓝杰时候的我跟现在对比一下,以前这种编程的工作量是我根本不感想的,虽然现在看来这并不算什么。
学东西不能想当然,一定要脚踏实地。不能说这个我好像懂了,一定要动动手,动手之后你会发现很多新的问题。有些东西不是你能不能做到的问题而是你肯不肯下功夫的问题。
好了,大概就这么一些吧。顺便祝福一下自己能够越学越好吧。

 

 

 

分享到:
评论
1 楼 刘凯宁 2013-07-31  
  

相关推荐

    高频PCB板画板心得总结.docx

    高频PCB板画板心得总结docx,高频PCB板画板心得总结

    protel99SE画板简明流程总结

    protel99SE画板简明流程总结,看完本总结对protel99画pcb板有一个整体的概念,本总结原创,根据很多次具体pcb画板过程总结而来

    java画图板的总结

    NULL 博文链接:https://pengchenming.iteye.com/blog/1399196

    简单画板开发总结

    NULL 博文链接:https://13808498112.iteye.com/blog/1207509

    画板BMP格式保存和打开总结

    NULL 博文链接:https://feargod.iteye.com/blog/1136890

    画板保存总结

    NULL 博文链接:https://jyw-6555-qq-com.iteye.com/blog/1432050

    PCB画板注意事项总结

    经过一周多的时间,终于画出了第一块PCB 板,学到了很多东西, 也犯了不少错误。闲话不多说,先说一下错误。

    Android编程实现画板功能的方法总结【附源码下载】

    本文实例讲述了Android编程实现画板功能的方法。分享给大家供大家参考,具体如下: Android实现画板主要有2种方式,一种是用自定义View实现,另一种是通过Canvas类实现。当然自定义View内部也是用的Canvas。第一种...

    JAVA简单画板程序的设计实验报告.doc

    总结问题 设计过程: A. 界面设计 新建一个Jframe容器,然后定义一个panel( Panel convas2),convas2是工具栏。用borderlayout布置容器的边框布局,将工具栏放在 NORTH部分。完成界面设计。 add(canvas2,...

    JAVA简单画板程序设计实验报告材料.doc

    总结问题 设计过程: A. 界面设计新建一个Jframe容器,然后定义一个panel〔 Panel convas2〕,convas2是工具栏.用borderlayout布置容器的边框布局,将工具栏放在NOR TH局部.完成界面设计. add,BorderLayout.NORTH&gt;; ...

    sync-sketch-plugin:sketch画板同步

    核心功能功能的实现都是通过的API实现其核心功能就俩:将画板编码解码为画板核心代码由于功能并不复杂,但是sketch并没有完整的API文档,所以只能摸索着来,最后总结一下用到的API,只有下面的几个重要函数。...

    java学习小总结——画图板制作(附代码)

    NULL 博文链接:https://xiaoyjj.iteye.com/blog/1702155

    绘图板课程设计报告 JAVA

    绘图板绘图板开发源文件 基于JAVA开发

    毕业论文安卓511画板app.doc

    包括摘要,背景意义,论文结构安排,开发技术介绍,需求分析,可行性分析,功能分析,业务流程分析,数据库设计,er图,数据字典,数据流图,详细设计,系统截图,测试,总结,致谢,参考文献。

    油漆刷迹风格创意个人工作总结计划ppt模板.zip

    刷子刷油漆刷迹创意主图,彩色油漆喷迹前言页,刷迹创意目录页、过渡页,油漆滴落风格画板内容页,简约扁平化设计,精美图表,适合个人工作总结、个人工作计划、个人述职报告等场景应用的ppt模板。

    mfc实现画图板(源码+实验报告)

    (1) 能够用鼠标操控方式,绘制直线、矩形、椭圆。 (2) 在绘图时,选择绘制某种图像后(如直线),在画布中按住鼠标左键后移动鼠标,在画布中实时的根据鼠标的移动显示相应的图形。在松开鼠标左键后,一次绘图操作...

    pcb.zip_PCB 设计

    一个画板十年工程师总结P C B 设计的经验(经典)

    AD19 PCB 快捷键.xlsx

    AD19快捷键,自己多年画板经验总结,加快PCB布局布线速度,加快整个项目的进度,增加PCB美观度,减少Layout工作量。

Global site tag (gtag.js) - Google Analytics