【分形算法】Jason带你飞之2——java AWT组件的使用

上一篇我们成功的写出了计算LS表达式的两个函数caluStatement1和caluStatement2,接下来需要“创造”一个窗口,并且按照规则进行画图。使用java.awt中的Canvas类来作图可以实现需要的效果。

1、使用Canvas类,在画布上画一个圆圈

import java.awt.*;
import java.awt.event.*;
//画布
class MyCanvas extends Canvas{
	int x,y,r;
	MyCanvas(){
		x=76; y=12; r=38;
		setBackground(Color.cyan);
	}
	public void paint(Graphics g){
		g.drawOval(x, y, 2*r, 2*r);
	}	
}
//窗口
class MyWindow extends Frame {
	MyCanvas canvas= new MyCanvas();
	
    //构造方法
	MyWindow(){
		Panel pn= new Panel();
		add(canvas,BorderLayout.CENTER);
		add(pn,BorderLayout.SOUTH);
		setBounds(100,100,300,200);
		setVisible(true);
	}
	//响应关闭操作
	protected void processWindowEvent(WindowEvent e) {
        super.processWindowEvent(e);
        if (e.getID() == WindowEvent.WINDOW_CLOSING) {
          System.exit(0);
        }
      }
	//窗口名称
    public synchronized void setTitle(String title) {
        super.setTitle(title);
        enableEvents(AWTEvent.WINDOW_EVENT_MASK);
      }	
}
/**Main method*/
public class sheldon {
	public static void main(String args[]){
		MyWindow instance= new MyWindow();
		instance.setTitle("sheldon and his brain yeah");
	}
}

在这个代码中,我们重写了父类的public void paint(Graphics g)方法。当重写这个方法时,参数g是自动实例化的,这样就可以在子类中使用g的相应方法,比如画直线、画图形等等。同时组件调用repaint方法时,程序会首先清除paint方法以前所画的内容,然后再调用paint方法。

2、给窗口加上菜单、下拉列表和按钮

我们要做一个有菜单,中间是黑底的画布,画笔是绿色,底部加一个panel的窗口。

java中Frame的一个实例就是一个容器(可理解成一个窗口),Frame上可以添加panel,panel上可以添加button和label之类的控件,这些元素组成一个外表凑合的窗口。这么多组件放到一个容器上最好可以空置组件在容器中的位置,java.awt包中提供了FlowLayout、BorderLayout、CardLayout、GridLayout布局类,具体区别就不介绍了,我们将采用BorderLayout布局。

在MyWindow类中定义组件

Panel pSouth= new Panel();

MenuBar menubar= new MenuBar();

Menu menu1= new Menu("文件"); Menu mn_mode= new Menu(); Menu support= new Menu("技术支持");

MenuItem item1= new MenuItem("退出");

MenuItem mn_mode_1= new MenuItem(); MenuItem mn_mode_2= new MenuItem();

Choice choice= new Choice();

Button button_step= new Button("单步迭代");

Label label_step= new Label("     ");

Label info= new Label("LLC LAB");


在构造方法中添加他们

//设置UI 

setBackground(Color.lightGray);

choice.addItem("牛逼的树");

pSouth.add(choice);

pSouth.add(button_step);

pSouth.add(label_step);

pSouth.add(info);

add(canvas,BorderLayout.CENTER);

add(pSouth,BorderLayout.SOUTH);

//设置menu

this.setMenuBar(menubar);

menubar.add(menu1); menubar.add(mn_mode); menubar.add(support);

menu1.add(item1);

mn_mode.add(mn_mode_1); mn_mode.add(mn_mode_2);

mn_mode.setLabel("生成模式");

mn_mode_1.setLabel("单一规则"); mn_mode_2.setLabel("随机规则");


这样便大功告成了。

3、画图类MyCanvas的中的核心方法

要在画布中画线那必须要有坐标表示方法

//为保存双精度的点而新建一个类

class doublePoint {     

  double x;

  double y;

  doublePoint(double x1,double y1){

    x=x1;y=y1;

  }

}

我们既然已经将指令存储在statement中了那么以此检查字符串数组的每个元素,遇到F就画线,遇到[就将当前状态存储到栈中,遇到]则从栈中取出状态。

