使点可拖动并存储新坐标 JavaFx

Make the points draggable and store the new coordinates JavaFx

我有这个:

Circle circle = null; 
List<Circle> circles = new ArrayList<>();

for(List row: list)  //list is list of coordinates i.e. [[200,100],[10,5.5],[15,100],[200,25]...]        
{
    circle = new Circle((double) row.get(0), (double) row.get(1), 4f);
    circle.setFill(Color.BLUE);

    Tooltip toolTipx = new Tooltip("The point is : " + (double) row.get(0));
    Tooltip.install(circle, toolTipx);

    circles.add(circle);
}
        
System.out.println(circles.size());
Pane pane = new Pane();
pane.getChildren().addAll(circles);

这完美地在 window 上绘制了上述点,工具提示描述了点的坐标。

现在,我想要的是创建可拖动的标绘点。这样我就可以将点拖动到 window 中的任何位置,并且新位置(拖动点的坐标)将被存储以显示在工具提示中或 window 末尾的固定标签中。

我遇到了 this (makeDraggable()),但找不到适合我的起点。

我怎样才能做到这一点?谢谢

下面是一个示例,说明如何在窗格中四处拖动。 只有两点,但您可以根据需要将它们放入列表中。 还有一个 helper class 可以更好、更轻松地处理一个点,还有一些 helper 方法可以使代码更容易阅读。

我喜欢将Main/fxml/Controller分开,但随时可以为您获取相关信息。

有文件:

控制器:

public class Controller implements Initializable {

    @FXML
    private Pane pane;
    @FXML
    private Label circlePos;
    @FXML
    private AnchorPane aPane;

    @Override
    public void initialize(URL location, ResourceBundle resources) {

        pane.prefWidthProperty().bind(aPane.widthProperty());
        pane.prefHeightProperty().bind(aPane.heightProperty());

        // Here are two circles to play around with but you can have as many as you want.
        // The center and radius are set randomly but within some borders to dont get rendered out of the visible pane.
        Circle circle = createCircle(new Point(randomBetween(5, 379), randomBetween(5, 200)), randomBetween(5, 10));
        circle.setFill(Color.BLUE);

        Circle circle1 = createCircle(new Point(randomBetween(5, 379), randomBetween(5, 200)), randomBetween(5, 10));
        circle1.setFill(Color.GREEN);

        pane.getChildren().addAll(circle, circle1);

    }

    /**
     * Creates a new Circle object with a given center and radius
     * It sets mouse events to be dragged on the pane and a label will be updated when the mouse hovers over
     * the circle
     *
     * @param center given center as Point object
     * @param radius given radius
     * @return created circle
     */
    private Circle createCircle(Point center, double radius) {
        Circle circle = new Circle(radius);
        circle.setCenterX(center.getX());
        circle.setCenterY(center.getY());

        // When the mouse hovers the circle sets the position label to this circle center's position
        circle.setOnMouseEntered(event -> setPosLabelText(circle));
        // When the mouse exits the circle (no more over it) resets the label to empty string.
        circle.setOnMouseExited(event -> circlePos.setText(""));
        // When a mouse drag is detected it sets the x and y coords of the circle's center to the mouse position
        // which is obtained from the event. 
        // Note: It is implemented so that the circle cannot be dragged out of the Pane, if it needed just remove
        // the if-s and set the CenterX/Y to event.getX/Y 
        circle.setOnMouseDragged(event -> {
            if (event.getX() < radius) {
                circle.setCenterX(radius);
            } else {
                circle.setCenterX(Math.min(event.getX(), pane.getWidth() - radius));
            }
            if (event.getY() < radius) {
                circle.setCenterY(radius);
            } else {
                circle.setCenterY(Math.min(event.getY(), pane.getHeight() - radius));
            }
            setPosLabelText(circle);
        });

        return circle;
    }

    /**
     * Sets the position label's text to the given circle's center coordinates.
     *
     * @param circle given circle
     */
    private void setPosLabelText(Circle circle) {
        circlePos.setText("x: " + (int) circle.getCenterX() + " y:" + (int) circle.getCenterY());
    }

    /**
     * Generates a random number between two integers
     *
     * @param from random number from inclusive
     * @param to   random number to exclusive
     * @return generated random number
     */
    private int randomBetween(int from, int to) {
        return new Random().nextInt(to - from) + from;
    }

    /**
     * Represents a 2D point
     */
    private static class Point {

        int x;
        int y;

        private Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        private int getX() {
            return x;
        }

        private int getY() {
            return y;
        }
    }
}

主要:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("View.fxml"));
        AnchorPane anchorPane =  loader.load();
        primaryStage.setScene(new Scene(anchorPane,384,216));
        primaryStage.show();
    }

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

Fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:id="aPane"
            fx:controller="drag.Controller">
    <VBox AnchorPane.topAnchor="0" AnchorPane.rightAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.bottomAnchor="0">
        <Pane fx:id="pane"/>
        <Label fx:id="circlePos">
            <padding>
                <Insets left="5" right="5"/>
            </padding>
        </Label>
    </VBox>
</AnchorPane>

希望对您有所帮助。

二手:

circle.setOnMouseDragged( event -> {
             circle.setCenterX(event.getX());
            circle.setCenterY(event.getY());
            });

在任何创建的 circles/points 上触发 mouseDragging 事件。 然后,只需将 centerX 和 centerY 重置为 event.getX()(目标 X 点)和 event.getY()(目标 Y 点)。

我的完整代码:

public void start(Stage stage) throws IOException 
    {    
            Label b = new Label("The coordinates are : "); 
            b.setLayoutX(190);
            b.setLayoutY(280);
            
            Label value = new Label(); 
            value.setLayoutX(320);
            value.setLayoutY(280);
            
          List<Circle> circles = new ArrayList<>();
        for(List row: list) 
        {
            Circle circle = new Circle((double) row.get(0), (double) row.get(1), 5f);
            circle.setFill(Color.BLUE);
            
            //this did the trick for me
            circle.setOnMouseDragged( event -> {
             circle.setCenterX(event.getX());
            circle.setCenterY(event.getY());
            });
            
            //for printing the values in a Label
             circle.setOnMouseClicked(new EventHandler<MouseEvent>() {
                    public void handle(MouseEvent event) {
                        System.out.println("Clicked");
                        value.setText(circle.getCenterX()+" , "+circle.getCenterY());
                    }
                });
            
            circles.add(circle);
        }
       
        System.out.println(circles.size());
        Pane pane = new Pane();

        pane.getChildren().addAll(circles);
        pane.getChildren().add(b);
        pane.getChildren().add(value);
 Scene scene = new Scene(pane, 600, 300);  
      
      //Setting title to the Stage 
      stage.setTitle("Show Points"); 
         
      //Adding scene to the stage 
      stage.setScene(scene); 

      scene.getStylesheets().add(Main.class.getResource("application.css").toExternalForm());
      //Displaying the contents of the stage 
      stage.show(); 
            
    } //end of start
    
    public static void main(String[] args) throws IOException {
        launch(args);
    }