JavaFX 应用程序,将数据从 nativeMouseListener 中继到 JavaFX 的框架
JavaFX application, framework to relay data from a nativeMouseListener to JavaFX
我正在制作一个 JavaFX 应用程序,我想执行以下操作。
我提供了几个按钮,按下它们时,GUI 将最小化并等待来自 JNativeHook 库的 mouseClick。单击鼠标时,它的 x、y 坐标需要传回 javaFx 控制器,GUI 最大化并表示 gui 中的数据,让我可以用它做其他事情。
我的这个行为对一个按钮有效,但一点也不好。如果我想要更多按钮,我当前的实现将无法工作,如下所示,它需要大量重复代码,我需要在布局控制器中为每个按钮(除了 buttonHandlers 之外)制作一个特定的 mouseListener 和方法。我显然不想要这个,基本上我正在寻找一个小框架,让下一个 NativeMouseEvent 在我的控制器中的 buttonHandle 方法中中继数据
这就是我得到的,带有按钮的 JavaFX layoutController,具有以下句柄
@FXML
private void handleGetPos() {
try {
mouseManager.startMousePosChecker(cntrl);
mainGUI.minimizeGUI();
} catch (Exception e) {
e.printStackTrace();
}
}
layoutController 将自身作为 cntrl
传递给我的 mouseManager,管理器只是(取消)注册一个 nativeHook 到 GlobalScreen
并向其添加一个新的 mouseListener 并传递 layoutController cntrl
用它。 (如果我想使用另一个布局控制器,将控制器传递给它也是愚蠢的,因为它们不是同一类型)
GlobalMouseListener mouseListener = new GlobalMouseListener();
mouseListener.setLayoutController(cntrl);
GlobalScreen.getInstance().addNativeMouseListener(mouseListener);
在 mouseListener 中发生了这种情况:
public void nativeMouseClicked(NativeMouseEvent e) {
Platform.runLater(() -> {
cntrl.setMousePos(ConvTypes.toStr(e.getX()), ConvTypes.toStr(e.getY()), e.getX(), e.getY() );
});
}
这很丑陋,当事件发生时,它会将 x、y 坐标作为字符串传递给我的布局控制器中的特定方法:
public void setMousePos(String sX, String sY, int x, int y) {
xPos.setText(sX);
yPos.setText(sY);
mainGUI.maximizeGUI();
mouseManager.stopMousePosChecker();
//other stuff
显然,此实现不适用于多个按钮。因此我想用 mouseManager 构建一个小框架。其中 registers/unregisters nativeHook 和仅制作一个 mouseListener,其中 returns 数据到 mouseManager。然后这个 mouseManager 将必要的数据提供给任何需要它的人。如果我是对的,这听起来像是一个自定义事件 class? (试图制作一个但我不知道如何实现我的 layoutController 或如何将它包装在 globalMouseEvents 周围)
无论如何我认为它会变成这样或者可能是带有 lambda 的东西? (注意我其实不知道):
@FXML
private void handleButton() {
xPos.setText(mouseManager<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
//necessery stuff goes here
所以是的,我不知道如何开始如何在任何 buttonHandle() 方法或任何实际方法中将数据获取到 return。我知道我当前的代码很糟糕,我想让它变得更好并重用代码而不是重复代码,但这个问题目前让我很头疼...
很长post,感谢阅读和帮助!
不确定我是否完全理解,但是你可以这样做吗:
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseListener;
import org.jnativehook.GlobalScreen;
import javafx.scene.input.MouseEvent ;
import javafx.application.Platform ;
import javafx.event.EventType ;
import javafx.geometry.Point2D ;
import javafx.beans.property.ReadOnlyObjectWrapper ;
import javafx.beans.property.ReadOnlyObjectProperty ;
public class GlobalMouseListener implements NativeMouseListener {
private final EventType<MouseEvent> eventType ;
private final ReadOnlyObjectWrapper<Point2D> mouseLocation = new ReadOnlyObjectWrapper<>();
/**
* @param eventType The type of event to listen for. Should be one of
* MouseEvent.MOUSE_CLICKED, MouseEvent.MOUSE_PRESSED, or MouseEvent.MOUSE_RELEASED.
* The mouseLocationProperty() will be updated if a global mouse event
* matching the semantic type of the provided eventType occurs.
*/
public GlobalMouseListener(EventType<MouseEvent> eventType) {
this.eventType = eventType ;
GlobalScreen.addNativeMouseListener(this);
}
public ReadOnlyObjectProperty<Point2D> mouseLocationProperty() {
return mouseLocation.getReadOnlyProperty() ;
}
public final Point2D getMouseLocation() {
return mouseLocationProperty().get();
}
@Override
public void nativeMouseClicked(NativeMouseEvent e) {
if (eventType == MouseEvent.MOUSE_CLICKED) {
Platform.runLater(() -> mouseLocation.set(new Point2D(e.getX(), e.getY())));
}
}
@Override
public void nativeMousePressed(NativeMouseEvent e) {
if (eventType == MouseEvent.MOUSE_PRESSED) {
Platform.runLater(() -> mouseLocation.set(new Point2D(e.getX(), e.getY())));
}
}
@Override
public void nativeMouseReleased(NativeMouseEvent e) {
if (eventType == MouseEvent.MOUSE_RELEASED) {
Platform.runLater(() -> mouseLocation.set(new Point2D(e.getX(), e.getY())));
}
}
public void cleanup() {
GlobalScreen.removeNativeMouseListener(this);
}
}
那么你的按钮处理程序只需要
@FXML
public void handleGetPos() {
GlobalMouseListener gml = new GlobalMouseListener(MouseEvent.MOUSE_CLICKED);
gml.mouseLocationProperty().addListener((obs, oldLocation, newLocation) -> {
double x = newLocation.getX();
double y = newLocation.getY();
gml.cleanup();
// restore window and process x, y...
});
mainGUI.minimizeGUI();
}
如果你真的想最小化样板代码,你可以定义
private void processMouseLocation(BiConsumer<Double, Double> pointProcessor) {
GlobalMouseListener gml = new GlobalMouseListener(MouseEvent.MOUSE_CLICKED);
gml.mouseLocationProperty().addListener((obs, oldLocation, newLocation) -> {
double x = newLocation.getX();
double y = newLocation.getY();
gml.cleanup();
// restore window...
pointProcessor.accept(x, y);
});
mainGUI.minimizeGUI();
}
然后您的每个按钮处理程序都减少到
@FXML
public void handleGetPos() {
processMouseLocation((x, y) -> {
// code to handle mouse press at x,y...
});
}
这些都是未经测试的(包括编译和 运行,我只是在此处输入),但我认为这应该足以让您入门。重点是您只需为鼠标位置公开一个 属性 ,并从每个按钮处理程序中收听它,并在它发生变化时执行特定于按钮的代码。当相关事件发生时,您的本地鼠标侦听器只需更新 属性;它不需要对控制器等的引用。
我正在制作一个 JavaFX 应用程序,我想执行以下操作。
我提供了几个按钮,按下它们时,GUI 将最小化并等待来自 JNativeHook 库的 mouseClick。单击鼠标时,它的 x、y 坐标需要传回 javaFx 控制器,GUI 最大化并表示 gui 中的数据,让我可以用它做其他事情。
我的这个行为对一个按钮有效,但一点也不好。如果我想要更多按钮,我当前的实现将无法工作,如下所示,它需要大量重复代码,我需要在布局控制器中为每个按钮(除了 buttonHandlers 之外)制作一个特定的 mouseListener 和方法。我显然不想要这个,基本上我正在寻找一个小框架,让下一个 NativeMouseEvent 在我的控制器中的 buttonHandle 方法中中继数据
这就是我得到的,带有按钮的 JavaFX layoutController,具有以下句柄
@FXML
private void handleGetPos() {
try {
mouseManager.startMousePosChecker(cntrl);
mainGUI.minimizeGUI();
} catch (Exception e) {
e.printStackTrace();
}
}
layoutController 将自身作为 cntrl
传递给我的 mouseManager,管理器只是(取消)注册一个 nativeHook 到 GlobalScreen
并向其添加一个新的 mouseListener 并传递 layoutController cntrl
用它。 (如果我想使用另一个布局控制器,将控制器传递给它也是愚蠢的,因为它们不是同一类型)
GlobalMouseListener mouseListener = new GlobalMouseListener();
mouseListener.setLayoutController(cntrl);
GlobalScreen.getInstance().addNativeMouseListener(mouseListener);
在 mouseListener 中发生了这种情况:
public void nativeMouseClicked(NativeMouseEvent e) {
Platform.runLater(() -> {
cntrl.setMousePos(ConvTypes.toStr(e.getX()), ConvTypes.toStr(e.getY()), e.getX(), e.getY() );
});
}
这很丑陋,当事件发生时,它会将 x、y 坐标作为字符串传递给我的布局控制器中的特定方法:
public void setMousePos(String sX, String sY, int x, int y) {
xPos.setText(sX);
yPos.setText(sY);
mainGUI.maximizeGUI();
mouseManager.stopMousePosChecker();
//other stuff
显然,此实现不适用于多个按钮。因此我想用 mouseManager 构建一个小框架。其中 registers/unregisters nativeHook 和仅制作一个 mouseListener,其中 returns 数据到 mouseManager。然后这个 mouseManager 将必要的数据提供给任何需要它的人。如果我是对的,这听起来像是一个自定义事件 class? (试图制作一个但我不知道如何实现我的 layoutController 或如何将它包装在 globalMouseEvents 周围)
无论如何我认为它会变成这样或者可能是带有 lambda 的东西? (注意我其实不知道):
@FXML
private void handleButton() {
xPos.setText(mouseManager<MouseEvent>() {
@Override
public void handle(MouseEvent e) {
//necessery stuff goes here
所以是的,我不知道如何开始如何在任何 buttonHandle() 方法或任何实际方法中将数据获取到 return。我知道我当前的代码很糟糕,我想让它变得更好并重用代码而不是重复代码,但这个问题目前让我很头疼...
很长post,感谢阅读和帮助!
不确定我是否完全理解,但是你可以这样做吗:
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseListener;
import org.jnativehook.GlobalScreen;
import javafx.scene.input.MouseEvent ;
import javafx.application.Platform ;
import javafx.event.EventType ;
import javafx.geometry.Point2D ;
import javafx.beans.property.ReadOnlyObjectWrapper ;
import javafx.beans.property.ReadOnlyObjectProperty ;
public class GlobalMouseListener implements NativeMouseListener {
private final EventType<MouseEvent> eventType ;
private final ReadOnlyObjectWrapper<Point2D> mouseLocation = new ReadOnlyObjectWrapper<>();
/**
* @param eventType The type of event to listen for. Should be one of
* MouseEvent.MOUSE_CLICKED, MouseEvent.MOUSE_PRESSED, or MouseEvent.MOUSE_RELEASED.
* The mouseLocationProperty() will be updated if a global mouse event
* matching the semantic type of the provided eventType occurs.
*/
public GlobalMouseListener(EventType<MouseEvent> eventType) {
this.eventType = eventType ;
GlobalScreen.addNativeMouseListener(this);
}
public ReadOnlyObjectProperty<Point2D> mouseLocationProperty() {
return mouseLocation.getReadOnlyProperty() ;
}
public final Point2D getMouseLocation() {
return mouseLocationProperty().get();
}
@Override
public void nativeMouseClicked(NativeMouseEvent e) {
if (eventType == MouseEvent.MOUSE_CLICKED) {
Platform.runLater(() -> mouseLocation.set(new Point2D(e.getX(), e.getY())));
}
}
@Override
public void nativeMousePressed(NativeMouseEvent e) {
if (eventType == MouseEvent.MOUSE_PRESSED) {
Platform.runLater(() -> mouseLocation.set(new Point2D(e.getX(), e.getY())));
}
}
@Override
public void nativeMouseReleased(NativeMouseEvent e) {
if (eventType == MouseEvent.MOUSE_RELEASED) {
Platform.runLater(() -> mouseLocation.set(new Point2D(e.getX(), e.getY())));
}
}
public void cleanup() {
GlobalScreen.removeNativeMouseListener(this);
}
}
那么你的按钮处理程序只需要
@FXML
public void handleGetPos() {
GlobalMouseListener gml = new GlobalMouseListener(MouseEvent.MOUSE_CLICKED);
gml.mouseLocationProperty().addListener((obs, oldLocation, newLocation) -> {
double x = newLocation.getX();
double y = newLocation.getY();
gml.cleanup();
// restore window and process x, y...
});
mainGUI.minimizeGUI();
}
如果你真的想最小化样板代码,你可以定义
private void processMouseLocation(BiConsumer<Double, Double> pointProcessor) {
GlobalMouseListener gml = new GlobalMouseListener(MouseEvent.MOUSE_CLICKED);
gml.mouseLocationProperty().addListener((obs, oldLocation, newLocation) -> {
double x = newLocation.getX();
double y = newLocation.getY();
gml.cleanup();
// restore window...
pointProcessor.accept(x, y);
});
mainGUI.minimizeGUI();
}
然后您的每个按钮处理程序都减少到
@FXML
public void handleGetPos() {
processMouseLocation((x, y) -> {
// code to handle mouse press at x,y...
});
}
这些都是未经测试的(包括编译和 运行,我只是在此处输入),但我认为这应该足以让您入门。重点是您只需为鼠标位置公开一个 属性 ,并从每个按钮处理程序中收听它,并在它发生变化时执行特定于按钮的代码。当相关事件发生时,您的本地鼠标侦听器只需更新 属性;它不需要对控制器等的引用。