for (i=0;i<statement.length();i++) {

        //获取公理中第i个字符,即解释instruction

           c = statement.charAt(i);

if (c=='F') {

               double rad = 2*Math.PI*direction/360 ; // 角度转换

               double p = lengthF * Math.cos(rad);

               double q = lengthF * Math.sin(rad);

               b = new doublePoint(a.x+p, a.y+q);

               //g=this.getGraphics();

               g.drawLine((int)(a.x), (int)(400-a.y), (int)(b.x) ,(int)(400-b.y));

               a = b; // 前一线段的终点为后一线段的起始点            

       }

       else if (c=='+') direction += rotation; //逆时针转角度

       else if (c=='-') direction -= rotation; //顺时针转角度

       else if (c=='[') {  //入栈

           aPoint.addElement(a);

           sDirection = String.valueOf(direction);

           aDirection.addElement(sDirection);

       }

       else if (c==']') {  //出栈

           a=(doublePoint)(aPoint.elementAt(aPoint.size()-1));

           sDirection=(String)(aDirection.elementAt(aDirection.size()-1));

           direction=Double.valueOf(sDirection).doubleValue();

           aPoint.removeElementAt(aPoint.size()-1);

           aDirection.removeElementAt(aDirection.size()-1);

       }

       }

4、全部源码和运行结果

package myFenxing.release;
/**
 * @author Jason 
 * @Corp LLC lab
 * @version LS grammar implementation version1; 菜单和按钮无功能
 */
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.util.Vector;

//为保存双精度的点而新建一个类
class doublePoint {     
  double x;
  double y;
  doublePoint(double x1,double y1){
    x=x1;y=y1;
  }
}
//画布
class MyCanvas extends Canvas{
	String statement;		//LS文法表达式
	int pStartX =320;        //起始点340,20
    int pStartY =20;
    double direction_init =90;  // 作画时的初始方向
    double direction =direction_init;
    double lengthF =4.5;
    double rotation =30;
    int StartDepth =7;     //画图深度
    doublePoint a, b;       // 画线段所需的两点
	MyCanvas(){
		setBackground(Color.black);
	}
	public void setStatement(String s){
		this.statement= s;
	}
	//改变窗口大小的时候会调用此方法重新绘图
	public void paint(Graphics g){
		//System.out.print("\n"+this.statement);
		a = new doublePoint(pStartX,pStartY); // 起始点
		g.setColor(new Color(110,170,60)); // 定义画笔的颜色绿色
		draw(g,this.statement);
	}
	//核心方法
		public void draw(Graphics g, String statement){
	        Vector aPoint = new Vector();//用堆栈记录[]中的内容
	        Vector aDirection = new Vector();
	        String sDirection;

	        int i;
	        char c; 	System.out.print("\ndraw length "+statement.length());
	        for (i=0;i<statement.length();i++) {
	        	//获取公理中第i个字符,即解释instruction
	            c = statement.charAt(i);
				if (c=='F') {
		                double rad = 2*Math.PI*direction/360 ; // 角度转换
		                double p = lengthF * Math.cos(rad);
		                double q = lengthF * Math.sin(rad);
		                b = new doublePoint(a.x+p, a.y+q);
		                //g=this.getGraphics();
		                g.drawLine((int)(a.x), (int)(400-a.y), (int)(b.x) ,(int)(400-b.y));
		                a = b; // 前一线段的终点为后一线段的起始点            
		        }
		        else if (c=='+') direction += rotation; //逆时针转角度
		        else if (c=='-') direction -= rotation; //顺时针转角度
		        else if (c=='[') {  //入栈
		            aPoint.addElement(a);
		            sDirection = String.valueOf(direction);
		            aDirection.addElement(sDirection);
		        }
		        else if (c==']') {  //出栈
		            a=(doublePoint)(aPoint.elementAt(aPoint.size()-1));
		            sDirection=(String)(aDirection.elementAt(aDirection.size()-1));
		            direction=Double.valueOf(sDirection).doubleValue();
		            aPoint.removeElementAt(aPoint.size()-1);
		            aDirection.removeElementAt(aDirection.size()-1);
		        }
	        }System.out.print("\ndraw over;");
		}
}
//窗口
class MyWindow extends Frame implements ActionListener{
	MyCanvas canvas= new MyCanvas();
	//在画布中绘图的起始点340,20
	int pStartX =320;        
    int pStartY =20;
	Panel pSouth= new Panel();
	MenuBar menubar= new MenuBar();
	Menu menu1= new Menu("文件"); Menu mn_mode= new Menu(); Menu support= new Menu("技术支持");
	MenuItem item1= new MenuItem("退出");
	MenuItem mn_mode_1= new MenuItem(); MenuItem mn_mode_2= new MenuItem();
	
