gpt4 book ai didi

reflection - 使用现有方法作为 JavaFX 事件处理程序

转载 作者:行者123 更新时间:2023-12-04 23:22:21 25 4
gpt4 key购买 nike

在我能找到的几乎所有示例中,JavaFX 事件处理程序都是作为匿名内部类创建的,
像这样:

button.setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
if (event.getClickCount()>1) {
System.out.println("double clicked!");
}
}
});

但是,我真的很讨厌匿名内部类(丑陋!!!),而且我也不想为每个事件处理程序创建单独的类。我想使用现有的方法作为事件处理程序,就像 FXMLLoader 一样。我的第一个想法是使用反射和泛型,这就是我想出的:
public final static <E extends Event> EventHandler<E> createEventHandler(
final Class<E> eventClass, final Object handlerInstance, final String handlerMethod) {
try {
final Method method = handlerInstance.getClass().getMethod(handlerMethod, eventClass);
return new EventHandler<E>() {
@Override
public void handle(E event) {
try {
method.invoke(handlerInstance, event);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
};
} catch (NoSuchMethodException | SecurityException e) {
return null;
}
}

您传递一个必需的 Event 类、处理程序实例和方法名称来处理事件,并返回所需的 EventHandler。它有效,但它看起来不是很优雅。有没有人有更好的主意?

最佳答案

建议方法

使用 Tom 关于 Java 8 方法引用的想法:

public void countClick(MouseEvent event) {
nClickProperty.set(nClickProperty.get() + 1);
}
. . .
label.setOnMouseClicked(this::countClick);

可执行样本
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public class ClickCounter extends Application {

private final IntegerProperty nClickProperty = new SimpleIntegerProperty(0);

public void countClick(MouseEvent event) {
nClickProperty.set(nClickProperty.get() + 1);
}

@Override
public void start(Stage stage) throws Exception {
Label label = new Label();
label.setPrefSize(100, 50);
label.setAlignment(Pos.CENTER);

label.textProperty().bind(
Bindings.concat("Num clicks: ", nClickProperty.asString())
);

label.setOnMouseClicked(this::countClick);

stage.setScene(new Scene(label));
stage.show();
}

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

基于问题和评论部分中的观点的进一步讨论

I really hate anonymous inner classes (UGLY!!!)



使用 Java 8 lambdas instead ,它们没有那么丑:
button.setOnMouseClicked(event -> {
if (event.getClickCount() > 1) {
System.out.println("double clicked!");
}
});

I would like to use existing methods as event handlers. as FXMLLoader does.



对于通用机制,您可以查看 FXMLLoader源代码并将事件处理机制提取到通用库中。

此外,如果您的 UI 是在 FXML 中定义的,那么您可以只使用 FXMLLoader 中的现有功能来获得您想要的行为。 (我猜你正在寻找一个不涉及 FXML 的解决方案)。

Does anyone have a better idea?



保留引用

将事件处理程序分配给引用。这种方法在某些情况下有用,但不一定美观。
private final EventHandler<MouseEvent> mouseHandler = event -> {
if (event.getClickCount() > 1) {
System.out.println("double clicked!");
}
};
. . .
button.setOnMouseClicked(mouseHandler);

保留对处理程序的本地引用的一个优点是它为您提供了稍后调用 node.removeEventHandler 的引用。对于先前使用 node.addEventHandler 注册的处理程序.

使用替代语言

如果您对替代语言持开放态度,那么在动态语言中实现动态方法调用会更简洁一些。你可以看看如何 JRubyFX处理来自 FXML 文档的事件处理程序分配问题(我认为它不依赖于 FXMLLoader,但相信它有自己的纯 Ruby 替换实现)。当然,那么您正在使用一种动态语言,在您的情况下可能需要也可能不需要。

关于reflection - 使用现有方法作为 JavaFX 事件处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20477187/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com