javafx中的蜂窝布局(使用flowpane?)

javafx中的蜂窝布局(使用flowpane?),java,javafx,flowpane,Java,Javafx,Flowpane,我正试图在JavaFX中用按钮创建一个蜂窝状流,到目前为止,它是一个流窗格 到目前为止,我在FlowPane上使用了一个负的VGap,使它工作了一半,但一旦我调整它的大小,使3-4行变为3-3-1,它显然出了问题 我正试图找到一个解决方案,使蜂窝式布局中的按钮数量可变,但到目前为止,我还没有取得多少成功。所以我想知道是否有人知道这个问题的解决方案 编辑:这是我目前的基本代码 FlowPane root = new FlowPane(); root.setHgap(3.0); root.set

我正试图在JavaFX中用按钮创建一个蜂窝状流,到目前为止,它是一个流窗格

到目前为止,我在FlowPane上使用了一个负的VGap,使它工作了一半,但一旦我调整它的大小,使3-4行变为3-3-1,它显然出了问题

我正试图找到一个解决方案,使蜂窝式布局中的按钮数量可变,但到目前为止,我还没有取得多少成功。所以我想知道是否有人知道这个问题的解决方案

编辑:这是我目前的基本代码

FlowPane root = new FlowPane();
root.setHgap(3.0); root.setVgap(-23.0);
root.setAlignment(Pos.CENTER);

Button[] array = new Button[7];

for(int i = 0; i <= 6; i++){
    Button button = new Button();
    button.setShape(polygon); (made a polygon in the same of a hexagon)
    array[i] = button;
}
root.getChildren().addAll(array);
FlowPane root=newflowpane();
根.setHgap(3.0);根.setVgap(-23.0);
根部设置对齐(位置中心);
按钮[]数组=新按钮[7];
对于(int i=0;i)列/行
这比使用
FlowPane
放置字段更方便

您可以观察到,使用列跨距,您可以将
按钮放置在
网格窗格中
:每个字段填充
sqrt(3/4)的2列
乘以字段高度;奇数行/偶数行分别从第0/1列开始。每个字段填充3行,列约束的大小在字段高度的四分之一到一半之间交替

示例

public static GridPane createHoneyComb(int rows, int columns, double size) {
    double[] points = new double[12];
    for (int i = 0; i < 12; i += 2) {
        double angle = Math.PI * (0.5 + i / 6d);
        points[i] = Math.cos(angle);
        points[i + 1] = Math.sin(angle);
    }
    Polygon polygon = new Polygon(points);

    GridPane result = new GridPane();
    RowConstraints rc1 = new RowConstraints(size / 4);
    rc1.setFillHeight(true);
    RowConstraints rc2 = new RowConstraints(size / 2);
    rc2.setFillHeight(true);

    double width = Math.sqrt(0.75) * size;
    ColumnConstraints cc = new ColumnConstraints(width/2);
    cc.setFillWidth(true);

    for (int i = 0; i < columns; i++) {
        result.getColumnConstraints().addAll(cc, cc);
    }

    for (int r = 0; r < rows; r++) {
        result.getRowConstraints().addAll(rc1, rc2);
        int offset = r % 2;
        int count = columns - offset;
        for (int c = 0; c < count; c++) {
            Button b = new Button();
            b.setPrefSize(width, size);
            b.setShape(polygon);
            result.add(b, 2 * c + offset, 2 * r, 2, 3);
        }
    }
    result.getRowConstraints().add(rc1);
    return result;
}
double[]点=新的double[12];
对于(int i=0;i<12;i+=2){
双角度=数学PI*(0.5+i/6d);
点[i]=数学cos(角度);
点[i+1]=数学sin(角度);
}
多边形=新多边形(点);
OffsetPane op=新的OffsetPane();
双字段高度=100;
双字段宽度=数学sqrt(0.75)*字段高度;
对于(int i=0;i<23;i++){
按钮按钮=新按钮();
按钮。设置形状(多边形);
按钮.setPrefSize(字段宽度、字段高度);
op.getChildren().add(按钮);
}
//水平放置正好位于最后一个元素的右侧
op.setHPositionFunction((int索引,双x,双y,双宽度,双高度)->新点2D(x+宽度,y));
//垂直位置为左/右尺寸的一半,具体取决于索引和
//1/4最后一个节点底部上方的节点高度
op.setVPositionFunction((整型索引,双x,双y,双宽度,双高度)->新点2D(x+(索引%2==0?宽度:-宽度)/2,y+高度*0.75));