	Choice choice= new Choice();		
	Button button_step= new Button("单步迭代");
	Label label_step= new Label("     ");
	Label info= new Label("LLC LAB");
	//LS文法需要的变量
	String statement,replacement;
    String sStart;           //公理;起始字符串
    String sRule[][];        //存储规则
	MyWindow(){
		//默认状态下的公理
		sStart = "F";//给公理赋值
		statement= sStart; replacement= "F[+F]F[-F]F" ;
		
	  	//用来随机抽取,绘制随机植物
	    sRule = new String [10][2];		    
		//设置UI 
		setBackground(Color.lightGray);
		choice.addItem("牛逼的树");
		pSouth.add(choice);
		pSouth.add(button_step);
		pSouth.add(label_step);
		pSouth.add(info);
		add(canvas,BorderLayout.CENTER);
		add(pSouth,BorderLayout.SOUTH);
		//设置menu		
		this.setMenuBar(menubar);		
		menubar.add(menu1); menubar.add(mn_mode); menubar.add(support);
		menu1.add(item1);
		mn_mode.add(mn_mode_1); mn_mode.add(mn_mode_2);
		mn_mode.setLabel("生成模式");
		mn_mode_1.setLabel("单一规则"); mn_mode_2.setLabel("随机规则");
	}
	//响应关闭操作
	protected void processWindowEvent(WindowEvent e) {
        super.processWindowEvent(e);
        if (e.getID() == WindowEvent.WINDOW_CLOSING) {
          System.exit(0);
        }
      }
	//窗口名称
      public synchronized void setTitle(String title) {
        super.setTitle(title);
        enableEvents(AWTEvent.WINDOW_EVENT_MASK);
      }
	@Override
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub		
	}
	public void init() {
		//将计算出的statement传递给画布
		canvas.setStatement(statement);		
		this.setSize(pStartX*2,550);
	    //获得屏幕长和宽,dimension类在一个单一对象中封装组建的宽和高
	    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
	    this.setLocation((d.width - this.getSize().width) / 2, (d.height - this.getSize().height) / 2);
	    this.setVisible(true);  
	}
	/**计算LS表达式*/	//1、直接替换
    public String caluStatement1(int depth){    	
        for(;depth > 0; depth--){
        	String newStatement="";
        	for(int i=0;i< statement.length();i++){
        		if(statement.charAt(i)== 'F') newStatement += replacement;
        		else newStatement += statement.charAt(i);
        		//防止字符串数组爆了,其最大长度取决于字符串在常量池中的存储大小 
        		if(newStatement.length() >= 65534){//2^16-1=65535
        			return newStatement;
        		}	        			
        	}
        	statement = newStatement;
        }
        return statement;
    }
    //2、随机替换
    public String caluStatement2(int depth){
    	//三条规则随机选择	 
    	sRule[0][0]="F";
	    sRule[0][1]="F[+F]F[-F]F" ;
	    sRule[1][0]="F";
	    sRule[1][1]="F[+F[+F]]F[-F]";
	    sRule[2][0]="F";
	    sRule[2][1]="F+F-[-F+F-F][+F-F+F]";
        for(;depth > 0; depth--){
        	String newStatement="";
        	for(int i=0;i< statement.length();i++){
        		replacement= sRule[(int)(Math.random()*3)][1];
        		if(statement.charAt(i)== 'F') newStatement += replacement;
        		else newStatement += statement.charAt(i);
        		//防止字符串数组爆了
        		if(newStatement.length() >= 65534){//2^16-1=65535
        			return newStatement;
        		}
        	}
        	statement = newStatement;
        }
        return statement;
    }

}
/**Main method*/
public class randomLS_V1 {
	public static void main(String args[]){
		MyWindow instance= new MyWindow();
		instance.setTitle("牛逼的树");
		instance.statement= instance.caluStatement2(5);
		instance.init();
	}
}

170013_1Ot2_576429.png

转载于:https://my.oschina.net/SnifferApache/blog/353426

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值