我想实现一个JavaFX布局组件。最终目标是使该组件允许夹层状堆叠多个组件,然后剪切该堆栈并将生成的剪切节点放置到标准布局组件中。
当我实现组件时,一切都很顺利,但有一个例外:我无法正确返回组件的layoutBounds。我花了很多时间在谷歌搜索和研究,但没有找到(谷歌)也没有理解(在JavaFX源代码中)如何报告自制组件的布局界限。
一些细节:Node.getLayoutBounds()是final,因此无法覆盖。 layoutBoundsProperty是只读的,无法修改。在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());
}
}
答案 0 :(得分:0)
我找到了JDK-8156089 : Provide official API so subclasses can override layout bounds computation
所以我似乎必须等待该功能请求的实现,这在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());
}
}