Java第六课——画图板

Java第六课——画图板

这节课画一个画图板,可以画线画圆,还可以通过递归画出好看的图案如:谢尔宾斯基三角形,康托尔方形集,甚至立体图门格海绵。

首先创建一个窗体。定义一个类和一个方法。

public class Draw{
	public void show(){
		JFrame frame =new JFrame();
		FlowLayout layout=new FlowLayout();
		frame.setLayout(layout);
		frame.setSize(1000,1000);
		frame.setVisible(true);
	}
	public static void main(String[] args){
		Draw ui=new Draw();
		ui.show();
	}
} 

再添加监听器
这里的监听器就不只是ActionListener了,由于是画图板,不仅要有按钮来判断是花园画圆还是划线,这里要用到动作监听器;而且要获取鼠标的位置来划线,要用到鼠标监听器MouseListener或者MouseMotionListener,这两者的区别如下:
MouseListener的鼠标事件有:
MOUSE_CLICKED 鼠标点击(要求比较苛刻,按下和松开必须是同一个像素格)
MOUSE_ENTERED 鼠标进入(某个窗体)
MOUSE_EXITED 鼠标离开
MOUSE_PRESSED 鼠标按下
MOUSE_RELEASED 鼠标松开
MouseMotionListener的鼠标事件有:
MOUSE_DRAGGED 鼠标拖拽
MOUSE_MOVED 鼠标移动
那么在划线时,推荐使用MouseListener里的mousePressed和mouseReleased。因为在拖拽时会持续划线,导致线越来越粗。
1、添加监听器,要额外创建一个类DrawListener
2、划线需要一支画笔,要用到Graphics,需要在监听器类和画图板类中都实例化一个Graphics的对象,并且让二者相等。
3、在这个类中还需要划线起始点和终止点的坐标值startx,starty,endx,endy。获取坐标的方法就由getX()和getY()来实现。
4、创建并添加监听器后,每次按下按钮,系统需要获取最近一次按下按钮的名称,根据该名称来判断应该是划线还是画圆,就需要一个空的String用于存储。

public class DrawListener implements MouseListener,ActionListener{
	//坐标
	int startx,starty,endx,endy;
	//Graphics
	Graphics g;
	//存储上一次按钮的名称
	String str="";
	//补齐函数
	public void actionPerformed(ActionEvent a){}
	public void mousePressed(MouseEvent e){}
	public void mouseReleased(MouseEvent e){}
	public void mouseClicked(MouseEvent e) {}
	public void mouseEntered(MouseEvent e) {}
	public void mouseExited(MouseEvent e) {}
}

在Draw类show方法中
1、Graphics获取的画笔必须在设置可视之后
2、为窗体添加按钮,并且为按钮添加ActionListener,当按钮数量比较多时,可以用数组(下一课会详细介绍,先按模板来)

public class Draw{
	public void show(){
		JFrame frame =new JFrame();
		FlowLayout layout=new FlowLayout();
  		frame.setLayout(layout);
		frame.setSize(1000,1000);
		
		DrawListener lis=new DrawListener();
		frame.addMouseListener(lis);
		
		//利用数组添加按钮
		String[] name={"直线","圆形","谢尔宾斯基三角形","康托尔方形集","门格海绵"}
		//通过for循环生成按钮并添加监听器
		for(int i=0;i<name.length;i++){
			JButton btn=new JButton(name[i]);
			frame.add(btn);
			btn.addActionListener(lis);
		}
		
		frame.setVisible(true);
		//从frame中获取位置,传回监听器类
		Graphics g=frame.getGraphics();
		lis.g=g;
		
	}
	public static void main(String[] args){
		Draw ui=new Draw();
		ui.show();
	}
} 

可以通过Dimension来调节按钮大小,让界面更美观,在界面那节课讲到,这里不多赘述。
接下来的任务是先获取按钮文本,在actionPerformed(ActionEvent a)中,用a.getActionCommand()得到按钮文本放到str中

public void actionPerformed(ActionEvent a){
	str=a.getActionCommand();
}

在pressed和released中获取startx,starty,endx,endy的值

public void mousePressed(MouseEvent e){
	startx = e.getX();
	starty = e.getY();
}
public void mouseReleased(MouseEvent e){
	endx = e.getX();
	endY = e.getY();
}

划线,画圆

划线是一个过程,也就是先按下鼠标,拖动,再松开鼠标,那么就上当鼠标松开时划线。划线用drawLine(int x1,int y1,int x2,int y2)
画圆也是同理,用drawOval(int x1,int y1,int width,int height),这里可能存在startx>endx,starty>endy的情况,那么加入数学函数Math.min(startx,endx)即可,宽度用endx-startx的绝对值Math.abs(endx-startx)

public void mouseReleased(MouseEvent e){
	endx = e.getX();
	endY = e.getY();
	if("直线".equals(str)){
		g.drawLine(startx,starty,endx,endy);
	}
	if("圆形".equals(str)){
		g.drawOval(Math.min(endx, startx), Math.min(starty, endy), Math.abs(endx-startx), Math.abs(endy-starty));
     }
}

