🌿🌿🌿跟随博主脚步,从这里开始→博主主页🌿🌿🌿
- 欢迎大家:这里是我的学习笔记、总结知识的地方,喜欢的话请三连,有问题可以私信🌳🌳🌳
您的点赞👍、关注➕、收藏⭐️、评论📝、私信📧是我最大的支持与鼓舞!!!🌻🌻🌻
事件处理
事件处理
- 事件处理:为控件设计相应的程序,使控件能够响应并处理用户的操作。
- Java程序一旦构建完GUI,就不再工作,而是等待用户通过鼠标、键盘给它通知,它再根据这个通知的内容进行相应的处理 (事件处理)。
- 通常一个键盘或鼠标操作会引发一个系统预先定义好的事件 (事件类) ,用户只需编写代码,定义每个特定事件发生时程序应做出何种响应即可。
事件处理模型
- JavaFX事件处理采用事件代理模型(委托事件模型):将事件源和对事件做出的具体处理分离开来。将事件的处理从事件源对象代理给一个或多个成为事件处理器或事件监听器的对象,事件由事件处理器处理。
- 事件处理模型涉及3种对象:事件源、事件和事件处理器(监听者):
(1)事件源(event source):能够产生事件的对象。如按钮、鼠标、文本框、键盘等。当这些对象的状态改变时,就会产生事件。
(2)事件(event):一个事件是事件类的实例,描述事件源状态的改变。
(3)事件处理器(handler):接收事件并对其进行处理的对象。该对象必须实现EventHandler接口。处理器有专门的方法来处理事件,事件处理器是一个对事件源进行监视的对象,当事件源上发生事件时,事件处理器能够监听到,并调用相应的方法对发生的事件做出相应的处理。 - JavaFX的事件处理模型如图所示:
- 例如,当按钮被鼠标单击时,会触发一个“动作事件”(
Action event
),JavaFX程序就会产生一个“事件对象”来表示这个事件,然后把这个“事件对象”传递给“事件处理器”,“事件处理器”再依据“事件对象”的种类把工作指派给事件处理者,即事件处理程序。在这里按钮就是一个事件源。 - 为了让“事件源”(如按钮)知道要把事件信息传递给哪一个“事件处理器”,事先必须把“事件处理器”向“事件源”注册(
register
),这个操作也就是告知“事件源”要把事件信息传递给它。 - 事件代理模型的工作原理:
总结:
要处理事件,首先在事件源上注册事件处理器。当用户动作触发一个事件,运行时系统将创建一个事件对象,然后执行事件处理器对象。
事件类和事件类型
- JavaFX定义了大量事件类用于处理各种用户操作所产生的事件,这些类封装了事件对象。在Java语言中,Java事件类的根是
java.util.EventObject
,JavaFX
事件类的根是javafx.event.Event
。 - 常用事件类的层次关系如下图:
- 事件类型是
javafx.event.EventType
类的实例,它表示与事件相关的具体类型。事件类型还可进一步分为单个的事件类。 - 如KeyEvent类就包含下面的事件类型:
KeyEvent.KEY_PRESSED:键被按下。
KeyEvent.KEY_RELEASED:键被释放。
KeyEvent.KEY_TYPED:键被按下,然后释放
- MouseEvent类包含10多个具体事件,下面是几个常用的:
MouseEvent.MOUSE_CLICKED,鼠标单击。
MouseEvent.MOUSE_ENTERED ,鼠标进入控件。
MouseEvent.MOUSE_PRESSED,按下鼠标左键。
MouseEvent.MOUSE_MOVED,鼠标指针移动。
使用事件处理器
- 担当事件源的事件处理器,需满足两个条件:
(1)事件处理器必须是一个对应的事件处理器接口的实例。
(2)事件处理器对象必须通过事件源进行注册,注册方法依赖于事件类型。 - 注册事件处理器的两种方法:
(1)使用控件提供的方便方法。教材中表15-2给出常用事件类型、用户动作和事件注册方法。
(2)使用Node类的addEventHandler()
的方法,该方法带一个事件类型参数和一个EventHandler
参数。
1.使用控件提供的方便方法来注册事件处理器,不同的事件注册方法不同。例如:
①对于ActionEvent事件,注册方法是
setOnAction(EventHandler<ActionEvent> handler);
②对于鼠标单击事件,注册方法是
setOnMouseClicked(EventHandler<MouseEvent> handler);
③对于一个按键事件,注册方法是
setOnKeyPressed(EventHandler<KeyEvent> handler);
2.使用Node类的addEventHandler()的方法:
JavaFX定义了一个对于事件T的统一的处理器接口EventHandler<T extends Event>
,该接口中声明了handle(T e)
方法用于处理事件。例如:
对于ActionEvent事件,处理器接口是EventHandler(ActionEvent)
,应该实现handle(ActionEvente)
方法处理事件。
实现事件处理器对象和注册事件处理器的三种方法:
(1)通过内部类对象实现;
(2)通过匿名内部类实现;
(3)使用Lambda表达式实现。
实战演练
例:下面代码使用匿名类创建一个处理器对象,处理鼠标事件,并为节点注册事件处理器。
//定义事件处理器handler
EventHandler handler = new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
System.out.println("处理事件:" + event.getEventType());}};
//为节点注册处理器handler
(1) myNode.setOnMouseClicked(handler);
(2)myNode.addEventHandler(MouseEvent.MOUSE_CLICKED,
handler);
常用事件类型
(1)动作事件ActionEvent
- ActionEvent是表示某种动作的事件,如按钮被点击、菜单项被选择,都发生这种类型事件。
- 使用控件的setOnAction()方法,一般格式为:
void setOnAction(EventHandler<ActionEvent> value)//事件处理器对象
- 使用Node类定义的addEventHandler()方法注册事件处理器:
void addEventHandler(ActionEvent eventType,
EventHandler<ActionEvent> handler)
实战演练
问题描述:
编写程序,实现如图所示的界面。要求当单击“确定或“取消”按钮时,在标签中显示相应信息。
例:使用Lambda表达式实现处理器
public class ActionEventDemo extends Application {
Label label = new Label();
Button ok = new Button("确定"), cancel = new Button("取消");
@Override
public void start(Stage stage) {
ok.setOnAction((ActionEvent event)->label.setText("你单击了'确定'按钮"));
cancel.setOnAction((ActionEvent event)->label.setText("你单击了'取消'按钮"));
FlowPane rootNode = new FlowPane(10, 10);
rootNode.setAlignment(Pos.CENTER);
rootNode.getChildren().addAll(ok, cancel, label);
Scene scene = new Scene(rootNode, 240, 100);
stage.setTitle("事件处理示例");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
2)鼠标事件MouseEvent
- 当鼠标按键在一个节点上或者一个场景中被按下、释放、单击、移动或者拖动时,一个
MouseEvent
事件被触发。 - MouseEvent类的常用方法:
MouseButton getButton()//结果是MouseButton枚举值。PRIMARY、MIDDLE、SECONDARY。
例:me.getButton()==MouseButton.SECONDARY
int getClickCount()
double getX()
double getY()
double getScreenX()
double getScreenY()
可以使用setOnMouseEntered()、setOnMouseExited()和setOnMousePressed()等方法为鼠标事件注册事件处理器。
实战演练
问题描述:
编写程序,如图所示。当鼠标进入圆、离开圆、在圆中按键,在标签中显示相关信息,当鼠标指针处于圆中并拖动,圆在新的位置显示。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CircleApp extends JFrame {
private JLabel statusLabel;
private int circleX = 100;
private int circleY = 100;
private int circleRadius = 50;
public CircleApp() {
setTitle("Circle App");
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
statusLabel = new JLabel("Mouse outside the circle");
statusLabel.setBounds(10, 10, 380, 20);
add(statusLabel);
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (isInsideCircle(e.getX(), e.getY())) {
statusLabel.setText("Mouse pressed inside the circle");
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (isInsideCircle(e.getX(), e.getY())) {
statusLabel.setText("Mouse released inside the circle");
}
}
@Override
public void mouseEntered(MouseEvent e) {
if (isInsideCircle(e.getX(), e.getY())) {
statusLabel.setText("Mouse entered the circle");
}
}
@Override
public void mouseExited(MouseEvent e) {
statusLabel.setText("Mouse outside the circle");
}
});
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (isInsideCircle(e.getX(), e.getY())) {
circleX = e.getX() - circleRadius;
circleY = e.getY() - circleRadius;
repaint();
}
}
});
}
private boolean isInsideCircle(int x, int y) {
return Math.sqrt(Math.pow(x - circleX - circleRadius, 2) + Math.pow(y - circleY - circleRadius, 2)) <= circleRadius;
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.drawOval(circleX, circleY, 2 * circleRadius, 2 * circleRadius);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
CircleApp frame = new CircleApp();
frame.setVisible(true);
});
}
}
(3)键盘事件KeyEvent
- 在一个节点或者一个场景上按下、释放或者敲击键盘按钮,就会触发一个
KeyEvent
事件。 - KeyEvent类的常用方法:
String getCharacter()
String getText()
KeyCode getCode()
boolean isShiftDown()
使用节点的setOnKeyPressed()、setOnKeyReleased()和setOnKeyTyped()等方法为键盘事件注册事件处理器。
实战演练
问题描述:
编写程序,如图所示。按字母键显示不同字母,按方向键,字母移动。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class KeyboardEventsExample extends Application {
private Text text = new Text(50, 50, "A");
private double x = 50, y = 50;
@Override
public void start(Stage primaryStage) {
Rectangle background = new Rectangle(400, 400, Color.WHITE);
StackPane root = new StackPane();
root.getChildren().addAll(background, text);
Scene scene = new Scene(root, 400, 400);
scene.setOnKeyPressed(event -> {
KeyCode keyCode = event.getCode();
switch (keyCode) {
case UP:
y -= 10;
text.setY(y);
break;
case DOWN:
y += 10;
text.setY(y);
break;
case LEFT:
x -= 10;
text.setX(x);
break;
case RIGHT:
x += 10;
text.setX(x);
break;
default:
text.setText(keyCode.toString().substring(0, 1));
break;
}
});
primaryStage.setTitle("JavaFX Keyboard Event Example");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
博主用心写,读者点关注,互动传真情,知识不迷路。