使点能够被拖动并存储新坐标 JavaFx

huangapple go评论89阅读模式
英文:

Make the points draggable and store the new coordinates JavaFx

问题

我有以下代码:

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

for(List row: list)
{
    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);

这段代码可以在窗口上绘制指定的点,并且工具提示显示了点的坐标。

现在,我想要实现的是让绘制的点可以拖动。这样我就可以在窗口中拖动点到任意位置,新位置(拖动点的坐标)将会被存储,然后显示在工具提示中或者窗口底部的固定标签中。

我看到了这个链接(makeDraggable()),但是对于我来说没有一个合适的起点。

请问如何实现这个功能?谢谢。

英文:

I have this:

Circle circle = null; 
List&lt;Circle&gt; circles = new ArrayList&lt;&gt;();

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(&quot;The point is : &quot; + (double) row.get(0));
	Tooltip.install(circle, toolTipx);

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

This plots the said points on the window perfectly and the tooltip depicts the coordinate of the point.

Now, what I want is to create the plotted points draggable. So that I can drag the points anywhere in the window and the new location(coordinates of the dragged points) is stored to show in the tooltip or in a fixed Label at the end of the window.

I came across this (makeDraggable()), but couldn't find a starting point for me.

How can I achieve this? Thanks.

答案1

得分: 1

以下是您要求的代码部分的中文翻译:

这是一个示例,演示如何在面板中实现拖动。只有两个点,但您可以将它们放在列表中,任意多个。
还有一个辅助类,用于更好、更容易地处理点,以及一些辅助方法,使代码更易于阅读。

我喜欢将主要部分/fxml/控制器分开,但随时获取您需要的相关信息。

以下是这些文件:

控制器:

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());

        // 这里有两个圆可以玩耍,但您可以拥有任意数量的圆。
        // 中心点和半径是随机设置的,但在一定范围内,以免渲染到可见面板外部。
        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);
    }

    /**
     * 使用给定的中心点和半径创建新的圆对象
     * 设置鼠标事件以在面板上拖动,并在鼠标悬停在圆上时更新标签
     *
     * @param center 给定的中心点作为Point对象
     * @param radius 给定的半径
     * @return 创建的圆
     */
    private Circle createCircle(Point center, double radius) {
        Circle circle = new Circle(radius);
        circle.setCenterX(center.getX());
        circle.setCenterY(center.getY());

        // 当鼠标悬停在圆上时,将位置标签设置为此圆心的位置
        circle.setOnMouseEntered(event -> setPosLabelText(circle));
        // 当鼠标退出圆时(不再悬停在上面),将标签重置为空字符串。
        circle.setOnMouseExited(event -> circlePos.setText(""));
        // 当检测到鼠标拖动时,将圆的中心点的x和y坐标设置为从事件中获取的鼠标位置。
        // 注意:它是这样实现的,以便圆不能拖出面板,如果需要,只需删除if语句并将CenterX/Y设置为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;
    }

    /**
     * 将位置标签的文本设置为给定圆的中心坐标。
     *
     * @param circle 给定的圆
     */
    private void setPosLabelText(Circle circle) {
        circlePos.setText("x: " + (int) circle.getCenterX() + " y:" + (int) circle.getCenterY());
    }

    /**
     * 生成两个整数之间的随机数
     *
     * @param from 起始范围(包括)
     * @param to   结束范围(不包括)
     * @return 生成的随机数
     */
    private int randomBetween(int from, int to) {
        return new Random().nextInt(to - from) + from;
    }

    /**
     * 表示2D点
     */
    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;
        }
    }
}

Main:

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>

希望这对您有所帮助。

英文:

Here is an example how you can achieve this dragging around in the pane.
There are only two points but you can have them in a list as many as you want.
There are also a helper class for better and easier handling of a point and a few helper methods to make the code a little bit easier to read.

I like to separate the Main/fxml/Controller but feel free to get the relevant informations for you.