谢尔宾斯基三角形

谢尔宾斯基三角形可以看出每个白色三角形内部都会分出三个白色三角形和一个黑色三角形,所以利用递归能很轻松的画出谢尔宾斯基三角形,只需要每次都找到白色三角形各边的中点,连接起来并涂黑就可以完成,涂黑用fillPolygon(int [ ] xPoints,int [ ] yPoints,int nPoints)前面两个数组为x,y坐标的数组,最后的nPoints表示所填充的多边形顶点个数
创建一个新的类,并利用函数triangle画出三角形

public class Sierpinskitriangle{
	public void triangle(){
	}
}

设n为找中点的次数,设(x1,y1)(x2,y2)(x3,y3)为最大三角形三个顶点的坐标
那么首先先把最开始的三个点之间连起来,并且获取各个中点代入数组:

g.drawLine(x1, y1, x2, y2);
g.drawLine(x1, y1, x3, y3);
g.drawLine(x2, y2, x3, y3);
int[] x={(x1+x2)/2,(x1+x3)/2,(x2+x3)/2};
int[] y={(y1+y2)/2,(y1+y3)/2,(y3+y2)/2};

当n=1时,涂黑 fillPolygon(x, y, 3)
当n增加时,要调用自己三次使得新的三个白色三角形都能再分出新的三角形,那么只需把x1,y1,x2,y2,x3,y3赋予新的三角形的三个顶点即可,所以通过形参直接赋值会方便的多,于是可以用到下面的函数头public void triangle(Graphics g,int n,int x1,int x2,int x3,int y1,int y2,int y3),Graphics g可以直接通过形参拿到画笔
那么当n=2时,三个triangle(g,2-1,x1,x2,x3,y1,y2,y3),这里的三个顶点为三个白色三角形的顶点,然后每次调用后都接fillPolygon(x, y, 3)
n=3时,三个triangle(g,3-1,x1,x2,x3,y1,y2,y3),fillPolygon(x, y, 3)
每次调用自己时都要涂黑显得麻烦,不如使得n=1时什么都不做,让涂黑到主程序里:

public class Sierpinskitriangle{
	public void triangle(Graphics g,int n,int x1,int x2,int x3,int y1,int y2,int y3){
		int[] x={(x1+x2)/2,(x1+x3)/2,(x2+x3)/2};
		int[] y={(y1+y2)/2,(y1+y3)/2,(y3+y2)/2};
		g.drawLine(x1, y1, x2, y2);
		g.drawLine(x1, y1, x3, y3);
		g.drawLine(x2, y2, x3, y3);
		g.fillPolygon(x, y, 3);
		if(n==1){
			return;
		}
		triangle(g,n-1,x1,(x1+x2)/2,(x1+x3)/2,y1,(y1+y2)/2,(y1+y3)/2);
		triangle(g,n-1,x2,(x1+x2)/2,(x2+x3)/2,y2,(y1+y2)/2,(y2+y3)/2);
		triangle(g,n-1,x3,(x1+x3)/2,(x2+x3)/2,y3,(y1+y3)/2,(y2+y3)/2);
	}
}

那么在监听器类中可在mouseReleased(MouseEvent e)函数中,像直线和画圆一样,if(“谢尔宾斯基三角形”.equals(str)),则创建一个对象并调用方法

