JavaFX应用程序,用于将数据从nativeMouseListener中继到JavaFX的框架

时间:2015-02-12 22:14:23

标签: events javafx frameworks mouselistener

我正在制作JavaFX应用程序而我想要执行以下操作。

我提供了几个按钮,当按下它们时,GUI将最小化并等待来自JNativeHook库的mouseClick。当单击鼠标时,它需要将协调器中继回到javaFx控制器,GUI最大化并表示gui中的数据,并且让我可以使用它来执行其他操作。

我已经将这种行为用于一个按钮,但它并不好。如果我想要更多按钮,我当前的实现将无法工作,如下所示,它需要很多重复的代码,我需要在layoutController中为每个按钮创建一个特定的mouseListener和方法(除了buttonHandlers) 。我显然不想要这个,基本上我正在寻找一个小框架让我的buttonHandle方法中的下一个NativeMouseEvent中继数据在控制器中

这就是我得到的,带按钮的JavaFX layoutController具有以下句柄

@FXML
private void handleGetPos() {
    try {
        mouseManager.startMousePosChecker(cntrl);
        mainGUI.minimizeGUI();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

layoutController将自身作为cntrl传递给我的mouseManager,管理器只是(un)将nativeHook注册到GlobalScreen并向其添加一个新的mouseListener并传递layoutController cntrl 。 (如果我想使用另一个layoutControllers,那么将控制器传递给它也是愚蠢的,因为它们的类型不同)

    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坐标作为字符串传递给我的layoutController中的特定方法:

public void setMousePos(String sX, String sY, int x, int y) {
    xPos.setText(sX);
    yPos.setText(sY);
    mainGUI.maximizeGUI();
    mouseManager.stopMousePosChecker();
    //other stuff

显然,这种实现不适用于多个按钮。因此,我想用mouseManager构建一个小框架。哪个注册/取消注册nativeHook并只生成一个mouseListener,它将数据返回给mouseManager。然后,此mouseManager会向需要它的任何人提供必要的数据。如果我纠正这听起来像一个自定义事件类? (尝试制作一个,但我不知道如何实现它我的layoutController或如何将它包装在globalMouseEvents周围)

无论如何,我认为它会变成这样的东西,或者是lambda的东西? (注意我实际上不知道):

     @FXML
     private void handleButton() {
         xPos.setText(mouseManager<MouseEvent>() {
         @Override
         public void handle(MouseEvent e) {
              //necessery stuff goes here

所以是的,我不知道如何开始如何在任何buttonHandle()方法或实际的任何方法中返回数据。我知道我当前的代码很糟糕,我想让它变得更好并重用代码而不是重复的代码,但这个问题目前让我头疼...

这是一篇很长的帖子,感谢阅读和帮助!

1 个答案:

答案 0 :(得分:1)

不确定我是否完全理解,但你可以这样做:

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...
    });
}

这都是未经测试的(编译和运行,我只是在这里输入),但我认为它应该足以让你开始。关键是你只是为鼠标位置公开一个属性,并从每个按钮处理程序中监听它,在它发生变化时执行特定于按钮的代码。您的本机鼠标侦听器只需在相关事件发生时更新属性;它不需要对控制器等的引用。