【发布时间】:2018-12-03 01:54:25
【问题描述】:
我有一个resizableImageView,图像的某些部分应该是可点击的。
我的想法是创建一个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 放置在与Image 内ImageView 相同的位置。 Image inside imageView_wheel 不断调整大小和改变它的位置,这完全没问题,但我不知道如何将它的大小和位置分配给gridPane_overlay。
我尝试将侦听器添加到各种 x/y 和宽度/高度属性,并且能够取得一些结果,但它停止工作,舞台变得最大化并继续设置完全无效的坐标。
更新:
似乎getParentInParent.getWidth() 和getParentInParent.getHeight() 在WrappedImageView 中返回了Image 的正确大小,现在我需要获取它的位置并将大小和位置都分配给网格。
更新 2:
基于cmets,我做了以下解决方案;
/**
*
* @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");
}
【问题讨论】:
-
首先,您不希望
GridPane影响整个事物的实际大小,因此您不应该添加任何会这样做的文本。相反,GridPane应该调整自己的大小以适应其父级可以给它的任何空间。其次,据我所知,所有透明节点都被排除在鼠标事件之外,因此使其完全透明可能行不通。 -
在
StackPane处添加鼠标点击事件可能会更容易,并使用它来计算点击发生的位置,然后根据此执行您需要的任何操作。
标签: javafx layout imageview resize coordinates