我是java(fx)的初学者。
如何在 JavaFX 中获取 x 和 y 中的鼠标位置?我尝试使用 AWT MouseInfo
(也导入了它),但它不起作用。我还在 Ensembles 中看到了它的代码(在“高级阶段”中拖动球窗,这就是我需要做的,拖动我未装饰的 JavaFX 阶段),但它也不起作用。我将 FXML 与控制器一起使用,我想这是主要问题。我应该切换回单文件的简单 JavaFX 吗?我知道 FXML 更适合布局 UI,但我无法让很多这样的代码工作。还是我的控制器需要其他类型的代码?请尽可能提供带有注释的正确代码。
如果您需要我的一些代码来检查,请随时询问。
3 回答
您的问题中有几项 - 我将一次解决一项。
如何在 JavaFX 中获取 x 和 y 中的鼠标位置?
将鼠标事件处理程序添加到要在其中跟踪鼠标位置的适当 JavaFX 组件。JavaFX 鼠标事件将报告多种不同类型的坐标。x 和 y 坐标相对于被监控位置的节点的左上角。sceneX 和 sceneY 坐标相对于场景左上角的 0,0 坐标。screenX 和 screenY 坐标相对于当前屏幕的左上角 0,0 坐标。
这些坐标记录在MouseEvent文档中。节点和场景文档中有关于理解坐标系的额外信息。
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 中拖动未装饰阶段的另一个示例是如何使用 JavaFX 2 绘制时钟?其中有相关的示例代码。用于使时钟样本的未装饰阶段可拖动的方法是:
/** 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 更适合布局 UI,但我无法让很多这样的代码工作。
对底层 JavaFX API 缺乏理解和熟悉可能是您的主要问题,而不是使用 FXML。但是,fxml 所暗示的额外复杂性以及网络上较轻的文档和示例可能会导致您的困难。如果使用 FXML 让您难以理解如何让一些 JavaFX 函数工作,我建议现在停止使用 FXML。使用 Java API 手动编写逻辑代码,并在遇到困难时 参考Oracle JavaFX 教程和Ensemble 示例代码。
一旦您习惯了直接使用 JavaFX API 编码,就可以切换回使用 FXML 来处理包含许多 GUI 元素的大型项目。FXML 元素和属性本身几乎完全基于标准 JavaFX API 的反映而构建。因此,如果您了解核心 JavaFX API,您也几乎了解有关 FXML 的所有内容。
请不要对这个答案发表后续评论(因为这个答案已经足够长了)。如果您有新问题,请创建一个新问题(每个问题一个问题)。
出于这个目的使用机器人怎么样?
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();
不幸的是,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));
});