There are the files:

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&#39;s position
circle.setOnMouseEntered(event -&gt; setPosLabelText(circle));
// When the mouse exits the circle (no more over it) resets the label to empty string.
circle.setOnMouseExited(event -&gt; circlePos.setText(&quot;&quot;));
// When a mouse drag is detected it sets the x and y coords of the circle&#39;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 -&gt; {
if (event.getX() &lt; radius) {
circle.setCenterX(radius);
} else {
circle.setCenterX(Math.min(event.getX(), pane.getWidth() - radius));
}
if (event.getY() &lt; radius) {
circle.setCenterY(radius);
} else {
circle.setCenterY(Math.min(event.getY(), pane.getHeight() - radius));
}
setPosLabelText(circle);
});
return circle;
}
/**
* Sets the position label&#39;s text to the given circle&#39;s center coordinates.
*
* @param circle given circle
*/
private void setPosLabelText(Circle circle) {
circlePos.setText(&quot;x: &quot; + (int) circle.getCenterX() + &quot; y:&quot; + (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;
}
}
}

Main:

public class Main extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource(&quot;View.fxml&quot;));
AnchorPane anchorPane =  loader.load();
primaryStage.setScene(new Scene(anchorPane,384,216));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Fxml:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;?import javafx.geometry.Insets?&gt;
&lt;?import javafx.scene.control.Label?&gt;
&lt;?import javafx.scene.layout.AnchorPane?&gt;
&lt;?import javafx.scene.layout.Pane?&gt;
&lt;?import javafx.scene.layout.VBox?&gt;
&lt;AnchorPane xmlns=&quot;http://javafx.com/javafx&quot;
xmlns:fx=&quot;http://javafx.com/fxml&quot;
fx:id=&quot;aPane&quot;
fx:controller=&quot;drag.Controller&quot;&gt;
&lt;VBox AnchorPane.topAnchor=&quot;0&quot; AnchorPane.rightAnchor=&quot;0&quot; AnchorPane.leftAnchor=&quot;0&quot; AnchorPane.bottomAnchor=&quot;0&quot;&gt;
&lt;Pane fx:id=&quot;pane&quot;/&gt;
&lt;Label fx:id=&quot;circlePos&quot;&gt;
&lt;padding&gt;
&lt;Insets left=&quot;5&quot; right=&quot;5&quot;/&gt;
&lt;/padding&gt;
&lt;/Label&gt;
&lt;/VBox&gt;
&lt;/AnchorPane&gt;

Hope it helps.

答案2

得分: 0

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

将上述代码用于任何创建的圆/点以触发鼠标拖拽事件。
然后,通过使用 event.getX()(目标 X 点)和 event.getY()(目标 Y 点)简单地重置 centerX 和 centerY。

完整代码:

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);
}
英文:

Used :

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

to trigger the mouseDragging event on any created circles/points.
Then, simply reset the centerX and centerY with event.getX()(the destination X point) and event.getY()(the destination Y point).

My Full Code :

public void start(Stage stage) throws IOException 
{    
Label b = new Label(&quot;The coordinates are : &quot;); 
b.setLayoutX(190);
b.setLayoutY(280);
Label value = new Label(); 
value.setLayoutX(320);
value.setLayoutY(280);
List&lt;Circle&gt; circles = new ArrayList&lt;&gt;();
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 -&gt; {
circle.setCenterX(event.getX());
circle.setCenterY(event.getY());
});
//for printing the values in a Label
circle.setOnMouseClicked(new EventHandler&lt;MouseEvent&gt;() {
public void handle(MouseEvent event) {
System.out.println(&quot;Clicked&quot;);
value.setText(circle.getCenterX()+&quot; , &quot;+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(&quot;Show Points&quot;); 
//Adding scene to the stage 
stage.setScene(scene); 
scene.getStylesheets().add(Main.class.getResource(&quot;application.css&quot;).toExternalForm());
//Displaying the contents of the stage 
stage.show(); 
} //end of start
public static void main(String[] args) throws IOException {
launch(args);
}

huangapple
  • 本文由 发表于 2020年9月15日 17:58:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/63899438.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定