《Java黑皮书基础篇第10版》 第15章【笔记】

第十五章 事件驱动编程和动画

15.1 引言

一个简单的例子

package com.example.demo;

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;

public class Test extends Application {
    @Override 
    public void start(Stage primaryStage) {
        HBox pane = new HBox(10);
        pane.setAlignment(Pos.CENTER);
        Button btOK = new Button("OK");
        Button btCancel = new Button("Cancel");
        // 当单击OK按钮的时候,将显示消息“OK button clicked”。当单击Cancel按钮的时候,将显示消息“Cancel button clicked”
        OKHandlerClass handler1 = new OKHandlerClass();
        btOK.setOnAction(handler1);
        CancelHandlerClass handler2 = new CancelHandlerClass();
        btCancel.setOnAction(handler2);
        pane.getChildren().addAll(btOK, btCancel);

       
        Scene scene = new Scene(pane);
        primaryStage.setTitle("HandleEvent"); 
        primaryStage.setScene(scene); 
        primaryStage.show();
    }
}

// 下面的代码定义了2个处理类,每个处理类都实现了EventHandler<ActionEvent>接口并覆写了handle方法来处理事件
class OKHandlerClass implements EventHandler<ActionEvent> {
    @Override
    public void handle(ActionEvent e) {
        System.out.println("OK button clicked");
    }
}

class CancelHandlerClass implements EventHandler<ActionEvent> {
    @Override
    public void handle(ActionEvent e) {
        System.out.println("Cancel button clicked");
    }
}
15.2 事件和事件源
15.2.1 解释

事件源类似于一个JavaFX的节点,是一个可供操作的用户界面控件,如按钮、文本框、菜单等

事件是从事件源产生的,用来执行一个命令,如单击按钮,输入文本框等。事件对象是一个具体的事件类的实例,例如ActionEvent类、MouseEvent类、KeyEvent类等

在事件下达指令后,由事件处理器进行处理,来实现某些功能,例如,单击按钮以暂停/重启程序

15.2.2 事件处理器

一个类想成为事件处理器,需要同时满足2个条件:

第一,这个类必须实现统一的处理器接口EventHandler(或者其他对应的事件处理接口),并覆写抽象方法handle()

第二,必须使用代码来注册一个源对象,例如

// button是源对象,setOnAction是事件,EnlargeHandler是处理器
button.setOnAction(new EnlargeHandler());
15.2.3 图解

在这里插入图片描述

15.3 注册处理器和处理事件
package com.example.demo;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

// 代码实现:通过按钮点按,圆就会放大或缩小
public class ControlCircle extends Application {
    // 创建一个字段circlePane,类型是CirclePane,这样,circlePane就可以调用CirclePane类的方法了
    // 需要注意的是,CirclePane是一个面板,继承了StackPane,根据代码,调用了CirclePane的无参构造方法,就意味着CirclePane中添加了一个半径是50的圆
    private CirclePane circlePane = new CirclePane();

    @Override
    public void start(Stage primaryStage) {
        // 生成两个按钮
        HBox hBox = new HBox();
        hBox.setSpacing(10);
        hBox.setAlignment(Pos.CENTER);
        Button btEnlarge = new Button("Enlarge");
        Button btShrink = new Button("Shrink");
        hBox.getChildren().add(btEnlarge);
        hBox.getChildren().add(btShrink);

        // 当用户点击按钮时,下面的代码就会调用setOnAction方法,参数是内部类
        // 在内部类中,会自动执行handle()方法,进行半径的扩大或缩小
        btEnlarge.setOnAction(new EnlargeHandler());
        btShrink.setOnAction(new ShrinkHandler());

        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(circlePane);
        borderPane.setBottom(hBox);
        BorderPane.setAlignment(hBox, Pos.CENTER);

        Scene scene = new Scene(borderPane, 200, 150);
        primaryStage.setTitle("ControlCircle"); // Set the stage title
        primaryStage.setScene(scene); // Place the scene in the stage
        primaryStage.show(); // Display the stage
    }

    class EnlargeHandler implements EventHandler<ActionEvent> {
        @Override // Override the handle method
        public void handle(ActionEvent e) {
            // circlePane的实际类型是CirclePane,所以可以调用这个方法
            circlePane.enlarge();
        }
    }

    class ShrinkHandler implements EventHandler<ActionEvent> {
        @Override // Override the handle method
        public void handle(ActionEvent e) {
            circlePane.shrink();
        }
    }
}

class CirclePane extends StackPane {
    private Circle circle = new Circle(50);

    public CirclePane() {
        getChildren().add(circle);
        circle.setStroke(Color.BLACK);
        circle.setFill(Color.WHITE);
    }

    // 更新属性
    public void enlarge() {
        circle.setRadius(circle.getRadius() + 2);
    }

    // 更新属性
    public void shrink() {
        circle.setRadius(circle.getRadius() > 2 ?
                circle.getRadius() - 2 : circle.getRadius());
    }
}
15.4 内部类

