目录
题目:**18.38 (递归树)
代码示例
代码逻辑解释
类定义和变量初始化
main 方法
start 方法
drawRecursiveTree 方法
输出结果
题目:**18.38 (递归树)
编写一个程序来显示一个递归树,如图18-20所示
-  代码示例
编程练习题18_38RecursionTree.java
package chapter_18;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;
public class 编程练习题18_38RecursionTree extends Application{
	private int order;
	private int size;
	private int canvasWidth;
	private int canvasHeight;
	
	public static void main(String[] args) {
		Application.launch(args);
	}
	@Override
	public void start(Stage primaryStage) throws Exception {
		size = 300;
		canvasWidth = size;
		canvasHeight = size - 50;
		
		Group root = new Group();
		Scene scene = new Scene(root,size,size);
		
		TextField tfOrder = new TextField();
		Label lbOrder = new Label("Enter a umber",tfOrder);
		lbOrder.setContentDisplay(ContentDisplay.RIGHT);
		lbOrder.setAlignment(Pos.CENTER);
		
		BorderPane borderPane = new BorderPane();
		borderPane.setCenter(root);
		borderPane.setBottom(lbOrder);
		BorderPane.setAlignment(lbOrder, Pos.CENTER);
		
		tfOrder.setOnKeyPressed(e ->{
			if(e.getCode() == KeyCode.ENTER) {
				root.getChildren().clear();
				order = Integer.parseInt(tfOrder.getText());
				drawRecursiveTree(root,order,canvasWidth/8,canvasHeight/4,
						canvasHeight*0.24,Math.PI/2);
			}
		});
		scene.setRoot(borderPane);
		primaryStage.setTitle(getClass().getName());
		primaryStage.setScene(scene);
		primaryStage.show();
	}
	private void drawRecursiveTree(Group group,int order,double x,double y,double length,double angle) {
		if(order < 0)
			return;
		double x2 = x + length*Math.cos(angle);
		double y2 = y - length*Math.sin(angle);
		Line line = new Line(x,y,x2,y2);
		line.setStroke(Color.BLACK);
		group.getChildren().add(line);
		drawRecursiveTree(group, order-1, x2, y2, length*0.7, angle-Math.PI/6);
		drawRecursiveTree(group, order-1, x2, y2, length*0.7, angle+Math.PI/6);
	}
}-  代码逻辑解释
类定义和变量初始化
- 类定义:编程练习题18_38RecursionTree类继承自Application,是 JavaFX 应用程序的入口。
- 变量初始化:类中定义了四个私有变量 order(树的阶数),size(窗口大小),canvasWidth(画布宽度),canvasHeight(画布高度)。注意,虽然canvasWidth和canvasHeight被初始化了,但在绘图过程中它们实际上并没有直接被用作限制条件,而是用于计算初始绘图的起始位置和长度。
main 方法
 
- Application.launch(args);:这是 JavaFX 应用程序的标准启动方式,它接收命令行参数并启动应用程序。
start 方法
 
- 初始化窗口大小:size设置为 300 像素,canvasWidth和size相同,canvasHeight设置为size - 50,为底部留出空间放置控件。
- 创建 Group 和 Scene:Group对象root作为所有绘图元素的容器,Scene对象scene设置了窗口的大小,并将root作为其内容。
- 创建用户输入控件:TextField用于接收用户输入的阶数,Label显示提示信息并与TextField关联。Label的内容显示设置为右侧,文本对齐设置为居中(虽然这主要用于水平布局,但在这个垂直布局的BorderPane中可能看起来有些奇怪)。
- 布局设置:使用 BorderPane布局,将root设置为中心区域,Label(包含TextField)设置为底部区域。TextField在BorderPane中直接居中对齐的设置实际上是无效的,因为它被包含在Label中,而Label的对齐方式被设置为居中,但这主要影响的是文本的水平对齐。
- 事件监听:为 TextField设置按键事件监听器,当按下回车键时,清除Group中的所有子元素,解析用户输入的阶数,并调用drawRecursiveTree方法绘制树。
- 设置并显示舞台:将 BorderPane设置为场景的根节点,设置舞台的标题,将场景添加到舞台,并显示舞台。
drawRecursiveTree 方法
 
- 递归逻辑:该方法通过递归调用自身来绘制树的每一级分支。
- 参数:包括 Group对象(用于添加线条)、阶数(order)、当前分支的起点坐标(x,y)、分支的长度(length),以及当前分支的角度(angle)。
- 递归终止条件:如果阶数小于 0,则递归结束。
- 绘制线条:计算当前分支的终点坐标,创建 Line对象,设置其颜色和起点终点坐标,并将其添加到Group中。
- 递归调用:对当前分支的左右两侧进行递归调用,每次递归时减小分支长度并调整角度(左右分支分别减去和加上 Math.PI/6,即 30 度)。
-  输出结果




















