到目前为止,我正在尝试使用JavaFX中的按钮来制作蜂窝流

java - javafx中的蜂窝布局(带有流 Pane ?)-LMLPHP

到目前为止,我通过在FlowPane上使用负VGap使它工作了一半,但是一旦我调整大小并将3-4行变为3-3-1,它显然就出错了

java - javafx中的蜂窝布局(带有流 Pane ?)-LMLPHP

我正在尝试找到一种解决方案,该方案将使蜂窝布局具有可变数量的按钮,但是到目前为止,我还没有取得太大的成功。所以我想知道是否有人知道解决方案。

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

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放置字段要方便一些。

您可以观察到,使用列跨度可以将Button放在GridPane中:每个字段填充2列sqrt(3/4)乘以字段高度。奇数/偶数行分别从列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;
}




类似于FlowPane的行为

FlowPane中,使x位置取决于添加子项的行并不是一个好主意。相反,我建议扩展Pane并覆盖layoutChildren方法,将子级放置在自定义位置。

在您的情况下,可以使用以下类:

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));

09-13 04:38