问题
I am trying to force the child of a GridPane
to fit the size of the cell it is in. In this case, I am creating a month view calendar and the columns and rows are a set size regardless of what is in it.
On this calendar, each cell contains a normal VBox
and each VBox
contains a label that displays the day of the month and each of the events for that day. Many of the days have no events; some of them have one event; and a few have more than one event.
The calendar size is dependent on the window size and will grow and shrink in accordance to the window. Right now, if the cell is too small to fit all of the events, then the height of that one VBox
for that day in the cell becomes larger than the cell.
The header row has the following constraint:
HEADER_CONSTRAINT = new RowConstraints(10, -1, 500,
Priority.NEVER, VPos.BASELINE, true);
and the other rows have this constraint:
ROW_CONSTRAINT = new RowConstraints(30, 30, Integer.MAX_VALUE,
Priority.ALWAYS, VPos.TOP, true);
What I think I need to do is:
grid.add(cell, c, r);
vbox.maxHeightProperty().bind(grid.getRow(r).heightProperty()); // <-- this line is not right, but something like this.
回答1:
As @fabian mentioned correctly, the size of a VBox
is entirely dependent the sizes of its children. If you wish to have a container that does not resize depending on its children, you can use a Pane
instead. Like this:
public void start(Stage primaryStage)
{
GridPane root = new GridPane();
Scene scene = new Scene(root, 300, 300);
int c = 0, r = 0;
Pane c0 = new Pane();
c0.setPrefSize(200, 200);
c0.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
new BorderWidths(1))));
root.add(c0, c, r);
primaryStage.setScene(scene);
primaryStage.show();
}
Add a shape to test:
Pane c0 = new Pane();
c0.setPrefSize(200, 200);
c0.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
new BorderWidths(1))));
{
Circle circle = new Circle(160, Color.BLUE);
circle.setCenterX(160);
circle.setCenterY(160);
c0.getChildren().add(circle);
}
root.add(c0, c, r);
Note that although the shape protrudes outside of the bounds of c0
, the borders of c0
stay in place, indicating that its size is unaffected. To prevent the content from protruding out, you need to add a clip:
c0.setClip(new Rectangle(c0.getPrefWidth(), c0.getPrefHeight()));
If you want a more fancy clip instead of a simple trim, such as fade-in, fade-out, and shadows, you can read this very good tutorial here.
Now just replace this Circle
with your VBox
, so that the VBox
is a child of this Pane
, and add the Pane
to your GridPane
and you're done. I will provide my final code here as a reference:
public void start(Stage primaryStage)
{
GridPane root = new GridPane();
Scene scene = new Scene(root, 300, 300);
int c = 0, r = 0;
Pane c0 = new Pane();
c0.setPrefSize(200, 200);
c0.setClip(new Rectangle(c0.getPrefWidth(), c0.getPrefHeight()));
c0.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
new BorderWidths(1))));
{
Circle circle = new Circle(160, Color.BLUE);
circle.setCenterX(160);
circle.setCenterY(160);
c0.getChildren().add(circle);
}
root.add(c0, c, r);
primaryStage.setScene(scene);
primaryStage.show();
}
Update:
@Jai pointed out that the size is static in this implementation. If you wish to dynamically adjust the size of the cells if the size of the GridPane
changes, you can add a listener to its widthProperty
and heightProperty
like this:
int rowCount = 5, columnCount = 7; // You should know these values.
ChangeListener<Number> updater = (o, oV, nV) ->
{
double newWidth = root.getWidth() / columnCount;
double newHeight = root.getHeight() / rowCount;
root.getChildren().forEach(n ->
{
// Assuming every child is a Pane.
Pane p = (Pane) n;
p.setPrefSize(newWidth, newHeight);
p.setClip(new Rectangle(newWidth, newHeight));
});
};
root.widthProperty().addListener(updater);
root.heightProperty().addListener(updater);
Alternatively...
If you wish to use ColumnConstraints
and RowConstraints
to determine the cell size you can set the Pane
s to expand, and only update their clips in the listener, which now listens to ColumnConstraints
and RowConstraints
:
ColumnConstraints cc = new ColumnConstraints(200);
RowConstraints rc = new RowConstraints(200);
c0.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
c0.setClip(new Rectangle(cc.getPrefWidth(), rc.getPrefHeight()));
and...
ChangeListener<Number> updater = (o, oV, nV) ->
{
root.getChildren().forEach(n ->
{
// Assuming every child is a Pane.
Pane p = (Pane) n;
p.setClip(new Rectangle(cc.getPrefWidth(), rc.getPrefHeight()));
});
};
cc.prefWidthProperty().addListener(updater);
rc.prefHeightProperty().addListener(updater);
来源:https://stackoverflow.com/questions/51275545/javafx-force-the-child-of-a-gridpane-to-fit-the-size-of-the-cell