我的水晶球在维护atm机上。如果没有代码,没有人能帮你…@Nidhoegger添加了我当前的代码,但我怀疑这会帮助muchAm纠正我的猜测,即这个蜂巢需要像FlowPane一样包装它的一行单元格来响应用户调整大小的动作?或者用户不允许调整它的大小?我弄得很糟糕我现在正在工作,但现在正在工作。OffsetPane正是我想要的,谢谢!
public class OffsetPane extends Pane {

    public interface PositionFunction {

        public Point2D getNextPosition(int index, double x, double y, double width, double height);

    }

    private static final PositionFunction DEFAULT_FUNCTION = new PositionFunction() {

        @Override
        public Point2D getNextPosition(int index, double x, double y, double width, double height) {
            return new Point2D(x, y);
        }

    };

    private final ObjectProperty<PositionFunction> hPositionFunction;
    private final ObjectProperty<PositionFunction> vPositionFunction;

    private ObjectProperty<PositionFunction> createPosProperty(String name) {
        return new SimpleObjectProperty<PositionFunction>(this, name, DEFAULT_FUNCTION) {

            @Override
            public void set(PositionFunction newValue) {
                if (newValue == null) {
                    throw new IllegalArgumentException();
                } else if (get() != newValue) {
                    super.set(newValue);
                    requestLayout();
                }
            }

        };
    }

    public OffsetPane() {
        this.hPositionFunction = createPosProperty("hPositionFunction");
        this.vPositionFunction = createPosProperty("vPositionFunction");
    }

    @Override
    protected void layoutChildren() {
        super.layoutChildren();
        double width = getWidth();

        List<Node> children = getManagedChildren();
        final int childSize = children.size();
        if (childSize > 0) {
            int row = 0;
            Node lastRowStart = children.get(0);
            Node lastNode = lastRowStart;
            lastRowStart.relocate(0, 0);
            PositionFunction hFunc = getHPositionFunction();
            PositionFunction vFunc = getVPositionFunction();
            int index = 1;
            int columnIndex = 0;

            while (index < childSize) {
                Node child = children.get(index);
                Bounds lastBounds = lastNode.getLayoutBounds();
                Bounds bounds = child.getLayoutBounds();
                Point2D pt = hFunc.getNextPosition(columnIndex, lastNode.getLayoutX(), lastNode.getLayoutY(), lastBounds.getWidth(), lastBounds.getHeight());

                if (pt.getX() + bounds.getWidth() > width) {
                    // break row
                    lastBounds = lastRowStart.getLayoutBounds();
                    pt = vFunc.getNextPosition(row, lastRowStart.getLayoutX(), lastRowStart.getLayoutY(), lastBounds.getWidth(), lastBounds.getHeight());
                    child.relocate(pt.getX(), pt.getY());

                    lastRowStart = child;
                    row++;
                    columnIndex = 0;
                } else {
                    child.relocate(pt.getX(), pt.getY());
                    columnIndex++;
                }

                lastNode = child;

                index++;
            }
        }
    }

    public final PositionFunction getHPositionFunction() {
        return this.hPositionFunction.get();
    }

    public final void setHPositionFunction(PositionFunction value) {
        this.hPositionFunction.set(value);
    }

    public final ObjectProperty<PositionFunction> hPositionFunctionProperty() {
        return this.hPositionFunction;
    }

    public final PositionFunction getVPositionFunction() {
        return this.vPositionFunction.get();
    }

    public final void setVPositionFunction(PositionFunction value) {
        this.vPositionFunction.set(value);
    }

    public final ObjectProperty<PositionFunction> vPositionFunctionProperty() {
        return this.vPositionFunction;
    }

}
double[] points = new double[12];
for (int i = 0; i < 12; i += 2) {
    double angle = Math.PI * (0.5 + i / 6d);
    points[i] = Math.cos(angle);
    points[i + 1] = Math.sin(angle);
}
Polygon polygon = new Polygon(points);

OffsetPane op = new OffsetPane();

double fieldHeight = 100;
double fieldWidth = Math.sqrt(0.75) * fieldHeight;

for (int i = 0; i < 23; i++) {
    Button button = new Button();
    button.setShape(polygon);
    button.setPrefSize(fieldWidth, fieldHeight);
    op.getChildren().add(button);
}
// horizontal placement just right of the last element
op.setHPositionFunction((int index, double x, double y, double width, double height) -> new Point2D(x + width, y));

// vertical position half the size left/right depending on index and
// 1/4 the node height above the bottom of the last node
op.setVPositionFunction((int index, double x, double y, double width, double height) -> new Point2D(x + (index % 2 == 0 ? width : -width) / 2, y + height * 0.75));