Thad Tayo
Thad Tayo

Reputation: 1

While-loop causes window to crash in JavaFX

I am trying to create a very simple, easy-to-use program that actively reads and displays the position of the mouse. I have seen many tutorials that create programs that read the position of the mouse only when it is inside the window of the GUI application, or after hitting a button, but I want one that displays the position of the mouse in all areas of the screen. This is what I have:

import java.awt.MouseInfo;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class MouseCoordinates extends Application{

     public static void main(String[] args) {

          launch();

     }

     public void start(Stage primaryStage) throws Exception{
          primaryStage.setTitle("Mouse Reader");
          Label x = new Label();
          Label y = new Label();
          StackPane layout = new StackPane();
          layout.getChildren().addAll(x, y);

          Scene scene = new Scene(layout, 600, 500);
          primaryStage.setScene(scene);
          primaryStage.show ();

          double mouseX = 1.0;
          double mouseY = 1.0;

          while(true){
               mouseX = MouseInfo.getPointerInfo().getLocation().getX();
               mouseY = MouseInfo.getPointerInfo().getLocation().getY();
               x.setText("" + mouseX);
               y.setText("" + mouseY);
          }
     }
}

I understand that this while-loop is the cause of the window crashing, but I can not figure out a way around it. Can anyone explain why I can not use a while-loop for JavaFX, as well as a way to solve this?

Upvotes: 0

Views: 902

Answers (1)

davidxxx
davidxxx

Reputation: 131456

Your start() method don't have any change to exit the loop and therefore to return as you defined an infinite loop : while(true){...} without return statement.

Why not use a Timeline ?

Timeline timeLine = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {

    @Override
    public void handle(ActionEvent event) {
        mouseX = MouseInfo.getPointerInfo().getLocation().getX();
        mouseY = MouseInfo.getPointerInfo().getLocation().getY();
        x.setText("" + mouseX);
        y.setText("" + mouseY);
    }
}));
timeLine.setCycleCount(Timeline.INDEFINITE);
timeLine.play();

or with a lambda :

Timeline timeLine = new Timeline(new KeyFrame(Duration.seconds(1), 
    e -> {
           mouseX = MouseInfo.getPointerInfo().getLocation().getX();
           mouseY = MouseInfo.getPointerInfo().getLocation().getY();
           x.setText("" + mouseX);
           y.setText("" + mouseY);
         }   
));
timeLine.setCycleCount(Timeline.INDEFINITE);
timeLine.play();

Another way to address your requirement could be using addEventFilter( MouseEvent.MOUSE_MOVED) on the StackPane object :

layout.addEventFilter(MouseEvent.MOUSE_MOVED, e -> {             
       x.setText("" + e.getScreenX());
       y.setText("" + e.getScreenY());
});

The MouseEvent class provides both X and Y absolute position on the device and on the source component :

getScreenX()

Returns absolute horizontal position of the event.

getScreenY()

Returns the absolute vertical y position of the event

getX();

Horizontal position of the event relative to the origin of the MouseEvent's source.

getY();

Vertical position of the event relative to the origin of the MouseEvent's source.

Upvotes: 5

Related Questions