What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:programming:java:courses:gtx_cs1311x:exceptions_ds_rec_gui [2024/01/30 12:52] – [JavaFX] codingharecs:programming:java:courses:gtx_cs1311x:exceptions_ds_rec_gui [2024/01/31 06:05] (当前版本) – [Addtional Operations] codinghare
行 680: 行 680:
   * //Scene//: 内容   * //Scene//: 内容
 {{ :cs:programming:java:courses:gtx_cs1311x:javafx_base_flow.svg?400 |}} {{ :cs:programming:java:courses:gtx_cs1311x:javafx_base_flow.svg?400 |}}
 +===JavaFX essentials===
 +==入口函数的定义==
 +使用 JavaFX 的类会继承自 ''javafx.application.Application''。该类中定义了一个**抽象**入口函数 ''start()''。需要使用 javaFX 的类都需要实现该函数(可以认为是 JavaFX 里的 ''main()''
 +<code js>
 +public class JavaFXTest extends Application {
 +    public void start(Stage mainStage) {
 +    //....
 +    }
 +}
 +</code>
 +==结构总览==
 +  * //Stage//:当前的窗口
 +  * //Scene//:由窗口中的元素以及其布局组成
 +==Events Handling==
 +//Events// 代表了用户的操作。JavaFX 中的 //Event// 继承自是 //ActionEvent//
 +\\ \\ 
 +{{ :cs:programming:java:courses:gtx_cs1311x:javafx_events.jpg?400 |}}
 +\\ \\ 
 +如果需要处理 //Events//,需要实例化对应类型的 //Events//,比如鼠标点击按钮:
 +<code js>
 +btn.setOnAction(new CustomEventHandler());
 +</code>
 +//Events// 的初始化需要 ''EventHandler'' 类型的实例来处理用户执行完操作以后到底会发生什么。为了将 //Events// 与 //Handler// 联系起来,JavaFX规定:
 +  * //Handler// 中必须定义一个 ''handle()'' 函数
 +    * 通过继承接口 ''EventHandler'' 实现。''EventHandler'' 包含了抽象函数  ''handle()'' 
 +    * 用户需要根据 //Event// 的类型决定 ''EventHandler'' 的特化类型(点击鼠标的类型是 ''ActionEvent''
 +比如为点击按钮设置一个名为 ''CustomEventHandler'' 的类:
 +<code js>
 +//CustomEventHandler implements EventHandler
 +//click button action has type ActionEvent
 +private class CustomEventHandler implements EventHandler<ActionEvent> {
 +     
 +    //rewrite handle
 +    //handle parameter has type T to ensure the parameter macting the event type
 +    public void handle(ActionEvent event) {
 +        System.out.println("Hello Wolrd!");
 +    }
 +}
 +</code>
 +当 ''CustomEventHandler'' 定义完毕后,我们将其传递给了 ''setOnActrion()'' 成员方法。该步骤相当于我们将其注册为 //Event Listener//,用于反馈结果给点击按钮的行为。
 +  * ''EventHandler'' 必须是 ''private'' 类型,并且是内部类(//Inner class//)
 +==Panes & Scene Graphs==
 +Panes 为整个 //Stage// 提供布局。其扮演了一个组件容器的角色:
 +<code js>
 +StackPane root = new StackPane();
 +</code>
 +<WRAP center round info 100%>
 +之后创建的组件会叠加到之前创建的组件**上面**。
 +</WRAP>
 +实例化 Pane 之后,我们就可以将之间创建的组件通过 ''getChildren()'' 成员放入该容器中了:
 +<code js>
 +//adding button element to the container
 +root.getChildren().add(btn);
 +</code>
 +Pane 与组件之间的关系是**包含(//contains//)**关系,可以用 //Scene Graphs// 的方式来描述(图中的粗线代表包含):
 +\\ \\ 
 +{{ :cs:programming:java:courses:gtx_cs1311x:scene_graph.jpg |}}
 +\\ 
 +其他可选的 layout 和组件有:
 +\\ \\ 
 +{{ :cs:programming:java:courses:gtx_cs1311x:elements.jpg?400 |}}
 +\\ \\ 
 +  * //Layout// 类别中的类都是 ''StackPane'' 的子类,代表了不同的布局方式。如果没有合适的,可以自己通过继承 ''Pane'' 来自定义布局。参考:[[https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/StackPane.html|文档]]
 +  * 元素组件被称为 ''leaf node''
 +  * //Layout// 本身不必是根部节点,也可以是**分支**节点(嵌套布局)
 +<WRAP center round tip 100%>
 +[[https://docs.oracle.com/javafx/2/layout/builtin_layouts.htm|JavaFX Layouts Example]]
 +</WRAP>
 +
 +===Anonymous Inner Classes===
 +EventHandler 可以用 inner class 的方式实现:
 +<code js>
 +EventHandler<ActionEvent> CustomEventHandler = new EventHandler<>() {
 +    public void handle(ActionEvent event) {
 +        System.out.println("Helloworld");
 +    };
 +};
 +//notice CustomEventHandler is not a cstr. it is an reference name now.
 +btn.setOnAction(CustomEventHandler);
 +<code>
 +如果只使用一次,可以写成匿名的形式直接作为 ''setOnAction()'' 的参数:
 +<code js>
 +btn.setOnAction(
 +    new EventHandler<ActionEvent>() {
 +        public void handle(ActionEvent event) {
 +            System.out.println("hello world");
 +        };
 +    }
 +);
 +</code>
 +===Lambda Expressions===
 +上述的 EventHandler 还可以使用 Lambda 表达式进一步的改进:
 +<code js>
 +btn.setOnAction(event -> System.out.println("helloWorld"));
 +</code>
 +  * ''handle()'' 可以省略,因为 EventHandler 中只有一个函数
 +  * ''ActionEvent'' 也可以省略,Java 可以根据 EventHandler 自动推断类型
 +  * 如果 ''handle()'' 的定义之后一行,连大括号都可以省去
 +===Addtional Operations===
 +<WRAP center round download 100%>
 +{{ :cs:programming:java:courses:gtx_cs1311x:temperatureconvertergui.java |Demo Code}}
 +</WRAP>
 +
 +==ComboBox==
 +  * 定义 ComboBox
 +<code js>
 +ComboBox<String> pickScaleFrom = new ComboBox<>();
 +</code>
 +  * 添加选项到 Combobox
 +<code js>
 +pickScaleFrom.getItems().addAll("Fahrenheit", "Celsius");
 +</code>
 +  * 设定默认选项
 +<code js>
 +pickScaleFrom.getSelectionModel().selectFirst();
 +pickScaleTo.getSelectionModel().selectLast();
 +</code>
 +  * 从 ComboBox 中获取选项值
 +<code js>
 + String scaleFrom = pickScaleFrom.getValue();
 +</code>
 +  * 打印值到 Label 区域
 +<code js>
 + result.setText(String.format("%.2f", conversionResult));
 +</code>
 +==Label==
 +  * 创建 Label
 +<code js>
 +abel from = new Label("From:");
 +</code>
 +==TextField==
 +  * 创建 TextField
 +<code js>
 +TextField userInput = new TextField();
 +</code>
 +  * 获取 TextField 中的内容(in string format)
 +<code js>
 +//userInput is an TextField instance
 +userInput.getCharacters().toString();
 +</code>
 +==Error dialog box==
 +{{ :cs:programming:java:courses:gtx_cs1311x:errorbox.jpg?300 |}}
 +<code js>
 +//define
 +Alert a = new Alert(AlertType.ERROR);
 +//title
 +a.setTitle("Error");
 +//error message
 +a.setHeaderText("Invaild Temperature");
 +//details
 +a.setContentText("That is not a valid tempature");
 +//keeping the dialog box show up, pause the program
 +a.showAndWait();
 +</code>
 +==Layout==
 +  * 创建 Layout
 +<code js>
 +//keep the element in the same row
 +HBox input = new HBox();
 +//
 +VBox scales = new VBox();
 +</code>
 +  * 设置对齐方式:
 +<code js>
 +input.setAlignment(Pos.CENTER);
 +</code>
 +  * 设置间距
 +<code js>
 +scales.setSpacing(10);
 +</code>
 +  * Layout 的嵌套
 +<code js>
 +root.getChildren().addAll(input, scales, convertButton, result);
 +</code>
 +