如何实现 JavaFX 节点,以便它可以返回计算的 layoutBounds?



我想实现一个JavaFX布局组件。最终目标是使该组件允许多个组件的三明治式堆叠,然后裁剪此堆栈并将生成的裁剪节点放入标准布局组件中。

当我实现组件时,一切都很顺利,但有一个例外:我无法正确返回组件的 layoutBounds。 我花了很多时间在谷歌上搜索和研究,但没有找到(谷歌)也不明白(在JavaFX源代码中)如何报告自制组件的布局边界。

一些细节:Node.getLayoutBounds() 是最终的,所以不能被覆盖。 布局边界属性是只读的,不能修改。在 JavaFx Node 实现中有许多帮助程序操作和看似有用的注释,但都引用了包私有功能,无法从外部访问。

所以问题是:如何实现一个组件,以便它可以计算自己的布局边界,并在像getLayoutBounds()这样的调用中将其报告给它的上下文?

下面是可执行的源代码。 不确定它是否有很大帮助,但它在正确的地方提出了正确的问题。

package stackoverflow.demo;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class LayoutBoundsTest extends Application {
public static void main(String[] args) {
Application.launch(args);
}
/**
* How to implement this component so that it can return
* its own computed layout bounds?
*/
public static class CenterPane extends StackPane
{
public CenterPane()
{
}
@Override
public boolean isResizable()
{
return false;
}
protected void addLayoutComponent( Node node )
{
Bounds bounds = node.getLayoutBounds();
// How to set 'bounds' on this CenterPane so that
// they are reported via CenterPane.getLayoutBounds()?
getChildren().add( node );
}
}
@Override
public void start(Stage stage) {
CenterPane centerPane = new CenterPane();
centerPane.addLayoutComponent( new Circle( 30, Color.YELLOW ) );
Node circle = new Circle( 30, Color.GREEN );
VBox root = new VBox();
root.getChildren().addAll(centerPane, circle);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Testing LayoutBounds");
stage.show();
// Both calls below should report the same layout bounds.
System.out.println("b0=" + centerPane.getLayoutBounds());
System.out.println("b2=" + circle.getLayoutBounds());
}
}

我发现JDK-8156089:提供官方API,以便子类可以覆盖布局边界计算

因此,我似乎必须等待该功能请求的实现,该功能请求在Java 9中不可用。 同时,解决方法如下:

package stackoverflow.demo;
import java.lang.reflect.Field;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class LayoutBoundsTest extends Application {
public static void main(String[] args) {
Application.launch(args);
}
/**
* How to implement this component so that it can return
* its own computed layout bounds?
*/
public static class CenterPane extends StackPane
{
public CenterPane()
{
}
@Override
public boolean isResizable()
{
return false;
}
protected void addLayoutComponent( Node node )
{
Bounds bounds = node.getLayoutBounds();
setBounds( bounds );
getChildren().add( node );
}
/**
* Do it the hard way (and don't try that at home).
*/
private void setBounds( Bounds bounds )
{
try
{
// In Java 8 and 9 there's a private field in the
// Region that is lazy-initialized.  We set this
// manually.
Field f = Region.class.getDeclaredField( "boundingBox" );
f.setAccessible( true );
f.set( this, bounds );
}
catch ( Exception e )
{
throw new RuntimeException( "No good.", e );
}
}
}
@Override
public void start(Stage stage) {
CenterPane centerPane = new CenterPane();
centerPane.addLayoutComponent( new Circle( 30, Color.YELLOW ) );
Node circle = new Circle( 30, Color.GREEN );
VBox root = new VBox();
root.getChildren().addAll(centerPane, circle);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Testing LayoutBounds");
stage.show();
// Both calls below should report the same layout bounds.
System.out.println("b0=" + centerPane.getLayoutBounds());
System.out.println("b2=" + circle.getLayoutBounds());
}
}

最新更新