`
joe243634401
  • 浏览: 6555 次
  • 性别: 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  
  

相关推荐

    java画图板的总结

    这篇博客的文章链接虽然无法直接查看,但从标题我们可以推测它可能是关于Java Canvas的使用经验和技巧的总结。 首先,Java中的Canvas类是一个非常基础的绘图接口,它没有内置的绘图功能,需要开发者自行实现。你...

    protel99SE画板简明流程总结

    Protel99SE是一款经典且广泛使用的电子设计自动化(EDA)软件,主要用于电路原理图设计和PCB(印制电路板)布局布线。本文将深入解析protel99SE画板的简明流程...希望这份简明总结能为你的PCB设计之路提供有力的支持。

    简单画板开发总结

    在给定的"简单画板开发总结"中,虽然具体使用的编程语言和库未明确指出,但我们可以假设它涉及到的是基本的绘图API的使用。 1. **绘图API**:无论是哪种语言,绘图API都是画板的核心。例如,HTML5的Canvas API提供...

    画板保存总结

    【标题】:“画板保存总结”涉及的知识点主要围绕图形绘制、事件监听和文件操作,这些是计算机图形学和Java编程中的基础概念。 【描述】虽然没有提供具体的内容,但根据“画板保存总结”这一标题,我们可以推测这篇...

    几何画板加自定义工具包.zip

    总结来说,"几何画板加自定义工具包.zip"不仅提供了一个基础的几何画板试用环境,更赠送了一份海量的自定义工具集,使得数学教学和学习变得更加生动有趣。无论是初学者还是经验丰富的用户,都能从中找到适合自己的...

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

    ### 高频PCB板设计心得总结 #### 一、前言 随着电子产品向着更高频率、更高性能的方向发展,高频PCB(Printed Circuit Board,印制电路板)设计成为了电子产品研发过程中的关键技术之一。良好的高频PCB设计不仅...

    Java实现画板(Java小程序 模仿Win系统画板)

    在本文中,我们将深入探讨如何使用...总结起来,Java实现的画板程序涉及到GUI设计、图形绘制、事件处理、文件操作等多个核心Java技术。通过学习和实践这个项目,开发者可以加深对Java Swing的理解,提升GUI编程能力。

    opencv画板功能实现源程序

    总结来说,"opencv画板功能实现源程序"项目通过OpenCV提供的图形绘制函数和鼠标事件处理,实现了让用户在交互式窗口上自由绘画的功能。项目中可能涉及多个Python模块,每个模块负责不同的功能,如主程序控制、画板...

    画板的 Demo 例子

    总结,画板Demo例子主要展示了如何在HTML5环境中使用画板API进行图形绘制。通过理解并实践这些基本操作,开发者可以创建出丰富多样的网页图形效果和应用程序。在压缩包`jihehuabao5.06`中,可能包含了实现这些示例的...

    玲珑画板 6.045 版安装.rar

    总结来说,玲珑画板6.045版是一款轻量级但功能强大的数学作图工具,它的出现为数学教育领域提供了新的可能性。无论是教学还是自学者,都可以从中受益,通过直观的图形化方式加深对数学的理解,提升学习效率。所以,...

    WPF+WCF画板聊天程序

    总结来说,"WPF+WCF画板聊天程序"是一个结合了先进图形界面技术与高效通信机制的创新应用,它利用WPF创建了生动的画板环境,借助WCF实现实时的聊天和协作功能,为用户提供了一种新颖的在线沟通和创作方式。...

    易语言画板自动换行写模块

    总结一下,易语言画板自动换行写模块是一个帮助开发者在画板上实现文本自动换行显示的工具。它涉及到了字符串处理、字符测量、画板操作等多个方面的知识,是易语言图形界面编程中的一项实用技术。通过学习和应用这个...

    易语言画板带滚动条加载图片

    总结起来,易语言画板带滚动条加载图片的实现涉及到文件操作、控件交互、事件处理等多个知识点。通过熟练掌握这些技能,开发者可以创建出具有高级交互功能的图形用户界面,满足各种复杂的显示需求。在实际应用中,还...

    几何画板课件350套 (2).zip

    总结起来,"几何画板课件350套 (2).zip" 是一个全面的几何学教育资源,包含了大量的教学实例和练习,适用于教师的教学辅助和学生的学习巩固。无论是在课堂教学还是自主学习中,这个压缩包都能提供丰富的素材,帮助...

    几何画板控件教程

    #### 六、总结 通过本文的详细介绍,我们了解到几何画板5.01控件不仅解决了以往版本中存在的问题,还进一步增强了其功能性和易用性。对于广大教师来说,这一工具无疑将成为提升教学质量的重要帮手。无论是制作动态...

    vc实现的画板

    总结,这个"VC实现的画板"项目是一个综合性的学习案例,涵盖了Windows编程的基础、GUI设计、事件处理、绘图函数和状态管理等多个方面。对于想要提升VC编程技能,尤其是对GUI应用程序开发感兴趣的开发者来说,这是一...

    MFC做的画板MFC做的画板

    总结,MFC为创建Windows桌面应用提供了强大的支持,尤其是对于画板类应用,MFC的图形绘制能力和用户交互处理机制使得开发过程更为简便。通过定制CView类,结合MFC的事件处理和GDI绘图API,我们可以构建出功能丰富的...

    web点击按钮事件弹出画板功能的画板插件

    总结来说,实现“web点击按钮事件弹出画板功能”需要利用JavaScript库如Fabric.js,并结合HTML5的canvas元素,监听按钮点击事件,动态加载画板。在视频教学项目中,这个功能能极大地提升教学质量和互动性。同时,...

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

    标题中的“画板BMP格式保存和打开总结”是指在编程中处理图像文件时,针对BMP(Bitmap)格式的图像进行保存和读取的操作。BMP是一种无损的位图格式,通常用于Windows操作系统中,它直接存储像素数据,没有经过任何...

Global site tag (gtag.js) - Google Analytics