JavaFX 如何将节点居中到 ImageView(使用 setPreserveRation == true)?
JavaFX how to center a Node to ImageView (with setPreserveRation == true)?
我有一个 resizable ImageView
图像的某些部分应该可以点击。
我的想法是创建一个 GridPane
作为覆盖层并在其中放置几个透明按钮,这样当用户单击图像的某些部分时,他实际上会触发图像上的隐藏按钮:
<!-- parent that resizes from time to time -->
<StackPane>
<StackPane>
<!-- background image, preserves ration -->
<ImageView/>
<!-- overlay with transparent buttons -->
<!-- should be positionion exactly the same as Image inside ImageView -->
<GridPane>
<!- buttons here, columns == rows -->
</GridPane>
</StackPane>
</StackPane>
代码如下所示:
StackPane stackPane_wrapper = new StackPane();
stackPane_wrapper.setAlignment(Pos.CENTER);
//menu wheel
WrappedImageView imageView_wheel = new WrappedImageView();
imageView_wheel.setImage(new Image("images/menu-wheel.png"));
imageView_wheel.setPreserveRatio(true);
stackPane_wrapper.getChildren().add(imageView_wheel);
GridPane gridPane_overlay = new GridPane();
stackPane_wrapper.getChildren().add(gridPane_overlay);
int size = 20;
for (int i = 0; i < size; ++i)
{
ColumnConstraints columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(100.0d / size);
gridPane_overlay.getColumnConstraints().add(columnConstraints);
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setPercentHeight(100.0d / size);
gridPane_overlay.getRowConstraints().add(rowConstraints);
}
Button button = new Button();
button.setText("test");
//... set style to make this button transparent
gridPane_overlay.add(button, 3, 5, 2, 4);
我的问题是我无法将 gridPane_overlay
放在与 ImageView
内的 Image
相同的位置。 Image
inside imageView_wheel
不断调整大小并改变它的位置,这完全没问题,但我不知道如何将它的大小和位置分配给 gridPane_overlay
.
我已经尝试将侦听器添加到各种 x/y 和 width/height 属性,并且能够取得一些结果,但它在舞台最大化并继续设置完全无效的坐标时停止工作。
更新:
似乎 getParentInParent.getWidth()
和 getParentInParent.getHeight()
return WrappedImageView
中 Image
的正确大小,现在我需要获取它的位置并分配两个大小并定位到网格。
更新二:
根据评论,我制定了以下解决方案;
/**
*
* @param bounds bounds of image - result of {@link WrappedImageView#localToScene(Bounds)} from {@link WrappedImageView#getBoundsInLocal()}
* @param x click X - {@link MouseEvent#getSceneX()} minus {@link Bounds#getMinX()}
* @param y click Y - {@link MouseEvent#getSceneY()} minus {@link Bounds#getMinY()}
* @return
*/
private int determineClick(Bounds bounds, double x, double y)
{
double centerX = bounds.getWidth() / 2;
double centerY = bounds.getHeight() / 2;
double angle = Math.toDegrees(Math.atan2(x - centerX, y - centerY));
Point2D center = new Point2D(centerX, centerY);
Point2D click = new Point2D(x, y);
double distance = center.distance(click);
double diameter = centerX;
boolean isInner = distance < diameter * 0.6;
//-90 -> -135
if (angle <= -90 && angle > -135)
{
if (isInner)
{
return 10;
}
return 0;
}
//-135 -> -180/180
if (angle <= -135 && angle > -180)
{
if (isInner)
{
return 11;
}
return 1;
}
//-180/180 -> 135
if (angle <= 180 && angle > 135)
{
if (isInner)
{
return 12;
}
return 2;
}
//135 -> 90
if (angle <= 135 && angle > 90)
{
if (isInner)
{
return 13;
}
return 3;
}
//90 -> 45
if (angle <= 90 && angle > 45)
{
if (isInner)
{
return 14;
}
return 4;
}
//45 -> -0/0
if (angle <= 45 && angle > 0)
{
if (isInner)
{
return 15;
}
return 5;
}
//-0/0 -> -45
if (angle <= 0 && angle > -45)
{
if (isInner)
{
return 16;
}
return 6;
}
//-45 -> -90
if (angle <= -45 && angle > -90)
{
if (isInner)
{
return 17;
}
return 7;
}
throw new RuntimeException("Unable to determine point coordinates");
}
我也在想@Jai 在评论中提到的。您可以在 imageview 本身上包含鼠标单击事件,以确定单击其边界的哪个点。然后你可以确定点击位置的范围并执行你的逻辑。
类似...
imageView_wheel.setOnMouseClicked(e -> {
Bounds bounds = imageView_wheel.localToScene(imageView_wheel.getBoundsInLocal());
double x = e.getSceneX()-bounds.getMinX();
double y = e.getSceneY()-bounds.getMinY();
System.out.println("Clicked at :: "+x+","+y);
// Now you know at what point in the image bounds is clicked, compute your logic as per your needs..
});
我有一个 resizable ImageView
图像的某些部分应该可以点击。
我的想法是创建一个 GridPane
作为覆盖层并在其中放置几个透明按钮,这样当用户单击图像的某些部分时,他实际上会触发图像上的隐藏按钮:
<!-- parent that resizes from time to time -->
<StackPane>
<StackPane>
<!-- background image, preserves ration -->
<ImageView/>
<!-- overlay with transparent buttons -->
<!-- should be positionion exactly the same as Image inside ImageView -->
<GridPane>
<!- buttons here, columns == rows -->
</GridPane>
</StackPane>
</StackPane>
代码如下所示:
StackPane stackPane_wrapper = new StackPane();
stackPane_wrapper.setAlignment(Pos.CENTER);
//menu wheel
WrappedImageView imageView_wheel = new WrappedImageView();
imageView_wheel.setImage(new Image("images/menu-wheel.png"));
imageView_wheel.setPreserveRatio(true);
stackPane_wrapper.getChildren().add(imageView_wheel);
GridPane gridPane_overlay = new GridPane();
stackPane_wrapper.getChildren().add(gridPane_overlay);
int size = 20;
for (int i = 0; i < size; ++i)
{
ColumnConstraints columnConstraints = new ColumnConstraints();
columnConstraints.setPercentWidth(100.0d / size);
gridPane_overlay.getColumnConstraints().add(columnConstraints);
RowConstraints rowConstraints = new RowConstraints();
rowConstraints.setPercentHeight(100.0d / size);
gridPane_overlay.getRowConstraints().add(rowConstraints);
}
Button button = new Button();
button.setText("test");
//... set style to make this button transparent
gridPane_overlay.add(button, 3, 5, 2, 4);
我的问题是我无法将 gridPane_overlay
放在与 ImageView
内的 Image
相同的位置。 Image
inside imageView_wheel
不断调整大小并改变它的位置,这完全没问题,但我不知道如何将它的大小和位置分配给 gridPane_overlay
.
我已经尝试将侦听器添加到各种 x/y 和 width/height 属性,并且能够取得一些结果,但它在舞台最大化并继续设置完全无效的坐标时停止工作。
更新:
似乎 getParentInParent.getWidth()
和 getParentInParent.getHeight()
return WrappedImageView
中 Image
的正确大小,现在我需要获取它的位置并分配两个大小并定位到网格。
更新二:
根据评论,我制定了以下解决方案;
/**
*
* @param bounds bounds of image - result of {@link WrappedImageView#localToScene(Bounds)} from {@link WrappedImageView#getBoundsInLocal()}
* @param x click X - {@link MouseEvent#getSceneX()} minus {@link Bounds#getMinX()}
* @param y click Y - {@link MouseEvent#getSceneY()} minus {@link Bounds#getMinY()}
* @return
*/
private int determineClick(Bounds bounds, double x, double y)
{
double centerX = bounds.getWidth() / 2;
double centerY = bounds.getHeight() / 2;
double angle = Math.toDegrees(Math.atan2(x - centerX, y - centerY));
Point2D center = new Point2D(centerX, centerY);
Point2D click = new Point2D(x, y);
double distance = center.distance(click);
double diameter = centerX;
boolean isInner = distance < diameter * 0.6;
//-90 -> -135
if (angle <= -90 && angle > -135)
{
if (isInner)
{
return 10;
}
return 0;
}
//-135 -> -180/180
if (angle <= -135 && angle > -180)
{
if (isInner)
{
return 11;
}
return 1;
}
//-180/180 -> 135
if (angle <= 180 && angle > 135)
{
if (isInner)
{
return 12;
}
return 2;
}
//135 -> 90
if (angle <= 135 && angle > 90)
{
if (isInner)
{
return 13;
}
return 3;
}
//90 -> 45
if (angle <= 90 && angle > 45)
{
if (isInner)
{
return 14;
}
return 4;
}
//45 -> -0/0
if (angle <= 45 && angle > 0)
{
if (isInner)
{
return 15;
}
return 5;
}
//-0/0 -> -45
if (angle <= 0 && angle > -45)
{
if (isInner)
{
return 16;
}
return 6;
}
//-45 -> -90
if (angle <= -45 && angle > -90)
{
if (isInner)
{
return 17;
}
return 7;
}
throw new RuntimeException("Unable to determine point coordinates");
}
我也在想@Jai 在评论中提到的。您可以在 imageview 本身上包含鼠标单击事件,以确定单击其边界的哪个点。然后你可以确定点击位置的范围并执行你的逻辑。
类似...
imageView_wheel.setOnMouseClicked(e -> {
Bounds bounds = imageView_wheel.localToScene(imageView_wheel.getBoundsInLocal());
double x = e.getSceneX()-bounds.getMinX();
double y = e.getSceneY()-bounds.getMinY();
System.out.println("Clicked at :: "+x+","+y);
// Now you know at what point in the image bounds is clicked, compute your logic as per your needs..
});