如何在JavaFX中显示非矩形的窗格?

如何在JavaFX中显示非矩形的窗格?,javafx,flowpane,Javafx,Flowpane,我在JavaFX中遇到了一个问题 这就是Jasperserver(一个服务器)、Adhoc模型(一个服务器模型)中显示的内容 如您所见,粉红色区域是一种HTML标记。它可以显示非矩形形状的UI。像俄罗斯方块 然而,我正试图在JavaFX中做同样的事情,但失败了 我使用了一个流程窗格作为窗格a,并在窗格a中添加了一些标签。然后我使用了一个小流程窗格作为窗格B,也在窗格B中添加了一些标签。最后,我将窗格B添加到窗格a中 如下图所示 如您所见,我未能显示非矩形形状的窗格B。我认为要做到这一点并不

我在JavaFX中遇到了一个问题

这就是Jasperserver(一个服务器)、Adhoc模型(一个服务器模型)中显示的内容

如您所见,粉红色区域是一种HTML
  • 标记。它可以显示非矩形形状的UI。像俄罗斯方块

    然而,我正试图在JavaFX中做同样的事情,但失败了

    我使用了一个流程窗格作为窗格a,并在窗格a中添加了一些标签。然后我使用了一个小流程窗格作为窗格B,也在窗格B中添加了一些标签。最后,我将窗格B添加到窗格a中

    如下图所示

    如您所见,我未能显示非矩形形状的窗格B。我认为要做到这一点并不容易

    有人能帮我吗?您的答复将不胜感激。多谢各位


    如果有人需要我的密码,请告诉我。我将重写一些简单的代码并放在这里。

    非常感谢@James\u D

    我编写了一个自定义窗格,它扩展了FlowPane,并重写了layoutChildren()函数

    它起作用了

    以下是我的代码:

    import java.util.ArrayList;
    import java.util.List;
    
    import javafx.geometry.HPos;
    import javafx.geometry.Insets;
    import javafx.geometry.VPos;
    import javafx.scene.Node;
    import javafx.scene.control.Label;
    import javafx.scene.layout.FlowPane;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.Region;
    
    public class LayoutFlowPane extends FlowPane {
    
        private class Child {
            Node node;
            double x, y, w, h;
            double blft, midy;
            public Child(Node node,
                    double x, double y, double w, double h,
                    double blft, double midy) {
                super();
                this.node = node;
                this.x = x;
                this.y = y;
                this.w = w;
                this.h = h;
                this.blft = blft;
                this.midy = midy;
            }
        }
    
        private List<Child> children = new ArrayList<>();
        private List<Double> midys = new ArrayList<>();
    
        public LayoutFlowPane() {
            super();
        }
    
        @Override protected void layoutChildren() {
    
            super.layoutChildren();
    
            Insets insets = getInsets();
            double width = getWidth();
            double height = getHeight();
            double top = insets.getTop();
            double left = insets.getLeft();
            double bottom = insets.getBottom();
            double right = insets.getRight();
            double maxw = width - left - right;
            double maxh = height - top - bottom;
            double hgap = snapSpace(this.getHgap());
            double vgap = snapSpace(this.getVgap());
    
            storeChildren();
    
            adjustChildren(maxw, maxh, hgap, vgap);
    
            children.forEach(child -> {
                layoutInArea(
                        child.node, child.x, child.y, 
                        child.w, child.h, child.blft, getMargin(child.node),
                        getColumnHalignmentInternal(), getRowValignmentInternal()
                );
            });
        }
    
        private void storeChildren() {
            children = new ArrayList<>();
            for (int i = 0; i < getChildren().size(); i ++) {
                Node child = getChildren().get(i);
                double x = child.getLayoutX();
                double y = child.getLayoutY();
                double w = 0;
                double h = 0;
                if (child instanceof Region) {
                    Region region = (Region) child;
                    w = region.getWidth();
                    h = region.getHeight();
                } else {
                    throw new UnknowTypeException("Unknow type found.");
                }
                double blft = child.getBaselineOffset();
                double midy = (y + y + h) / 2;
                Child newChild = new Child(child, x, y, w, h, blft, midy);
                children.add(newChild);
            }
            midys = new ArrayList<>();
            for (int i = 0; i < children.size(); i ++) {
                Child child = children.get(i);
                if (midys.isEmpty() || midys.get(midys.size()-1) != child.midy) {
                    midys.add(child.midy);
                }
            }
        }
    
        private void adjustChildren(double maxw, double maxh, double hgap, double vgap) {
            for (int i = 1; i < children.size(); i ++) { // begin with 1
                Child pc = children.get(i-1);
                Child ch = children.get(i);
                boolean bothGridPane = (pc.node instanceof GridPane) && (ch.node instanceof GridPane); 
                double x = pc.x + pc.w + (bothGridPane ? 0 : hgap);
                double midy;
                if (x + ch.w <= maxw) { // ThisLine
                    midy = pc.midy;
                    ch.x = x;
                    ch.y = gety(ch.y, ch.midy, midy);
                    ch.midy = midy;
                } else { // NextLine
                    midy = getNextMidy(pc.midy);
                    ch.x = children.get(0).x;
                    ch.y = gety(ch.y, ch.midy, midy);
                    ch.midy = midy;
                }
            }
        }
    
        private double getNextMidy(double midy) {
            for (int i = 0; i < midys.size(); i ++) {
                if (i + 1 < midys.size() && midys.get(i) == midy && midys.get(i+1) != midy) {
                    return midys.get(i+1);
                } else if (i + 1 == midys.size() && midys.get(i) == midy) {
                    return midys.get(i);
                }
            }
            throw new NotFoundException("Next midy not found.");
        }
    
        private double gety(double oldy, double oldMidy, double newMidy) {
            return oldy + (newMidy - oldMidy);
        }
    
        private HPos getColumnHalignmentInternal() {
            HPos localPos = getColumnHalignment();
            return null == localPos ? HPos.LEFT : localPos;
        }
    
        private VPos getRowValignmentInternal() {
            VPos localPos =  getRowValignment();
            return null == localPos ? VPos.CENTER : localPos;
        }
    
        private class UnknowTypeException extends RuntimeException {
            private static final long serialVersionUID = 1L;
            public UnknowTypeException(String message) {
                super(message);
            }
        }
    
        private class NotFoundException extends RuntimeException {
            private static final long serialVersionUID = 1L;
            public NotFoundException(String message) {
                super(message);
            }
        }
    
    }
    
    import java.util.ArrayList;
    导入java.util.List;
    导入javafx.geometry.HPos;
    导入javafx.geometry.Insets;
    导入javafx.geometry.VPos;
    导入javafx.scene.Node;
    导入javafx.scene.control.Label;
    导入javafx.scene.layout.FlowPane;
    导入javafx.scene.layout.GridPane;
    导入javafx.scene.layout.Region;
    公共类LayoutFlowPane扩展了FlowPane{
    私班儿童{
    节点;
    双x,y,w,h;
    双盲板,midy;
    公共子节点(节点,
    双x,双y,双w,双h,
    双盲双盲){
    超级();
    this.node=节点;
    这个.x=x;
    这个。y=y;
    这个.w=w;
    这个,h=h;
    this.blft=blft;
    this.midy=midy;
    }
    }
    private List children=new ArrayList();
    private List midys=new ArrayList();
    公共布局流程窗格(){
    超级();
    }
    @重写受保护的void layoutChildren(){
    super.layoutChildren();
    Insets Insets=getInsets();
    double width=getWidth();
    双倍高度=getHeight();
    double-top=insets.getTop();
    左双=insets.getLeft();
    双底=insets.getBottom();
    double right=insets.getRight();
    double maxw=宽度-左-右;
    double maxh=高度-顶部-底部;
    double hgap=snapSpace(this.getHgap());
    double vgap=snapSpace(this.getVgap());
    储存儿童();
    调整子项(最大值、最大值、hgap、vgap);
    children.forEach(child->{
    布局区(
    child.node、child.x、child.y、,
    child.w、child.h、child.blft、getMargin(child.node),
    GetColumnHaligmentInternal(),GetRowValigmentInternal()
    );
    });
    }
    私家子女(){
    children=newarraylist();
    对于(int i=0;i如果(x+ch.w)如果可能的话,您必须使用自定义窗格,并自己定义布局。我将通过设置单个子节点的样式来实现这一点(在您的示例中,IIUC
    Label
    s)。只需使用一个
    流程窗格
    ,并将相关标签的样式设置为粉红色背景。感谢您的回复@James_D。您有任何建议的自定义窗格吗?或者您有任何简单的代码来定义布局本身吗?谢谢:这样做一点都不简单。您必须对
    窗格
    进行子类化,然后覆盖
    layoutChildren()
    ,然后布局各个子节点以获得所需的效果。简单的建议有什么问题?谢谢。它很有效!