111 - Lecture 10

File I/O and GUI with JavaFX

文件输入/输出与JavaFX图形用户界面

一、Overview

 1. File I/O    

(1) learning Java File I/O mechanism

(2) writing into and reading from a file                使用文件I/O进行数据读取和写入。

2. GUI with JavaFX

(1)drawing shapes and creating graphical user interface    使用JavaFX创建图形界面,绘制形状

(2) practicing OOP with JavaFX

Learning Outcomes

• 能够开发可以通过图形表示或文本菜单与用户交互的程序。

graphical representation, or text-based menus.

• 使用Java编程表示、显示和操作数据作为对象,同时注意相关的风险/安全,确保计算和信息系统的安全操作。

 being cognizant of associated risk/safety for safe operation of computing and information systems.

二、 File I/O (文件输入/输出)

1. File and File Class (文件和文件类)

(1) 程序结束时(terminates,存储在变量中的数据将丢失,因此我们需要将数据保存在文件中,并将文件存储在存储设备上(storage device

(2) 绝对路径(Absolute file name):操作系统(OS)相关,例如在Windows中:

C:\Users\teng.ma\Documents\NetBeansProjects\Lecture10Demo\data\text1.txt

(3)       相对路径(Relative file name):  relative to the current working directory,例如:data\text1.txt

(4) 使用Java中的File对象来表示文件。

        

File file =new File("C:\\Users\\teng.ma\\Documents\\NetBeansProjects\\Lecture10Demo\\data\\text1.txt");

2. File Object

(1)Since OS may vary, do not use absolute file name when creating File objects

(2) Use relative file name in Java (with forward slash) :

File file = new File("data/text1.txt");

(3) creating a File object does not actually create a file on the computer!

3. File Methods (文件方法)

 File类包含用于获取(obtain文件属性的方法,以及重命名和删除文件的方法。

(1) obtain the property of a file/directory

exists(), isFile(), length(), canRead(), canWrite() 

File file = new File("data/text1.txt");
file.exists();
file.isFile();
file.isDirectory();
file.isHidden();
file.length();    //in bytes
file.canRead();
file.canWrite();
file.getAbsolutePath();

(2) rename and delete a file/directory 

delete(), renameTo(File), mkdir()

• exists():检查文件或目录是否存在。

• isFile():检查是否为普通文件。(不是目录)

• isDirectory():检查是否为目录。

• isHidden():检查文件或目录是否为隐藏文件。(隐藏文件用于存储系统配置或操作系统的内部文件,这些文件不应该被普通用户直接访问或修改)

• length():获取文件大小,单位为字节,如果是目录,通常返回 0 或未定义

• canRead():检查文件是否可读。

• canWrite():检查文件是否可写。

• getAbsolutePath():获取文件的绝对路径。

File file = new File("example.txt");

System.out.println("文件的绝对路径:" + file.getAbsolutePath());

• delete():删除文件或目录。(如果是目录,目录必须为空才能删除)

//如果文件或目录成功删除,返回 true;否则返回 false

file.delete()

• renameTo(File):重命名文件或移动文件。

File oldFile = new File("oldName.txt");

File newFile = new File("newName.txt");

if (oldFile.renameTo(newFile)) {

    System.out.println("文件重命名成功。");

} else {

    System.out.println("文件重命名失败。");

}

• mkdir():创建新目录。

File directory = new File("newDirectory");

if (directory.mkdir()) {

    System.out.println("目录创建成功。");

} else {

    System.out.println("目录创建失败。");

}

4. PrintWriter类用于创建文件并将数据写入文本文件(text file)

Key methods in PrintWriter

• flush() 方法的作用是强制将缓冲区中的内容立刻写入到文件。通常,PrintWriter 类会将写入的内容暂时存储在内存中的缓冲区,直到缓冲区满或者文件关闭时,才会将内容实际写入文件。

• print():写入文本,不自动换行;适用于在同一行写入多个文本内容。

• write():写入原始数据,不做格式处理;适合于写入字符、字节等低级数据。

• println(): Prints data followed by a new line.

• close(): Closes the writer and releases the associated resources.

printf(String format, Object... args):允许格式化输出。如:output.printf("Hello, %s!", "World");

PrintWriter writer = new PrintWriter("example.txt");
writer.print("Hello, ");
writer.print("world!");        //输出结果 Hello, world!
writer.flush(); // 强制将内容写入文件
writer.close(); // 关闭流

create a file 

File newFile = new File("data/text2.txt");

if (newFile.exists()) {

        System.out.println("File already exists!");

        System.exit(0);        //exit the program

}

try {

        PrintWriter output = new PrintWriter(newFile);

} catch (IOException ioe) {

System.out.println(ioe.getMessage());

}

write data into a text file

File file = new File("data/text1.txt");

try {

        PrintWriter output = new PrintWriter(file);

        output.println(“CPT111");

        output.println(“is");

        output.println(“so hard");

        output.close();

} catch (IOException ioe) {

        System.out.println(ioe.getMessage());

}

when you’re trying to create a file (e.g., text1.txt) within a folder (e.g., data), you must ensure that the folder (data) already exists.(because Java doesn’t automatically create parent directories for a file unless explicitly told to do so  File folder = new File("data");)

• 在创建文件前,检查文件是否已存在,避免覆盖。(overwriting)

默认情况下,PrintWriter 在每次创建时会 覆盖 文件,这意味着 不会添加更多行,而是 替换 文件中的内容。

5. BufferedWriter to Improve Efficiency 

BufferedWriter 包装 FileWriter

• BufferedWriter将字符串先缓存到内存中,再写入文件,能提高效率。

• 使用flush()方法强制将缓冲区内容(buffered content写入文件。

在 Windows 上,\n 代表换行,但标准换行符是 \r\n,而在 Linux/macOS 上,\n 就是标准的换行符。

• buffer.newLine() 方法是为了跨平台的兼容性,它会自动根据操作系统的要求插入正确的换行符。

try {

FileWriter file = new FileWriter("data/text1.txt");

BufferedWriter buffer = new BufferedWriter(file);

buffer.write(“CPT111");

buffer.newLine();

buffer.write(“is");

buffer.newLine();

buffer.flush();        //otherwise write until buffer is full or closed

buffer.write(“so hard");

buffer.newLine();

buffer.close();

} catch (IOException ioe) {

System.out.println(ioe.getMessage());

}

• BufferedWriter 主要用于高效写入字符流,提供了一个缓冲机制,它不会自动添加换行符,除非显式调用 newLine() 方法。

• BufferedReader一次性(in one将文件内容读取到内存中,之后可以高效地访问。

• PrintWriter 提供了更多便捷的写入方法,例如 println()、printf() 等。它不仅可以写入普通文本,还能格式化输出并自动添加换行符。

• BufferedWriter 和 PrintWriter 都需要包装一个底层 Writer(如 FileWriter)才能完成文件写入,而 FileWriter 是可以单独使用的。

PrintWriter 封装 BufferedWriter 是可以覆盖 FileWriter 的功能

6. Scanner

(1)Reading  text Data Using Scanner 

• 使用Scanner逐行(line by line读取文本文件内容。

nextLine():读取整行输入,包括空格,直到遇到换行符。

next():读取下一个词,遇到空格或者换行符会停止。

nextInt():读取一个整数,输入必须是合法的整数字符串。

nextDouble():读取一个双精度浮点数。

hasNext():检查是否有更多的输入数据(一个词)。

hasNextInt():检查是否有下一个整数。

hasNextDouble():检查是否有下一个双精度浮点数。

File file = new File("data/text1.txt");

try {

        Scanner input = new Scanner(file);

        while (input.hasNextLine()) {

                String line = input.nextLine();

                System.out.println(line);

}

        input.close();

} catch (IOException ioe) {

        System.out.println(ioe.getMessage());

}

(2)Reading csv data using Scanner

• 从CSV(comma-separated values)文件中读取数据,使用split(",")来分割(extract)每行的内容。

create a Scanner for the file, extract the values by first splitting them

File file = new File("data/cpt111.csv");

try {

        Scanner input = new Scanner(file);

        while (input.hasNextLine()) {

                String line = input.nextLine();

                String[] values = line.split(",");

                String module = values[0];

                int grade = Integer.parseInt(values[1]);

                System.out.println(“Component: " + module + " Grade: " + 

grade);

        }

        input.close();

} catch (IOException ioe) {

        System.out.println(ioe.getMessage());

}

• split 方法: String 类中的 split 方法用于根据指定的分隔符(这里是 ",")将字符串拆分为子字符串,并返回一个字符串数组。

7. Improve efficiency using BufferedReader

File file = new File("data/text1.txt");

try {

        FileReader fileReader = new FileReader(file);

        BufferedReader reader = new BufferedReader(fileReader);

        String line;

        while ((line = reader.readLine()) != null) {

                System.out.println(line);

        }

        reader.close();

} catch (IOException ioe) {

        System.out.println(ioe.getMessage());

}

没有修饰符的情况:在方法内部定义的局部变量(local variables)不需要修饰符。它们的生命周期仅限于方法内部。而成员变量(定义在类中的变量)通常需要修饰符来决定其访问权限。

三、GUI with JavaFX (Graphical User Interface)

1. JavaFX Basics 

• JavaFX是替代Swing和AWT(Abstract Windows Toolkit)的图形用户界面框架。

JavaFX is the new GUI framework 

• JavaFX的优势:支持面向对象的编程,使用Stage、Scene和Node组织图形界面。

 Stage (top-level container), Scene (holds nodes), and Node (visual components:buttons, images, panes, and shapes).

Node can contain other nodes 

2. JavaFX程序的基本结构

import javafx.application.Application;

import javafx.stage.Stage;

import javafx.scene.Scene;

import javafx.scene.control.Button;

public class JavaFXTesting extends Application { 

// 定义类 JavaFXTesting,并继承 Application 类,表明这是一个 JavaFX 应用程序。

    @Override

    public void start(Stage primaryStage) { 

    // 重写 Application 类的 start 方法。该方法是 JavaFX 应用程序的入口点,负责设置和展示 UI。

    

        Button helloButton = new Button("Hello World!");

        // 创建一个 Button 对象,并设置按钮显示的文本为 "Hello World!"。

        

        Scene scene = new Scene(helloButton, 200, 250); 

        // 创建一个 Scene 对象,指定场景的根节点为按钮 helloButton,并设置场景的宽度为 200,高度为 250。

        

        primaryStage.setTitle("My First JavaFX Program");

        // 设置窗口标题为 "My First JavaFX Program"。

        

        primaryStage.setScene(scene);

        // 将场景 scene 设置为主舞台(窗口)的场景。

        

        primaryStage.show();

        // 显示主舞台,即打开窗口并展示 UI。

    }

    public static void main(String[] args) {

    // 主方法,程序入口点。

        launch(args); 

        // 启动 JavaFX 应用程序,会调用 start 方法。

    }

}

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

public class JavaFXExample extends Application {
    @Override
    public void start(Stage primaryStage) {
        // 创建按钮
        Button button = new Button("Click Me");
        button.setOnAction(e -> System.out.println("Button was clicked!"));

        // 创建场景
        Scene scene = new Scene(button, 300, 200);
        scene.setFill(javafx.scene.paint.Color.LIGHTBLUE);

        // 设置主舞台
        primaryStage.setTitle("JavaFX Example");
        primaryStage.setScene(scene);
        primaryStage.setWidth(400);
        primaryStage.setHeight(300);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

 

当 JavaFX 应用程序调用 launch(args) 时,它会将 main 方法接收到的命令行参数传递给 launch 方法,以便 JavaFX 应用程序在初始化时使用这些参数。 

button.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent e) {
        System.out.println("Button clicked!");
    }
});

e 是事件对象,类型为 ActionEvent,它表示由按钮点击产生的事件。

e -> System.out.println("Button clicked!") 是一个 Lambda 表达式,表示一个匿名函数。它是 EventHandler<ActionEvent> 接口的实现。 

 

 

(1)Stage and Scene 

• Stage是窗口对象,Scene包含要显示的内容。

a Stage object called primary stage is automatically created by JVM when the application is launched

• Scene通过构造函数创建,并设置宽高和节点。

Scene objects are created by Scene(node, width, height)

Panes and Group

Pane 是一个容器,可以设置子节点的位置和大小。Place nodes inside a Pane

Group 是一个简单的节点集合,可以将多个节点组合在一起。

Parent 提供了许多方便的方法,让管理节点变得简单:

• getChildren():获取容器内的所有子节点。

• add(Node child):向容器中添加子节点。

• remove(Node child):从容器中移除子节点。

• getBoundsInParent():获取子节点在父容器中的边界信息。

Parent 的子类(如 Pane、HBox、VBox)提供了适应不同需求的布局方式:

• VBox:让节点垂直排列。

• HBox:让节点水平排列。

• StackPane:让节点堆叠在一起。

 

Parent 是一种特殊的 Node,它可以包含子节点,是容器类的基类。

实心菱形:聚合关系(Composition): 表示 “整体-部分” 的强依赖关系。 

• Scene 到 Parent 的实心菱形

• Scene 是整体,而 Parent(或者具体的根节点,例如 Pane 或 Group)是它的部分。

• 这意味着一个 Scene 必须包含一个根节点(Parent 类型)。

• 如果 Scene 被销毁,它的根节点也会随之销毁。

空心菱形:关联关系(Aggregation)​​​​​​​: 表示 “整体-部分” 的弱依赖关系。

• Parent 到 Node 的空心菱形

• Parent 是整体,Node 是它的部分。

• 一个 Parent(如 Pane 或 Group)可以包含多个 Node 子节点。

• 但是,Node 可以独立于 Parent 存在,比如创建一个 Button,不一定非要马上加入到 Parent 中。

Button in a Pane

在一个 StackPane 中放置一个按钮。

• StackPane 是一个简单的布局容器,会将子节点堆叠起来,并默认将它们放置在容器中心。

   @Override
    public void start(Stage primaryStage) { 
        // 重写 start 方法,设置 JavaFX 程序的初始内容
        StackPane pane = new StackPane(); 
        // 创建一个 StackPane 对象,用于布局子节点
        pane.getChildren().add(new Button("OK")); 
        // 向 StackPane 中添加一个按钮,按钮的文字是 "OK"
        Scene scene = new Scene(pane, 200, 50); 
        // 创建一个 Scene 场景对象,将 StackPane 作为根节点,设置宽度 200,高度 50
        primaryStage.setTitle("Button in a Pane"); 
        // 设置主窗口的标题为 "Button in a Pane"
        primaryStage.setScene(scene); 
        // 将场景设置到主窗口
        primaryStage.show(); 
        // 显示主窗口
    }
    public static void main(String[] args) {
        launch(args); 
        // 启动 JavaFX 应用程序,会自动调用 start 方法
    }
}
 

Circle

在 Pane 中放置一个圆形(Circle)。

• 圆形的属性如 中心点 和 半径 可以通过方法设置。

注意:窗口大小调整后,圆形的位置不会自动调整。

public class ShowCircle extends Application {
    @Override
    public void start(Stage primaryStage) {  // 重写 start 方法
        Circle circle = new Circle();    // 创建一个 Circle 对象
        circle.setCenterX(100); // 设置圆心的 X 坐标为 100
        circle.setCenterY(100);     // 设置圆心的 Y 坐标为 100
    
        circle.setRadius(50);     // 设置圆的半径为 50
        
        circle.setStroke(Color.BLACK);     // 设置圆的边框颜色为黑色
     
        circle.setFill(Color.WHITE);  // 设置圆的填充颜色为白色
 
        Pane pane = new Pane();  // 创建一个 Pane 容器
     
        pane.getChildren().add(circle);     // 将圆形添加到 Pane 容器中
 
        Scene scene = new Scene(pane, 200, 200);  // 创建一个场景,将 Pane 设置为根节点,宽度和高度均为 200
   
        primaryStage.setTitle("ShowCircle");   // 设置主窗口的标题
      
        primaryStage.setScene(scene);         // 将场景设置到主窗口
   
        primaryStage.show();  // 显示主窗口
    }
    public static void main(String[] args) {
        launch(args); 
        // 启动 JavaFX 应用程序
    }
}

Java Coordinate System

Java coordinate system is measured in pixels, with (0, 0) at its upper-left corner

Property Binding to Center Circle on Resizing

• 将 Circle 的中心点(centerX 和 centerY)与容器的宽度和高度绑定。

• 当窗口大小改变时,圆形会保持居中。

public class ShowCircleCentered extends Application {
    @Override
    public void start(Stage primaryStage) {

        Pane pane = new Pane();  // 创建一个 Pane 容器

        Circle circle = new Circle();     // 创建一个 Circle 对象

        circle.centerXProperty().bind(pane.widthProperty().divide(2)); 
        // 将圆心的 X 坐标绑定到 Pane 的宽度的一半

        circle.centerYProperty().bind(pane.heightProperty().divide(2)); 
        // 将圆心的 Y 坐标绑定到 Pane 的高度的一半

        circle.setRadius(50);

        circle.setStroke(Color.BLACK); //设置圆的边框颜色

        circle.setFill(Color.WHITE);     // 设置圆的填充颜色为白色

        pane.getChildren().add(circle);   // 将圆形添加到 Pane 容器中

        Scene scene = new Scene(pane, 200, 200);  //创建一个场景,将 Pane 设置为根节点

        primaryStage.setTitle("ShowCircleCentered");         // 设置主窗口的标题
        primaryStage.setScene(scene);         // 将场景设置到主窗口
        primaryStage.show(); 
    }

    public static void main(String[] args) {
        launch(args); 
        // 启动 JavaFX 应用程序
    }
}

Color

 Color 类用于创建和管理颜色。

• 颜色可以通过 RGBA(红、绿、蓝、透明度)模型或预定义的标准颜色常量表示。

RGBA 模型:

• R(红色),G(绿色),B(蓝色):from 0.0 (darkest) to 1.0 (lightest)

• A(透明度):0.0 完全透明,1.0 完全不透明。

• 示例:Color color = new Color(0.25, 0.14, 0.333, 0.51);

标准颜色常量:

• Color 类提供了一些预定义的常量,例如 RED, GREEN, BLUE 等。

• 使用示例:circle.setFill(Color.RED);

Font, Label and StackPane

Font is defined by its name, weight, posture, and size; and is set on a Label object

A StackPane object is used to contain a circle and a label

// 创建 StackPane 容器
Pane pane = new StackPane();

// 创建圆形并设置属性
Circle circle = new Circle();
circle.setRadius(50); // 圆的半径为 50
circle.setStroke(Color.BLACK); // 边框颜色为黑色
circle.setFill(new Color(0.5, 0.5, 0.5, 0.1)); // 填充颜色为灰色(带透明度)
pane.getChildren().add(circle); // 将圆形添加到 StackPane 中

// 创建标签并设置属性
Label label = new Label("JavaFX");
label.setFont(Font.font("Times New Roman", FontWeight.BOLD, FontPosture.ITALIC, 20)); 
// 设置字体为 Times New Roman,粗体,斜体,大小为 20
pane.getChildren().add(label); // 将标签添加到 StackPane 中

// 创建场景并设置到舞台
Scene scene = new Scene(pane);
primaryStage.setTitle("FontDemo"); // 设置窗口标题
primaryStage.setScene(scene); // 将场景设置到舞台
primaryStage.show(); // 显示窗口

Font

• 字体可以通过名称(如 "Times New Roman")、粗细(FontWeight)、样式(FontPosture)和大小来定义。

• 使用 Font.font() 方法设置字体。

 Label

• Label 是一种控件,用于显示文本内容。

• 可以通过 setFont() 方法设置字体样式。

 

Image and ImageView

Image class loads an image; ImageView is a node for displaying image

An HBox is a pane that places all nodes horizontally in one row

1. Image 类

• 用于加载图像文件。

• 示例:Image image = new Image("path/to/image.jpg");

2. ImageView 类

• 用于显示 Image 对象。

• 提供属性设置:

• setFitWidth() 和 setFitHeight():设置图像显示的宽度和高度。

• setRotate():设置图像的旋转角度。

3. HBox 布局

• HBox 是一个布局容器,将所有子节点水平排列。

// 创建 HBox 容器并设置边距
Pane pane = new HBox(10); // HBox 容器,子节点间距为 10
pane.setPadding(new Insets(5, 5, 5, 5)); // 设置容器的边距

// 加载图像
Image image = new Image("image/us.gif");

// 添加原始图像
pane.getChildren().add(new ImageView(image)); 

// 设置大小后添加图像
ImageView imageView2 = new ImageView(image);
imageView2.setFitHeight(100); // 设置图像高度
imageView2.setFitWidth(100);  // 设置图像宽度
pane.getChildren().add(imageView2);

// 设置旋转后添加图像
ImageView imageView3 = new ImageView(image);
imageView3.setRotate(90); // 设置图像旋转 90 度
pane.getChildren().add(imageView3);

// 创建场景并显示
Scene scene = new Scene(pane);
primaryStage.setTitle("ShowImage"); // 设置窗口标题
primaryStage.setScene(scene); // 设置场景
primaryStage.show(); // 显示窗口

Layout Panes

Pane 类:提供 getChildren() 方法来管理子节点。

Shapes

Shapes 是 JavaFX 中用于绘制图形的节点:

• 包括:Text(文本)、Line(线条)、Rectangle(矩形)、Circle(圆形)、Ellipse(椭圆)、Arc(弧形)、Polygon(多边形)、Polyline(折线)

 fill:

• 设置形状内部的填充颜色。interior of a shape

• 示例:circle.setFill(Color.RED);

 stroke:

• 设置形状边框的颜色。outline of a shape

• 示例:rectangle.setStroke(Color.BLACK);

strokeWidth:

• 设置边框的宽度。

• 示例:line.setStrokeWidth(2);

(1) Text

Text 类用于在指定的起始位置 (x, y) 绘制字符串

• 可以设置字体、颜色、下划线、删除线等样式。

• Text 是 Shape 的一个子类。

// 创建 Pane 容器并设置内边距
Pane pane = new Pane();
pane.setPadding(new Insets(5, 5, 5, 5));

// 添加第一个文本节点
Text text1 = new Text(20, 20, "Programming is fun"); // 起点 (20, 20)
text1.setFont(Font.font("Courier", FontWeight.BOLD, FontPosture.ITALIC, 15)); // 设置字体
pane.getChildren().add(text1);

// 添加第二个文本节点
Text text2 = new Text(60, 60, "Programming is fun\nDisplay text"); // 包含换行符
pane.getChildren().add(text2);

// 添加第三个文本节点,并设置更多样式
Text text3 = new Text(10, 100, "Programming is fun\nDisplay text");
text3.setFill(Color.RED); // 设置填充颜色
text3.setUnderline(true); // 设置下划线
text3.setStrikethrough(true); // 设置删除线
pane.getChildren().add(text3);

// 创建场景并设置到舞台
Scene scene = new Scene(pane);
primaryStage.setTitle("ShowText"); // 设置窗口标题
primaryStage.setScene(scene);
primaryStage.show(); // 显示窗口

 

(2) Line

Line 类用于绘制一条连接两点 (startX, startY) 和 (endX, endY) 的直线

• 提供属性绑定功能,可根据容器的宽高动态调整。

public class ShowLine extends Application {
    @Override
    public void start(Stage primaryStage) {
        // 创建场景并设置到舞台
        Scene scene = new Scene(new LinePane(), 200, 200); // 使用自定义 Pane
        primaryStage.setTitle("ShowLine");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

// 自定义 Pane 类,绘制两条对角线
class LinePane extends Pane {
    public LinePane() {
        // 第一条线
        Line line1 = new Line(10, 10, 10, 10); // 起点和终点初始相同
        line1.endXProperty().bind(widthProperty().subtract(10)); // 动态绑定宽度
        line1.endYProperty().bind(heightProperty().subtract(10)); // 动态绑定高度
        line1.setStrokeWidth(5); // 设置边框宽度
        line1.setStroke(Color.GREEN); // 设置颜色
        getChildren().add(line1);

        // 第二条线
        Line line2 = new Line(10, 10, 10, 10);
        line2.startXProperty().bind(widthProperty().subtract(10)); // 动态绑定起点宽度
        line2.endYProperty().bind(heightProperty().subtract(10)); // 动态绑定终点高度
        line2.setStrokeWidth(5);
        line2.setStroke(Color.GREEN);
        getChildren().add(line2);
    }
}

 

 

(3)Rectangle

Rectangle 类用于绘制矩形

• 提供属性:x, y(左上角坐标),width(宽度),height(高度),arcWidth(圆角宽度),arcHeight(圆角高度)。

 

// 创建矩形并设置属性
Rectangle r1 = new Rectangle(25, 10, 60, 30); // 左上角 (25, 10),宽 60,高 30
r1.setStroke(Color.BLACK); // 设置边框颜色
r1.setFill(Color.WHITE); // 设置填充颜色

Rectangle r2 = new Rectangle(25, 50, 60, 30); // 第二个矩形
Rectangle r3 = new Rectangle(25, 90, 60, 30);
r3.setArcWidth(15); // 设置圆角宽度
r3.setArcHeight(25); // 设置圆角高度

// 创建组容器并添加节点
Group group = new Group();
group.getChildren().addAll(new Text(10, 27, "r1"), r1,
                           new Text(10, 67, "r2"), r2,
                           new Text(10, 107, "r3"), r3);

// 动态生成旋转的矩形
for (int i = 0; i < 4; i++) {
    Rectangle r = new Rectangle(100, 50, 100, 30);
    r.setRotate(i * 360 / 8); // 设置旋转角度
    r.setStroke(Color.color(Math.random(), Math.random(), Math.random())); // 随机颜色
    r.setFill(Color.WHITE); // 设置填充颜色
    group.getChildren().add(r);
}

// 创建场景并设置到舞台
Scene scene = new Scene(new BorderPane(group), 250, 150);
primaryStage.setScene(scene);
primaryStage.setTitle("ShowRectangle");
primaryStage.show();

line1.endXProperty().bind(widthProperty().subtract(10));

• endXProperty() 方法

• 是 Line 类的一个方法,用于获取该直线的终点 X 坐标属性。

• 返回值是一个 DoubleProperty,可以进行动态绑定。

• bind() 方法

• 是 Property 接口中的方法,用于将一个属性绑定到另一个属性。

绑定效果:

• 如果被绑定的属性发生变化(例如容器宽度变了),当前属性会自动更新。

• widthProperty() 方法

• 是 Pane 类的一个方法,返回容器的宽度属性。

• 通过绑定 widthProperty(),可以使线段的终点 X 坐标随容器宽度动态变化。

• subtract(10) 方法

• 是 NumberExpression 类中的方法,用于对数值表达式进行计算。

• widthProperty().subtract(10) 表示容器宽度减去 10 像素。

Scene scene = new Scene(new BorderPane(group), 250, 150);

• new BorderPane(group):

• 创建了一个 BorderPane 对象,并将 Group 设置为其中心区域的内容

pane.setPadding(new Insets(5, 5, 5, 5));

• setPadding() 方法

• 是 Pane 类 提供的方法,用于设置容器的内边距(Padding)。

• 内边距是指容器的边框与内部子节点之间的距离。

• Insets 类

• Insets(double top, double right, double bottom, double left):

• 构造方法,用于分别指定容器四个方向的边距值。

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/921049.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【架构】主流企业架构Zachman、ToGAF、FEA、DoDAF介绍

文章目录 前言一、Zachman架构二、ToGAF架构三、FEA架构四、DoDAF 前言 企业架构&#xff08;Enterprise Architecture&#xff0c;EA&#xff09;是指企业在信息技术和业务流程方面的整体设计和规划。 最近接触到“企业架构”这个概念&#xff0c;转念一想必定和我们软件架构…

vue3:使用插件递归组件

vue3:使用插件递归组件 首先安装插件 npm i unplugin-vue-define-optionsvite.config.ts 配置插件 // vite.config.ts// 引入 unplugin-vue-define-options import DefineOptions from "unplugin-vue-define-options"; export default defineConfig({// 注册插件 De…

开源远程桌面工具:RustDesk

在远程办公和远程学习日益普及的今天&#xff0c;我们经常需要远程访问办公电脑或帮助他人解决电脑问题。 市面上的远程控制软件要么收费昂贵&#xff0c;要么需要复杂的配置&#xff0c;更让人担心的是数据安全问题。 最近我发现了一款名为 RustDesk 的开源远程桌面工具&…

springboot整合hive

springboot整合hive pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.…

ChatGPT 与其他 AI 技术在短视频营销中的技术应用与协同策略

摘要&#xff1a; 本文深入探讨了 ChatGPT 及其他 AI 技术在短视频营销中的应用。从技术层面剖析了这些技术如何助力短视频内容创作、个性化推荐、用户互动以及营销效果评估等多方面&#xff0c;通过具体方法分析、数据引用与大模型工具介绍&#xff0c;旨在为短视频营销领域提…

国土安全部发布关键基础设施安全人工智能框架

美国国土安全部 (DHS) 发布建议&#xff0c;概述如何在关键基础设施中安全开发和部署人工智能 (AI)。 https://www.dhs.gov/news/2024/11/14/groundbreaking-framework-safe-and-secure-deployment-ai-critical-infrastructure 关键基础设施中人工智能的角色和职责框架 https:/…

xtu oj 前缀和

样例输入 3 3 2 1 2 3 1 2 3 2 1 2 3 -1 -2 3 3 -4 3 1 4 2 1 样例输出 0 3 3 解题思路&#xff1a;排序前缀和二分查找 因为数组b是可以插入到数组a任意位置&#xff0c;要想k最大&#xff0c;就要尽可能把b的小数插到a数组的前面。所以&#xff0c;用qsort方法对数组b进…

Nexus搭建go私有仓库,加速下载go依赖包

一、搭建go私库 本文我们梳理一下go依赖包的私库搭建以及使用。 它只分为proxy和group两种仓库&#xff0c;这一点和maven仓库有所不同。 1、创建Blob Stores 为了区分不同的私库依赖包&#xff0c;存储的位置分隔开。 2、新建go proxy官网 Remote storage&#xff1a;htt…

CPU算法分析LiteAIServer摄像机实时接入分析平台固废检测算法助力环保

随着城市化进程的加速和工业化发展的不断深入&#xff0c;固体废弃物的处理问题逐渐成为了一个全球性的挑战。传统的固废检测方法主要依赖于人工巡查和抽样检测&#xff0c;这种方式不仅效率低下&#xff0c;而且难以实现对固体废弃物的全面覆盖和实时监测。为了解决这一问题&a…

国内镜像android studio

Android SDK在线更新镜像服务器 1.中国科学院协会镜像站: 部分地区无法使用 ◦IPV4/IPV6: mirrors.opencas.cn 端口&#xff1a;80 ◦IPV4/IPV6: mirrors.opencas.org 端口&#xff1a;80 ◦IPV4/IPV6: mirrors.opencas.ac.cn 端口&#xff1a;80 2.上海GDG镜像服务器地址…

Ubuntu上安装MySQL并且实现远程登录

目录 下载网络工具 查看网络连接 更新系统软件包&#xff1b; 安装mysql数据库 查看mysql数据库状态 以数字ip形式显示mysql的监听状态。&#xff08;默认监听端口是3306&#xff09; 查看安装mysql数据库时系统创建的目录信息。 根据查询到的系统用户名以及随机密码&a…

从零开始认识显卡

显卡&#xff08;GPU&#xff0c;全称为Graphics Processing Unit&#xff09;&#xff0c;是电脑中专门负责图形处理的硬件组件。以下是从零开始认识显卡的简单介绍&#xff1a; 1. 显卡的基本组成 显卡通常由以下几个主要部分组成&#xff1a; GPU核心&#xff1a;显卡的“…

mac安装Pytest、Allure、brew

安装环境 安装pytest 命令 pip3 install pytest 安装allure 命令&#xff1a;brew install allure 好吧 那我们在安装allure之前 我们先安装brew 安装brew 去了官网复制了命令 还是无法下载 如果你们也和我一样可以用这个方法哦 使用国内的代码仓库来执行brew的安装脚本…

【Vue】 npm install amap-js-api-loader指南

前言 项目中的地图模块突然打不开了 正文 版本太低了&#xff0c;而且Vue项目就应该正经走项目流程啊喂&#xff01; npm i amap/amap-jsapi-loader --save 官方说这样执行完&#xff0c;就这结束啦&#xff01;它结束了&#xff0c;我还没有&#xff0c;不然不可能记录这篇文…

三极管工作原理,以及小电流,如何驱动大电流

因为研究【自动下载电路实现】&#xff0c;涉及到三极管内容&#xff0c;之前看过&#xff0c;现在回看之前的笔记&#xff0c;一点印象都没了&#xff0c;于是&#xff0c;想了个办法&#xff0c;记住它 个人联想&#xff0c;不喜绕道&#xff0c;只是帮助个人记忆的 标题也是…

一文了解倾斜摄影

倾斜摄影是通过从一个垂直、四个倾斜、五个不同的视角同步采集影像&#xff0c;获取到丰富的建筑物顶面及侧视的高分辨率纹理。它不仅能够真实地反映地物情况&#xff0c;高精度地获取物方纹理信息&#xff0c;还可通过先进的定位、融合、建模等技术&#xff0c;生成真实的三维…

浅谈,华为切入具身智能赛道

近期&#xff0c;全球具身智能大模型&#xff08;机器人“通用大脑”&#xff09;赛道热闹非凡&#xff0c;科技大厂、初创公司接连发布重磅消息。 国外&#xff1a; 10月底&#xff0c;美国科技巨头【Meta】旗下基础人工智能研究 &#xff08;FAIR&#xff09;公布公司触摸感…

Spring |(二)IOC相关内容 | bean

文章目录 &#x1f4da;bean基础配置&#x1f407;bean的id和class&#x1f407;bean的name属性&#x1f407;bean作用范围scope配置&#x1f407;bean基础配置小结 &#x1f4da;bean实例化&#x1f407;构造方法实例化&#xff08;常用&#xff09;&#x1f407;静态工厂实例…

网络安全-企业环境渗透2-wordpress任意文件读FFmpeg任意文件读

一、 实验名称 企业环境渗透2 二、 实验目的 【实验描述】 操作机的操作系统是kali 进入系统后默认是命令行界面 输入startx命令即可打开图形界面。 所有需要用到的信息和工具都放在了/home/Hack 目录下。 本实验的任务是通过外网的两个主机通过代理渗透到内网的两个主机。…

Java 对象头、Mark Word、monitor与synchronized关联关系以及synchronized锁优化

1. 对象在内存中的布局分为三块区域&#xff1a; &#xff08;1&#xff09;对象头&#xff08;Mark Word、元数据指针和数组长度&#xff09; 对象头&#xff1a;在32位虚拟机中&#xff0c;1个机器码等于4字节&#xff0c;也就是32bit&#xff0c;在64位虚拟机中&#xff0…