我的仿XP画板初期
写一篇总结,对我而言,远比漂漂亮亮的写出一个程序难。但是没有总结,怎么告诉自己我在进步???????? 记于终于决定写画板总结前
我的仿XP画板初期
这个画板还远没有做到我自己想象中的perfect,只是实现了一些非常基础的功能,尚处于更进中。
一、概况
1.1重点分析
界面设置,绘制基本图形的实现,可选颜色的实现
1.2实现功能
1. 绘制一些基本的图形:直线,矩形,实心矩形,椭圆,实心椭圆,圆角矩形,实心圆角矩形等。
2. 用鼠标在画图板上单击拖动进行随笔画。
3. 设置画笔的颜色:可以选择当前绘制图形的画笔颜色。
4. 每种绘制选项的图标都有四种状态,分别是初始状态、鼠标进入,被按下、鼠标松开。当每种选项被操作的时候,图标会做出相应改变。
5. 在窗体改变时可保留原有图形,即实现了画板的重绘。
二、界面详细介绍
2.1 基本图形按钮
1、基本图形按钮包括:Pencil(随笔画)、Line(直线)、Rect(矩形)、fRect(实心矩形)、Oval(椭圆)、fOval(实心椭圆)、RoundRect(圆角矩形)、fRoundRect(实心圆角矩形)。
2、基本图形都继承自同一个父类:Shape。考虑到每种图形的绘制方法不一样,将Shape定义为抽象类,它具有的属性和方法如下:
int x1, y1, x2, y2; //用来存放相应图形元素的相关坐标
Color colorDraw、colorFill; //用来存放图形色彩信息
public void draw(Graphics g){} ;//绘制图形的方法,由各个基本图形自己重写父类绘制方法来实现。
2.2 菜单及其组成
1. “文件”菜单项,包括:打开(打开一个图形文件)、保存(保存一个图形文件)、新建(新建一个图形文件)、退出(退出程序)。
2. “编辑”菜单项:包括:撤销、恢复。
3. “帮助”菜单项:有关的程序帮助提示。
(这些操作均没有实现,只是在菜单栏中添加了这些选项)
2.3颜色板
1. 添加了8种颜色,可以通过点击颜色板相应颜色来设置画笔颜色。
2. 可以单独控制填充图形的边框颜色和填充颜色。
2.4 画板重绘
1、在画图板最小化再恢复后,可以恢复已经绘制了的图形。
2、在画图区域被拖离屏幕范围后再恢复,可以恢复已经绘制了的图形。
2.5 现在的程序界面图为:
三、详细设计与实现
3.1基本图形包括:
1. Pencil:随笔画,图标为。
2. Line:直线,图标为。
3. Rect:矩形,图标为。
4. fRect:实心矩形。
5. Oval:椭圆,图标为。
6. fOval:实心椭圆。
7. RoundRect:圆角矩形,图标为。
8. fRoundRect:实心圆角矩形。
单击工具栏上相应图形的图标,然后在绘图区域内用鼠标拖动进行绘画即可。
3.2选择颜色
1、画笔颜色的改变:直接点击想要使用的颜色后,再到画图区域进行绘画即可
2、填充颜色的改变:选中左下方单选按钮,再选择想使用的颜色,再绘制即可
3.3程序结构说明
本程序主体文件为一个工程:我的画图板。其中包括的包有:drawBoard、shape、list,分别包含:窗体设计、绘制形状、动态数组三大块内容,每个包中有含有的类如下:
drawBoard:
1. MyDrawBoard:构造函数,用以初始化。
2. InitDrawBoard:用于设置窗体属性。
3. InitMenuBar:用于设置菜单栏属性
4. InitDrawType:用于设置绘制形状工具栏属性
5. InitDrawArea:用于设置绘图区域属性
6. InitColorToolBar:用于设置颜色工具栏属性
7. DrawAreaLis:绘图区域面板监听器
8. DrawTypeLis:绘制选项面板监听器
9. ColorLis:颜色面板监听器
Shape(前面已有介绍,此处略去)
List:
1. ListInterface:接口类,作为父类,写明了动态数组必须实现的方法(为便于使用,所存放的数据类型定义为泛型)
2. ListImp:实现ListInterface中的方法
四、关键部分具体实现代码
我的画板入口:
窗体属性的设置
窗体属性的设置
窗体属性的设置
设置绘图区域面板属性
由于还没有实现此面板的其他功能,所以代码很少
public class InitDrawArea {
/**
* 重写构造方法,传入参数
* @param drawAreaPanel 绘图区域面板
*/
public InitDrawArea(JPanel drawAreaPanel){
// 创建绘图区域面板
drawAreaPanel.setBackground(Color.white);
}
}
绘制选项工具栏属性设置
public class InitDrawType {
ButtonGroup group;
String buttonName[];
FlowLayout fl= new FlowLayout();
javax.swing.JRadioButton[] radioButton;
/**
* 重写构造函数,传入以下参数
* @param drawTypeToolBar 绘制选项工具栏
* @param group 单选键组
* @param buttonName 单选键名称,也是即将设置的绘制命令
* @param radioButton 单选建
*/
public InitDrawType(JToolBar drawTypeToolBar, ButtonGroup group,String buttonName[],javax.swing.JRadioButton[] radioButton) {
this.group = group;
this.buttonName=buttonName;
this.radioButton=radioButton;
drawTypeToolBar.setBackground(Color.LIGHT_GRAY);
// 设置面板布局为空布局
drawTypeToolBar.setLayout(fl);
//创建监听器,获取相应的按钮,并将其图标作出改动
DrawTypeLis drawTadap= new DrawTypeLis(group);
// 创建单选键 并设置命令
//创建绘图选项按钮,并添加图片
for (int i = 0; i < buttonName.length; i++) {
javax.swing.JRadioButton name = new javax.swing.JRadioButton();
name.setPreferredSize(new Dimension(32,32));
name.setActionCommand(buttonName[i]);
ImageIcon nameIcon = new ImageIcon("images2/draw"+i+"-1.jpg");
name.setIcon(nameIcon);
name.setBackground(Color.LIGHT_GRAY);
if(buttonName[i].equals("draw6")){
name.setSelected(true);
}
//将按钮添加到单选键组
group.add(name);
radioButton[i]=name;
name.addMouseListener(drawTadap);
name.addMouseMotionListener(drawTadap);
//将按钮添加到面板
drawTypeToolBar.add(name);
}
}
}
设定绘图区域面板监听器的操作
public class DrawAreaLis extends MouseAdapter {
private javax.swing.ButtonGroup typeGroup;
private java.awt.Graphics g;
private int x1, y1, x2, y2;
private String type = "pencil";
private JLabel lbColorDraw;
private JLabel lbColorFill;
private Color c = Color.white;
private ListImp<Shape> list;
private Shape shape;
javax.swing.JRadioButton[] radioButton;
/**
* @param gra
* 绘图区域画布
* @param typeGroup
* 单选键组,用于放置绘图选项
* @param buttonName
* 绘制选项名称数组
* @param drawAreaPanel
* 绘图区域面板
* @param list
* 存放已绘制数据,以备重绘时使用
* @param lbColorDraw
* 画笔颜色
* @param lbColorFill
* 填充颜色
* @param radioButton
* 绘制选项按钮组
*
*/
public DrawAreaLis(Graphics g, javax.swing.ButtonGroup typeGroup,
String[] buttonName, JPanel drawAreaPanel, ListImp<Shape> list,
JLabel lbColorDraw, JLabel lbColorFill,
javax.swing.JRadioButton[] radioButton) {
this.g = g;
this.typeGroup = typeGroup;
this.list = list;
this.lbColorDraw = lbColorDraw;
this.lbColorFill = lbColorFill;
this.radioButton = radioButton;
}
/**
* 鼠标按下时,获取当前位置坐标存放在x1,y1中
*/
public void mousePressed(MouseEvent e) {
// 得到选中的绘制形状
type = typeGroup.getSelection().getActionCommand();
// 获得按下时的坐标
x1 = e.getX();
y1 = e.getY();
}
/**
* 鼠标释放时,获取当前位置坐标,并绘制相应的图形
*/
public void mouseReleased(MouseEvent e) {
// 获得释放时的坐标
x2 = e.getX();
y2 = e.getY();
// 绘图
shape = new Line(x1, y1, x2, y2, lbColorDraw.getBackground());
if ("draw10".equals(type)) { // 直线
shape = new Line(x1, y1, x2, y2, lbColorDraw.getBackground());
} else if ("draw12".equals(type)) { // 矩形
if (lbColorFill.getBackground().getRGB() == c.getRGB()) { // 判断填充颜色是否为空???????
shape = new Rect(x1, y1, x2, y2, lbColorDraw.getBackground());
} else {
shape = new FRect(x1, y1, x2, y2, lbColorDraw.getBackground(),
lbColorFill.getBackground());
}
} else if ("draw14".equals(type)) { // 椭圆
if (lbColorFill.getBackground().getRGB() == c.getRGB()) {
shape = new Oval(x1, y1, x2, y2, lbColorDraw.getBackground());
} else {
shape = new FOval(x1, y1, x2, y2, lbColorDraw.getBackground(),
lbColorFill.getBackground());
}
} else if ("draw15".equals(type)) { // 圆矩
if (lbColorFill.getBackground().getRGB() == c.getRGB()) {
shape = new RoundRect(x1, y1, x2, y2, Math.abs(x1 - x2) / 4,
Math.abs(y1 - y2) / 4, lbColorDraw.getBackground());
} else {
shape = new FRoundRect(x1, y1, x2, y2, Math.abs(x1 - x2) / 4,
Math.abs(y1 - y2) / 4, lbColorDraw.getBackground(),
lbColorFill.getBackground());
}
}
// 绘制相应的图形
shape.draw(g);
list.add(shape);
}
/**
* 铅笔画,鼠标拖动,切换起始点画直线
*/
public void mouseDragged(MouseEvent e) {
if ("draw6".equals(type)) {
// 获得拖动时的坐标
x2 = e.getX();
y2 = e.getY();
shape = new Pencil(x1, y1, x2, y2, lbColorDraw.getBackground());
shape.draw(g);
x1 = x2;
y1 = y2;
list.add(shape);
}
}
}
设定颜色工具栏监听器的操作
public class ColorLis extends MouseAdapter {
JLabel lbColorDraw;
JLabel lbColorFill;
javax.swing.JRadioButton btnColorFill;
/**
* 重写构造方法,传入以下参数
* @param lbColorDraw 画笔颜色
* @param lbColorFill 填充颜色
* @param btnColorFill 控制填充标签显示与否的按钮
*/
public ColorLis(JLabel lbColorDraw, JLabel lbColorFill,
javax.swing.JRadioButton btnColorFill) {
this.lbColorDraw = lbColorDraw;
this.lbColorFill = lbColorFill;
this.btnColorFill = btnColorFill;
}
/**
* 将被选中的按钮背景色赋给lBColorDraw作为背景色
*/
public void mouseReleased(MouseEvent e) {
// 得到事件源对象(被点击的按钮)
JButton c = (JButton) e.getSource();
Color col = c.getBackground();
if (btnColorFill.isSelected()) {
lbColorFill.setBackground(col);
} else{
lbColorDraw.setBackground(col);
}
}
}
绘制选项工具栏监听器设定
实则控制绘制选项工具栏上图标的状态对鼠标操作所做的相应改变,我的图片都在这个工程中的images2文件夹中。但是这里还有问题没有解决,当新按下一个键后,之前被选定的键不会自动弹起,求解^_^~
public class DrawTypeLis extends java.awt.event.MouseAdapter{
ButtonGroup group;
/**
* 重写构造方法,传入参数
* @param group 单选键组
*/
public DrawTypeLis(ButtonGroup group){
this.group=group;
}
/**
* 鼠标按下
*/
public void mousePressed(MouseEvent e) {
javax.swing.JRadioButton jrb=(javax.swing.JRadioButton)e.getSource();
ImageIcon icon = new ImageIcon("images2/"+jrb.getActionCommand()+".jpg");
jrb.setIcon(icon);
}
/**
* 鼠标释放
*/
public void mouseReleased(MouseEvent e) {
javax.swing.JRadioButton jrb=(javax.swing.JRadioButton)e.getSource();
ImageIcon icon = new ImageIcon("images2/"+jrb.getActionCommand()+"-2.jpg");
jrb.setIcon(icon);
}
/**
* 鼠标进入
*/
public void mouseEntered(MouseEvent e) {
javax.swing.JRadioButton jrb=(javax.swing.JRadioButton)e.getSource();
ImageIcon icon = new ImageIcon("images2/"+jrb.getActionCommand()+"-3.jpg");
jrb.setIcon(icon);
}
/**
* 鼠标离开
*/
public void mouseExited(MouseEvent e) {
javax.swing.JRadioButton jrb=(javax.swing.JRadioButton)e.getSource();
ImageIcon icon = new ImageIcon("images2/"+jrb.getActionCommand()+"-1.jpg");
jrb.setIcon(icon);
for(int i=0;i<16;i++){
if(group.getSelection().getActionCommand()==jrb.getActionCommand()){
ImageIcon jrbIcon = new ImageIcon("images2/"+jrb.getActionCommand()+"-2.jpg");
jrb.setIcon(jrbIcon);
}
}
}
}
shape包下的各种形状绘制方法
由于每种形状的实现都近似,所以此处不一一写出,只奉上父类和两个子类的代码作为示例
父类,定义为抽象类,因为绘制方法不能确定
/**
* 形状类,所有形状必须继承
* 有绘制方法以及坐标参数
* @author 丫丫
*
*/
public abstract class Shape {
//定义Shape的属性
int x1,y1,x2,y2;
Color colorDraw;
Color colorFill;
public void draw(Graphics g){};
}
画直线
public class Line extends Shape{
public Line (int x1,int y1,int x2,int y2,Color colorDraw){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
this.colorDraw=colorDraw;
}
public void draw(Graphics g){
g.setColor(colorDraw);
g.drawLine(x1, y1, x2, y2);
}
}
画填充矩形
public class FRect extends Shape {
/**
* 重写构造方法,以便传入参数
*/
public FRect (int x1,int y1,int x2,int y2,java.awt.Color colorDraw,java.awt.Color colorFill){
this.x1=x1;
this.y1=y1;
this.x2=x2;
this.y2=y2;
this.colorDraw=colorDraw; //边框颜色
this.colorFill=colorFill; //填充颜色
}
/**
* 重写父类绘制方法
*/
public void draw(Graphics g){
//控制填充色
g.setColor(colorFill);
g.fillRect(Math.min(x1, x2),Math.min(y1, y2), Math.abs(x1-x2),Math.abs(y1-y2));
//控制边框色
g.setColor(colorDraw);
g.drawRect(Math.min(x1, x2),Math.min(y1, y2), Math.abs(x1-x2),Math.abs(y1-y2));
}
}
此处用于重绘的list是自己写的,但是这个类在collection类中已经存在,可直接使用,便不再赘述。
五、此次画板收获中的一点点
虽然是很小的一个项目,但是真的要把它做好的确是挺难的,我们从开始学这个到做出来一个像样的画板具体花了多少时间有多少,我没有去计算过,至少有一个多星期吧。可是看着自己的成果,再看看人家XP正版的,不禁唏嘘。我们这还是在前人已经实现的基础上做的,用了这么长时间,实现的功能还不及人家的冰山一角,若要我们自己来想出一个新的工具,将它做出来,将它完善,又该花多少时间?我不喜欢为了写一些应付的文字去完成任务,或许大多数人都不喜欢吧,可是很多时候却是迫于各种压力不得不写,不得不胡乱充数。不过,这一片总结不是强迫出来的,而是自己做了许久之后,回头再看自己的劳动成果,蓦地发现自己有话说了。谢谢龙哥没有强制性的要求什么时候必须提交! 这个画板我会继续更进的,但愿,能做到真正的仿XP!
最后啰嗦一句 ,感谢有这样一个纯技术的博客平台,不过貌似有些不稳定呢!希望一同进步!