Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javafx 根据放大/缩小时的可见区域在方框正面显示文本_Javafx_Javafx 8_Javafx 3d - Fatal编程技术网

Javafx 根据放大/缩小时的可见区域在方框正面显示文本

Javafx 根据放大/缩小时的可见区域在方框正面显示文本,javafx,javafx-8,javafx-3d,Javafx,Javafx 8,Javafx 3d,我有一个示例3D应用程序(通过引用Javafx示例3DViewer构建),它有一个通过布局框和窗格创建的表: 工作台以wrt(0,0,0)坐标为中心,相机最初位于-z位置 它具有基于对象的摄影机z位置的放大/缩小功能。 放大/缩小对象的边界时,父对象增加/减少,即面面积增加/减少。因此,我们的想法是,当我们有更多的面积(总是限制在脸内)时,放更多的文本,当脸面积太小时,放更少的文本或没有文本。我可以使用此节点层次结构来实现这一点: 以及根据每次放大/缩小时的方框调整窗格大小(以及管理vBox

我有一个示例3D应用程序(通过引用Javafx示例3DViewer构建),它有一个通过布局框和窗格创建的表:

工作台以wrt(0,0,0)坐标为中心,相机最初位于-z位置

它具有基于对象的摄影机z位置的放大/缩小功能。 放大/缩小对象的边界时,父对象增加/减少,即面面积增加/减少。因此,我们的想法是,当我们有更多的面积(总是限制在脸内)时,放更多的文本,当脸面积太小时,放更少的文本或没有文本。我可以使用此节点层次结构来实现这一点:

以及根据每次放大/缩小时的方框调整窗格大小(以及管理vBox和其中的文本数)

现在的问题是,只要第一次将文本添加到vBox中,table boundsInParent就会给出错误的结果(在顶部显示边界框)。在进一步放大/缩小时,将给出正确的边界框,并且不会关闭

以下是UIpane3D类:

public class UIPane3D extends Pane
{
VBox textPane;

ArrayList<String> infoTextKeys = new ArrayList<>();
ArrayList<Text> infoTextValues = new ArrayList<>();

Rectangle bgCanvasRect = null;

final double fontSize = 16.0;   

public UIPane3D() {
    setMouseTransparent(true);
    textPane = new VBox(2.0)
}

public void updateContent() {
    textPane.getChildren().clear();
    getChildren().clear();

    for (Text textNode : infoTextValues) {
        textPane.getChildren().add(textNode);
        textPane.autosize();
        if (textPane.getHeight() > getHeight()) {
            textPane.getChildren().remove(textNode);
            textPane.autosize();

            break;
        }
    }

    textPane.setTranslateY(getHeight() / 2 - textPane.getHeight() / 2.0);

    bgCanvasRect = new Rectangle(getWidth(), getHeight());
    bgCanvasRect.setFill(Color.web(Color.BURLYWOOD.toString(), 0.10));
    bgCanvasRect.setVisible(true);

    getChildren().addAll(bgCanvasRect, textPane);
}


public void resetInfoTextMap()
{
    if (infoTextKeys != null || infoTextValues != null) 
    {
        try 
        {
            infoTextKeys.clear();
            infoTextValues.clear();     
        } catch (Exception e){e.printStackTrace();}
    }
}


public void updateInfoTextMap(String pKey, String pValue)
{
    int index = -1;
    boolean objectFound = false;

    for (String string : infoTextKeys) 
    {
        index++;
        if(string.equals(pKey))
        {
            objectFound = true;
            break;
        }
    }

    if(objectFound)
    {
        infoTextValues.get(index).setText(pValue.toUpperCase());
    }
    else
    {
        if (pValue != null) 
        {   
            Text textNode = new Text(pValue.toUpperCase());
            textNode.setFont(Font.font("Consolas", FontWeight.BLACK, FontPosture.REGULAR, fontSize));
            textNode.wrappingWidthProperty().bind(widthProperty());
            textNode.setTextAlignment(TextAlignment.CENTER);
            infoTextKeys.add(pKey);
            infoTextValues.add(textNode);
        }
    }
}
两件事:

  • 首次添加文本时,table3D的boundsInParent未正确更新

  • 在3D节点上放置文本的正确方式是什么?我不得不做大量的操作,才能按要求带来文本


  • 共享代码。

    对于第一个问题,关于在滚动新文本项后可以注意到的“跳跃”:

    在深入研究之后,我注意到
    UIPane3D
    有一个
    vboxtextpane
    ,其中包含不同的文本节点。每次调用
    updateContent
    时,它都会尝试添加文本节点,但会检查vbox的高度是否始终低于窗格的高度,否则将删除该节点:

        for (Text textNode : infoTextValues) {
            textPane.getChildren().add(textNode);
            textPane.autosize();
            if (textPane.getHeight() > getHeight()) {
                textPane.getChildren().remove(textNode);
                textPane.autosize();
                break;
            }
        }
    
    虽然这基本上是正确的,但当您将节点添加到场景中时,您无法立即获取
    textPane.getHeight()
    ,因为它尚未布局,您必须等待下一个脉冲。这就是为什么下次滚动时,高度正确且边界框放置正确的原因

    强制布局并获得
    textNode
    的正确高度的一种方法是强制css和布局传递:

        for (Text textNode : infoTextValues) {
            textPane.getChildren().add(textNode);
    
            // force css and layout
            textPane.applyCss();
            textPane.layout();
    
            textPane.autosize();
            if (textPane.getHeight() > getHeight()) {
                textPane.getChildren().remove(textNode);
                textPane.autosize();
                break;
            }
        }
    
    请注意:

    此方法[
    applyCss
    ]通常不需要直接调用,但可以与
    Parent.layout()
    结合使用,以在下一个脉冲之前调整节点大小,或者如果场景不在某个阶段中

    对于第二个问题,关于向三维形状添加文本的不同解决方案

    事实上,将(2D)文本放置在3D形状的顶部是相当困难的,并且需要复杂的数学(顺便说一句,这在项目中做得非常好)

    另一种方法是避免直接使用二维节点

    正是在上一篇文章中,我将其“写入”到一幅图像中,后来我将其用作3D形状的材质漫反射贴图

    内置3D
    将相同的图像放置在每个人脸上,因此无法工作。我们可以实现一个3D棱镜,也可以利用FXyz3D中的
    CuboidMesh
    节点

    更换
    UIPaneBoxGroup
    中的

    final CuboidMesh contentShape;
    UIPane3D displaypane = null;
    PhongMaterial shader = new PhongMaterial();
    final Color pColor;
    
    public UIPaneBoxGroup(final double pWidth, final double pHeight, final double pDepth, final Color pColor) { 
        contentShape = new CuboidMesh(pWidth, pHeight, pDepth);
        this.pColor = pColor;
        contentShape.setMaterial(shader);
        getChildren().add(contentShape);
        addInfoUIPane();
    }
    
    并添加
    generateNet
    方法:

    private Image generateNet(String string) {
    
        GridPane grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
    
        Label label5 = new Label(string);
        label5.setFont(Font.font("Consolas", FontWeight.BLACK, FontPosture.REGULAR, 40));
        GridPane.setHalignment(label5, HPos.CENTER);
    
        grid.add(label5, 3, 1);
    
        double w = contentShape.getWidth() * 10; // more resolution
        double h = contentShape.getHeight() * 10;
        double d = contentShape.getDepth() * 10;
        final double W = 2 * d + 2 * w;
        final double H = 2 * d + h;
    
        ColumnConstraints col1 = new ColumnConstraints();
        col1.setPercentWidth(d * 100 / W);
        ColumnConstraints col2 = new ColumnConstraints();
        col2.setPercentWidth(w * 100 / W);
        ColumnConstraints col3 = new ColumnConstraints();
        col3.setPercentWidth(d * 100 / W);
        ColumnConstraints col4 = new ColumnConstraints();
        col4.setPercentWidth(w * 100 / W);
        grid.getColumnConstraints().addAll(col1, col2, col3, col4);
    
        RowConstraints row1 = new RowConstraints();
        row1.setPercentHeight(d * 100 / H);
        RowConstraints row2 = new RowConstraints();
        row2.setPercentHeight(h * 100 / H);
        RowConstraints row3 = new RowConstraints();
        row3.setPercentHeight(d * 100 / H);
        grid.getRowConstraints().addAll(row1, row2, row3);
        grid.setPrefSize(W, H);
        grid.setBackground(new Background(new BackgroundFill(pColor, CornerRadii.EMPTY, Insets.EMPTY)));
        new Scene(grid);
        return grid.snapshot(null, null);
    }
    
    现在可以删除所有与2D相关的代码(包括
    displaypane
    ),并在滚动事件后获得图像:

    public void refreshBomUIPane() {        
        Image net = generateNet(displaypane.getText());
        shader.setDiffuseMap(net);
    }
    
    其中在
    UIPane3D
    中:

    public String getText() {
        return infoTextKeys.stream().collect(Collectors.joining("\n"));
    }
    
    我还移除了边界框以获得此图片:


    我没有讨论过可以添加到VBox中的文本节点的数量、字体大小,也没有讨论过避免在每个卷轴上生成图像的策略:只有当文本发生变化时,才应该这样做。因此,当前的方法非常缓慢,但可以显著改进,因为每个框只有三个可能的图像。

    如果您共享代码,可能会更好,至少我们可以使用它来重现您的问题?@JoséPereda共享代码链接,主类:JFXApp.javagot,布局在下一个脉冲之前通过,谢谢。对于第二个问题,使用图像对3D对象进行着色(使用FXyz3D库和网格方法在不同的面上显示太多不同的文本)是显示文本和避免2D的好选择。但后来我想让那些3D框交互(有一个按钮等),我选择了窗格,而不是他们。不确定在3D中混合2D是否是一个好的设计?我不喜欢在同一次场景中混合2D和3D。当然,这取决于您的用例。如果您想添加交互,甚至可以尝试3D(结合pickResult和小网格动画…),也可以尝试2D面板/弹出窗口/覆盖(如果您需要文本字段左右,不需要在同一子场景中,请参阅)。这与您的不同,但可以为您提供有关网格交互的提示。
    public String getText() {
        return infoTextKeys.stream().collect(Collectors.joining("\n"));
    }