if("谢尔宾斯基三角形".equals(str)){
	Sierpinskitriangle triangle=new Sierpinskitriangle();
	triangle.triangle(g,5,500,100,900,100,900,900);

当n=5时画出的图像和上图一样

康托尔方形集康托尔方形集

先创建一个类和一个方法

public class CantorSquareset{
	public void csset(){
	}
}

用drawRect(int x1,int y1,int width,int height)画矩形
给n下个定义,最开始有一个最大的矩形。当n=1时,画出中间的第二大的矩形;n=2时,画出第二大矩形周围8个第三大的矩形。那么从1开始n每加一,就需要调用8次函数本身,而其实只需要找到这八次的八个矩形的顶点,那么利用函数头csset(Graphics g,int n,int x1,int y1,int x2,int y2) 其中(x1,y1)(x1,y2)分别时矩形的左上角和右下角
那么当n=1时,中间矩形 drawRect(x1+(x2-x1)/3, y1+(y2-y1)/3, (x2-x1)/3, (y2-y1)/3)
当n=2时,找出各小矩形左上角和长宽

public class CantorSquareset{
	public void csset(Graphics g,int n,int x1,int y1,int x2,int y2){
	g.drawRect(100, 100, 800, 800);
	if(n==1){ 
		g.drawRect(x1+(x2-x1)/3, y1+(y2-y1)/3, (x2-x1)/3, (y2-y1)/3);
		return;
	}
	csset(g,n-1,x1,y1,x2,y2);
	csset(g,n-1,x1,y1,x1+(x2-x1)/3,y1+(y2-y1)/3);
	csset(g,n-1,x1+(x2-x1)/3,y1,x2-(x2-x1)/3,y1+(y2-y1)/3);
	csset(g,n-1,x2-(x2-x1)/3,y1,x2,y1+(y2-y1)/3);
	csset(g,n-1,x1,y1+(y2-y1)/3,x1+(x2-x1)/3,y2-(y2-y1)/3);
	csset(g,n-1,x2-(x2-x1)/3,y1+(y2-y1)/3,x2,y2-(y2-y1)/3);
	csset(g,n-1,x1,y2-(y2-y1)/3,x1+(x2-x1)/3,y2);
	csset(g,n-1,x1+(x2-x1)/3,y2-(y2-y1)/3,x2-(x2-x1)/3,y2);
	csset(g,n-1,x2-(x2-x1)/3,y2-(y2-y1)/3,x2,y2);
	}
}

在mouseReleased(MouseEvent e)函数中

if("康托尔方形集".equals(str)){
	CantorSquareset csset=new CantorSquareset();
	csset.csset(g, 3, 100, 100, 900, 900);
	}

当n=3时图案和上图一样

门格海绵

门格海绵(由于没计算好长宽高,看起来不太像立方体,但能凑合)
门格海绵由三层构成,第一层8个,第二层4个,第三层8个。门格海绵并不复杂但较为繁琐这里就不展开来讲了直接放代码

public void smallsquare(Graphics g,int n,int x0,int y0,int a,int dx,int dy){
	if (n==1){  
		g.drawRect(x0, y0-a, a, a);
		g.drawLine(x0+dx, y0-a-dy, x0+dx+a, y0-a-dy);
		g.drawLine(x0+dx+a, y0-a-dy, x0+dx+a, y0-dy);
		g.drawLine(x0, y0-a, x0+dx, y0-a-dy);
		g.drawLine(x0+a, y0-a, x0+dx+a, y0-a-dy);
		g.drawLine(x0+a, y0, x0+a+dx, y0-dy);
		
		Polygon Polg2=new Polygon();
		Polg2.addPoint(x0, y0-a);
		Polg2.addPoint(x0+a, y0-a);
		Polg2.addPoint(x0+dx+a, y0-dy-a);
		Polg2.addPoint(x0+dx, y0-dy-a);    
		g.setColor(new Color(255,145,0));
		g.fillPolygon(Polg2);
   
		Polygon Polg1=new Polygon();
		Polg1.addPoint(x0, y0);
		Polg1.addPoint(x0+a, y0);
		Polg1.addPoint(x0+a, y0-a);
		Polg1.addPoint(x0, y0-a);    
		g.setColor(new Color(121,45,0));
		g.fillPolygon(Polg1);
   
		Polygon Polg3=new Polygon();
		Polg3.addPoint(x0+a, y0);
		Polg3.addPoint(x0+a, y0-a);
		Polg3.addPoint(x0+a+dx, y0-a-dy);
		Polg3.addPoint(x0+a+dx, y0-dy);    
		g.setColor(new Color(137,111,0));
		g.fillPolygon(Polg3);
		return;
		}
	smallsquare(g,n-1,x0+2*dx/3,y0-2*dy/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*dx/3+a/3,y0-2*dy/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*dx/3+2*a/3,y0-2*dy/3,a/3,dx/3,dy/3);  
	smallsquare(g,n-1,x0+dx/3,y0-dy/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+dx/3+2*a/3,y0-dy/3,a/3,dx/3,dy/3);  
	smallsquare(g,n-1,x0,y0,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+a/3,y0,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*a/3,y0,a/3,dx/3,dy/3);
  
	smallsquare(g,n-1,x0+2*dx/3,y0-2*dy/3-a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*dx/3+2*a/3,y0-2*dy/3-a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0,y0-a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*a/3,y0-a/3,a/3,dx/3,dy/3);
  
	smallsquare(g,n-1,x0+2*dx/3,y0-2*dy/3-2*a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*dx/3+a/3,y0-2*dy/3-2*a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*dx/3+2*a/3,y0-2*dy/3-2*a/3,a/3,dx/3,dy/3);  
	smallsquare(g,n-1,x0+dx/3,y0-dy/3-2*a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+dx/3+2*a/3,y0-dy/3-2*a/3,a/3,dx/3,dy/3);  
	smallsquare(g,n-1,x0,y0-2*a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+a/3,y0-2*a/3,a/3,dx/3,dy/3);
	smallsquare(g,n-1,x0+2*a/3,y0-2*a/3,a/3,dx/3,dy/3);
}

在mouseReleased(MouseEvent e)函数中

if("门格海绵".equals(name)){
	Mengersponge sponge=new Mengersponge();
	sponge.smallsquare(n, 4, 50, 950, 630, 220, 220);
}

当n=4时图案和上图一样

关于画图板内内容差不多到这,实际上是加强的递归的运用。另外画图板还有分形,但由于并不难就不介绍了,下一课讲数组

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值