画图板初步

                                                     画图板初步

   从只是一个窗口,到画图板各种组件一步一步的齐全。先说一下我最大的收获,也是以后要注意的。


一:设定参数变量的时候,变量名一定要起好,要有规律...不然的话自己都很难找。

二:传值的时候一定要小心,(例如在界面和监听器中传值),漏传,传错等,皆是空值。

 

 

 

心得总结:

 

通过这次的画图板,让我初步体会到了 做一个大的程序的一些经验。

 

以前学的只是一个个小的程序,变量不多,但是真正的大程序,数据繁琐,必须要做到每一步的清晰(尤其是我错了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:

 

这是一个布置容器的边框布局,它可以对容器组件进行安排,并调整其大小,使其符合下列五个区域:北、南、东、西、中。每个区域最多只能包含一个组件,并通过相应的常量进行标识:NORTHSOUTHEASTWESTCENTER。当使用边框布局将一个组件添加到容器中时,要使用这五个常量之一,例如:

    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等数字的代表了吧~~~

 

 

画图板总体的架构已经完成,剩余的,就是其他功能的实现~~

 

 

 

 

你可能感兴趣的:(java)