如何在JavaFX中获取鼠标的位置?

时间:2013-05-19 14:08:06

标签: custom-controls mouse customization javafx draggable

我是java(fx)的初学者。
如何在JavaFX中获得x和y中的鼠标位置?我尝试使用AWT的MouseInfo(也导​​入了它),但它不起作用。我也在Ensembles中看到了它的代码(在“高级阶段”拖动球窗,这就是我需要做的,拖动我未修饰的JavaFX阶段),但它也不起作用。我正在使用带控制器的FXML,我猜这是主要问题。我应该切换回单文件简单的JavaFX吗?我知道FXML更适合布局用户界面,但我不能让很多这样的代码工作。或者我的控制器是否需要其他类型的代码?请尽可能提供适当的代码和评论 如果您需要我的一些代码进行检查,请随时询问。

3 个答案:

答案 0 :(得分:23)

你的问题中有几个项目 - 我会一次解决一个问题。

  

如何在JavaFX中获取x和y中的鼠标位置?

将鼠标事件处理程序添加到要跟踪鼠标位置的相应JavaFX组件中.JavaFX鼠标事件将报告多种不同类型的坐标。 x和y坐标是相对于正在监视其位置的节点的左上角。 sceneX和sceneY坐标是相对于场景的左上角0,0坐标。 screenX和screenY坐标是相对于当前屏幕的左上角0,0坐标。

这些坐标记录在MouseEvent文档中。在NodeScene文档中了解协调系统有额外的信息。

mouselocationmonitor

import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.*;

public class MouseLocationReporter extends Application {
  private static final String OUTSIDE_TEXT = "Outside Label";

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

  @Override public void start(final Stage stage) {
    final Label reporter = new Label(OUTSIDE_TEXT);
    Label monitored = createMonitoredLabel(reporter);

    VBox layout = new VBox(10);
    layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10px;");
    layout.getChildren().setAll(
      monitored,
      reporter
    );
    layout.setPrefWidth(500);

    stage.setScene(
      new Scene(layout)
    );

    stage.show();
  }

  private Label createMonitoredLabel(final Label reporter) {
    final Label monitored = new Label("Mouse Location Monitor");

    monitored.setStyle("-fx-background-color: forestgreen; -fx-text-fill: white; -fx-font-size: 20px;");

    monitored.setOnMouseMoved(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent event) {
        String msg =
          "(x: "       + event.getX()      + ", y: "       + event.getY()       + ") -- " +
          "(sceneX: "  + event.getSceneX() + ", sceneY: "  + event.getSceneY()  + ") -- " +
          "(screenX: " + event.getScreenX()+ ", screenY: " + event.getScreenY() + ")";

        reporter.setText(msg);
      }
    });

    monitored.setOnMouseExited(new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent event) {
        reporter.setText(OUTSIDE_TEXT);
      }
    });

    return monitored;
  }
}
  

我尝试使用AWT的MouseInfo(也是导入它),但它不起作用。

不要这样做。混合不同的图形工具包(例如Swing / AWT和JavaFX)是一个高级主题。通常,如果您正在编写JavaFX应用程序,请避免从java.awt命名空间和javax.swing命名空间导入任何内容。如果您有一个大型的,现有的基于Swing的应用程序或框架,您只需要与JavaFX应用程序进行交互操作,那么您才真正需要使用它们。在这种情况下,您没有这种情况。

  

我还在Ensembles中看到了它的代码(在“高级阶段”拖动球窗,这就是我需要做的,拖动我未修饰的JavaFX阶段),但它也不起作用。

我尝试了Ensemble Advanced Stage示例并拖动那个阶段为我工作。

在JavaFX中拖动未修饰阶段的另一个示例是How to draw a clock with JavaFX 2?的答案associated sample code。用于使时钟样本可拖动的未修饰阶段的方法是:

