到目前为止,我正在尝试使用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
放置字段要方便一些。
您可以观察到,使用列跨度可以将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));