英文:
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<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);
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'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;
}
}
}
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>
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 -> {
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("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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论