我希望能够检测鼠标何时移动以及何时不使用JavaFX移动到AnchorPane上。
我目前在我的窗格上有一个'鼠标移动事件',当移动鼠标时会输出一些文本,但是当鼠标不移动时还希望包含一些输出。
我仍然难以理解如何在保持相对简单的同时实现问题的后半部分。
每当鼠标移动时,下面输出“移动”,但当鼠标停止时,没有任何反应。我可以看到这是因为checkMovement
仅在移动时被调用。
是否存在反函数或类似函数 - 这会反过来?
我相信我可以使用特定的事件处理程序和/或计时器来实现我想要的东西,但这对于看似非常简单的事情来说过于复杂。
我错过了一些完全明显的东西吗?
我只是很擅长使用FX,所以请随意指出我应该以不同的方式做任何事情。
修改
我忘了指定我使用FXML来定义控件。
我是否需要将此过程放在控制器(AppController.java)中,或者为了“易用”而将它留在Main.java中?
我怎么能这样做/有可能吗?
显然,mouseMovementMethod
需要修改。
AppController.Java
public class AppController实现Initializable {
boolean moved = false;
@FXML
private AnchorPane anchorPane;
@FXML
private ImageView killpic;
@FXML
private ImageView processpic;
@FXML
private Text exit;
@FXML
private Button processAnimalButton;
/*
* ...Other Variables
*/
@FXML
void mouseMovedMethod(Event event){
//Mouse Movement Event
}
@FXML
void closeMenu(Event event) {
Stage stage = (Stage) exit.getScene().getWindow();
stage.close();
}
@FXML
void selectProcess(Event event) {
Image killimg = new Image("/images/knife_blood.png");
Image proimg = new Image("/images/p_selected.png");
killpic.setImage(killimg);
processpic.setImage(proimg);
}
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
Image killimg = new Image("/images/knife_blood_selected.png");
Image proimg = new Image("/images/p.png");
killpic.setImage(killimg);
processpic.setImage(proimg);
}
}
Main.java:
//*Required imports*//
public class Main extends Application {
Stage thestage;
@Override
public void start(Stage primaryStage) {
try {
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("popup.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
thestage = primaryStage;
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
答案 0 :(得分:1)
创建MouseEvent.ANY的事件侦听器。在该事件侦听器中,您将自己的属性mouseX和mouseY设置为事件的鼠标位置值。除此之外,创建一个永久运行的AnimationTimer并检查鼠标坐标是否在“delta”ms的间隔内没有变化。如果他们没有,请调用您的处理代码。
示例:
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
public class Main extends Application {
Scene scene;
MouseStatus mouseStatus = new MouseStatus();
Label infoLabel;
@Override
public void start(Stage primaryStage) {
Group root = new Group();
infoLabel = new Label();
root.getChildren().add( infoLabel);
scene = new Scene(root, 640, 480);
primaryStage.setScene(scene);
primaryStage.show();
addInputListeners();
}
private void addInputListeners() {
scene.addEventFilter(MouseEvent.ANY, e -> {
infoLabel.setText("Moving");
mouseStatus.setX(e.getX());
mouseStatus.setY(e.getY());
mouseStatus.setPrimaryButtonDown(e.isPrimaryButtonDown());
mouseStatus.setSecondaryButtonDown(e.isSecondaryButtonDown());
});
AnimationTimer loop = new AnimationTimer() {
long deltaNs = 30_000_000;
double currX;
double currY;
long currNs;
double prevX;
double prevY;
long prevNs;
@Override
public void handle(long now) {
currX = mouseStatus.x;
currY = mouseStatus.y;
currNs = now;
if( currNs - prevNs > deltaNs) {
if( prevX == currX && prevY == currY) {
infoLabel.setText("Stopped");
}
prevX = currX;
prevY = currY;
prevNs = currNs;
}
}
};
loop.start();
}
public class MouseStatus {
double x;
double y;
boolean primaryButtonDown;
boolean secondaryButtonDown;
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public boolean isPrimaryButtonDown() {
return primaryButtonDown;
}
public void setPrimaryButtonDown(boolean primaryButtonDown) {
this.primaryButtonDown = primaryButtonDown;
}
public boolean isSecondaryButtonDown() {
return secondaryButtonDown;
}
public void setSecondaryButtonDown(boolean secondaryButtonDown) {
this.secondaryButtonDown = secondaryButtonDown;
}
}
public static void main(String[] args) {
launch(args);
}
}
答案 1 :(得分:1)
这并不像你认为的那么简单的原因是"鼠标不移动的概念"没有你想象的那么明确。底层操作系统在一些深埋的内环中检测输入事件,例如鼠标的移动。该循环需要一段有限的时间才能运行,因此鼠标在循环运行时总是显得静止。操作系统将以较低的频率向JavaFX工具包报告这些移动,而JavaFX工具包可能会进一步限制那些移动的报告时间。
因此,要定义"鼠标不移动",你真的不得不求助于"在最后x
"中没有检测到鼠标移动,其中{{ 1}}是时间的一些度量(实时,例如纳秒,或帧渲染的数量)。所以你真的必须以某种方式实际实现这个逻辑,并决定计算多少时间"不要移动"。
@MadProgrammer在评论中建议一个实现(我认为这个实现更简单),而@Roland建议另一个实现。
这是@ MadProgrammer建议的实现:
x
这是@Roland建议的实现:
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class TrackMouseStopped extends Application {
private final long MIN_STATIONARY_TIME = 100_000_000 ; // nanoseconds
@Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
BooleanProperty mouseMoving = new SimpleBooleanProperty();
mouseMoving.addListener((obs, wasMoving, isNowMoving) -> {
if (! isNowMoving) {
System.out.println("Mouse stopped!");
}
});
PauseTransition pause = new PauseTransition(Duration.millis(MIN_STATIONARY_TIME / 1_000_000));
pause.setOnFinished(e -> mouseMoving.set(false));
// Note: if you want to consider the mouse having moved for
// other events (e.g. dragging), you can do
// pane.addEventHandler(MouseEvent.ANY, e -> { ... }); here
pane.setOnMouseMoved(e -> {
mouseMoving.set(true);
pause.playFromStart();
});
Scene scene = new Scene(pane, 600, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}