/** makes a stage draggable using a given node */
public static void makeDraggable(final Stage stage, final Node byNode) {
  final Delta dragDelta = new Delta();
  byNode.setOnMousePressed(new EventHandler<MouseEvent>() {
    @Override public void handle(MouseEvent mouseEvent) {
      // record a delta distance for the drag and drop operation.
      dragDelta.x = stage.getX() - mouseEvent.getScreenX();
      dragDelta.y = stage.getY() - mouseEvent.getScreenY();
      byNode.setCursor(Cursor.MOVE);
    }
  });
  byNode.setOnMouseReleased(new EventHandler<MouseEvent>() {
    @Override public void handle(MouseEvent mouseEvent) {
      byNode.setCursor(Cursor.HAND);
    }
  });
  byNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
    @Override public void handle(MouseEvent mouseEvent) {
      stage.setX(mouseEvent.getScreenX() + dragDelta.x);
      stage.setY(mouseEvent.getScreenY() + dragDelta.y);
    }
  });
  byNode.setOnMouseEntered(new EventHandler<MouseEvent>() {
    @Override public void handle(MouseEvent mouseEvent) {
      if (!mouseEvent.isPrimaryButtonDown()) {
        byNode.setCursor(Cursor.HAND);
      }
    }
  });
  byNode.setOnMouseExited(new EventHandler<MouseEvent>() {
    @Override public void handle(MouseEvent mouseEvent) {
      if (!mouseEvent.isPrimaryButtonDown()) {
        byNode.setCursor(Cursor.DEFAULT);
      }
    }
  });
}
  

我正在使用FXML和控制器,我猜这是主要问题。我应该切换回单文件简单的JavaFX吗?我知道FXML更适合布局用户界面,但我不能让很多这样的代码工作。

缺乏对底层JavaFX API的理解和熟悉可能是您的主要问题,而不是使用FXML。然而,fxml的额外复杂性意味着更轻的文档和网上的样本可能会助长您的艰辛。如果使用FXML使您难以理解如何使某些JavaFX功能起作用,我建议暂时停止使用FXML。使用Java API手动编写逻辑代码,并在遇到困难的事情时参考Oracle JavaFX tutorialsEnsemble sample code

一旦您熟悉直接编写JavaFX API,请切换回使用FXML来处理包含许多GUI元素的大型项目。 FXML元素和属性本身几乎完全是在反映标准JavaFX API的基础上构建的。因此,如果您了解核心JavaFX API,您几乎可以理解FXML的所有内容。

请不要对此答案发表后续评论(因为这个答案足够长)。如果您有新问题,请创建一个新问题(每个问题一个问题)。

答案 1 :(得分:3)

为此目的使用机器人怎么样?

http://docs.oracle.com/javase/1.5.0/docs/api/java/awt/Robot.html

使用机器人,与将事件发布到AWT事件队列不同。事件在本机事件队列中生成。实际上,使用Robot.mouseMove,您不仅可以设置鼠标位置,还可以获得位置。

要获得鼠标位置,您可以坚持使用MouseInfo

import java.awt.MouseInfo;
// get the mouse's position
Point p = MouseInfo.getPointerInfo().getLocation();

这不起作用:你和Mac在一起吗?您的JavaFX版本是哪个?似乎是FX8纠正的问题。仅限mac,您可以使用

com.sun.glass.ui.Robot robot =
       com.sun.glass.ui.Application.GetApplication().createRobot();

// getPosition of the mouse in Mac
int x = robot.getMouseX(); 
int y = robot.getMouseY();

答案 2 :(得分:2)

遗憾的是,JavaFx 8 WindowEvent不提供鼠标的(x,y)位置。我通过使用像这样的AWT MouseInfo解决了这个问题(并且工作正常):

Tooltip t = new Tooltip();
Tooltip.install(yournode, t);
t.setOnShowing(ev -> {// called just prior to being shown
                Point mouse = java.awt.MouseInfo.getPointerInfo().getLocation();
                Point2D local = yournode.screenToLocal(mouse.x, mouse.y);

                // my app-specific code to get the chart's yaxis value
                // then set the text as I want
                double pitch = yaxis.getValueForDisplay(local.getY()).doubleValue();
                double freq = AudioUtil.pitch2frequency(pitch);
                t.setText(String.format("Pitch %.1f:  %.1f Hz   %.1f samples", pitch, freq, audio.rate / freq));
        });