一个内部类被编译成一个名为OuterClass$InnerClass的类,例如,Test中的内部类A被编译成Test$A.class

一个内部类可以引用定义在它外部类中的数据和方法。所以,你没有必要将外部类对象的引用传递给内部类的构造方法

一个内部类可以使用可见性修饰符所定义

一个内部类可以被定义为 static

15.5 匿名内部类处理器

在注册事件的时候,先写出注册事件的语句,然后再调用内部类EnlargeHandler()的构造方法比较麻烦

btEnlarge.setOnAction(new EnlargeHandler());

class EnlargeHandler implements EventHandler<ActionEvent> {
        @Overrid
        public void handle(ActionEvent e) {
            circlePane.enlarge();
        }
}

为了简化代码使用,可以不显示声明EnlargeHandler类,而是变成一个匿名内部类。在内部类中,只保留new操作符和实现的接口,然后在类中写下要实现的代码即可

btEnlarge.setOnAction(new EventHandler<ActionEvent>() {
	@Override
  public void handle(ActionEvent e) {
  	circlePane.enlarge();
  }   
});

使用匿名内部类扩大缩小圆圈的完整代码如下:

package com.example.demo;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

// 代码实现:通过按钮点按,圆就会放大或缩小
public class ControlCircle extends Application {
    // 创建一个字段circlePane,类型是CirclePane,这样,circlePane就可以调用CirclePane类的方法了
    // 需要注意的是,CirclePane是一个面板,继承了StackPane,根据代码,调用了CirclePane的无参构造方法,就意味着CirclePane中添加了一个半径是50的圆
    private CirclePane circlePane = new CirclePane();

    @Override
    public void start(Stage primaryStage) {
        // 生成两个按钮
        HBox hBox = new HBox();
        hBox.setSpacing(10);
        hBox.setAlignment(Pos.CENTER);
        Button btEnlarge = new Button("Enlarge");
        Button btShrink = new Button("Shrink");
        hBox.getChildren().add(btEnlarge);
        hBox.getChildren().add(btShrink);

        // 当用户点击按钮时,下面的代码就会调用setOnAction方法,参数是内部类
        // 在内部类中,会自动执行handle()方法,进行半径的扩大或缩小
        btEnlarge.setOnAction(new EventHandler<ActionEvent>() {
            @Override // Override the handle method
            public void handle(ActionEvent e) {
                circlePane.enlarge();
            }
        });

        btShrink.setOnAction(new EventHandler<ActionEvent>() {
            @Override // Override the handle method
            public void handle(ActionEvent e) {
                circlePane.shrink();
            }
        });

        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(circlePane);
        borderPane.setBottom(hBox);
        BorderPane.setAlignment(hBox, Pos.CENTER);

        Scene scene = new Scene(borderPane, 200, 150);
        primaryStage.setTitle("ControlCircle"); // Set the stage title
        primaryStage.setScene(scene); // Place the scene in the stage
        primaryStage.show(); // Display the stage
    }
}

class CirclePane extends StackPane {
    private Circle circle = new Circle(50);

    public CirclePane() {
        getChildren().add(circle);
        circle.setStroke(Color.BLACK);
        circle.setFill(Color.WHITE);
    }

    // 更新属性
    public void enlarge() {
        circle.setRadius(circle.getRadius() + 2);
    }

    // 更新属性
    public void shrink() {
        circle.setRadius(circle.getRadius() > 2 ?
                circle.getRadius() - 2 : circle.getRadius());
    }
}
15.6 使用lambda表达式简化事件处理

如果要编译器理解lambda表达式,接口必须只包含一个抽象方法。这样的接口称为功能接口(functional interface)或者一个单抽象方法(Single Abstract Method, SAM)接口

在这里插入图片描述

15.7 示例学习:贷款计算器
15.8 鼠标事件

当一个鼠标按键在一个节点上或者一个场景中被按下、释放、单击、移动或者拖动时,一个MouseEvent事件被触发

15.9 键盘事件

在一个节点或者一个场景上面只要按下、释放或者敲击键盘按键,就会触发一个 KeyEvent 事件

15.10 可观察对象的监听器

监听器类通过实现InvalidationListener接口以重写invalidated(Observable o)方法,从而处理值的改变

15.11 动画

抽象类 Animation 提供了 JavaFX 中动画制作的核心功能, JavaFX 提供了许多 Animation 的具体子类,本节一一介绍:

15.11.1 PathTransition

PathTransition类制作一个在给定时间内,节点沿着一条路径从一个端点到另外一个端点的移动动画

15.11.2 FadeTransition

FadeTransition 类在一个给定的时间内,通过改变一个节点的透明度来产生动画

15.11.3 Timeline

Timeline类可以用于通过使用一个或者更多的KeyFrame(关键帧)来编写任意动画

15.12 示例学习:弹球

自行观看

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值