This is my code:
public class TestPanel extends ScrollPane {
final int SPACING = 5;
final int ROW_MAX = 6;
public TestPanel(ArrayList<Item> items) {
VBox root = new VBox();
root.setSpacing(SPACING);
HBox row = null;
int count = 0;
for (Item item: items){
if (count == ROW_MAX || row == null){
row = new HBox();
row.setSpacing(SPACING);
root.getChildren().add(row);
count = 0;
}
CustomBox box = new customBox(item);
row.getChildren().add(box);
HBox.setHgrow(box, Priority.ALWAYS);
//box.prefWidthProperty().bind(row.widthProperty()); // Worked for GridPane
count ;
}
setFitToWidth(true);
setContent(root);
}
And this is the custom box node element thing that I'm placing in the V and H Boxes
public class CustomBox extends StackPane {
private Items item;
private Rectangle square;
private int size = 20; // Irrelevent
public CustomBox(NewAirbnbListing item) {
this.item= item;
setPadding(new Insets(5, 5, 5, 5));
square = new Rectangle(size, size, Color.RED);
square.widthProperty().bind(widthProperty());
//square.heightProperty().bind(heightProperty());
minHeightProperty().bind(widthProperty()); // Maintains aspect ratio
getChildren().add(square);
}
The Error: Pink is box, grey is background colour of the StackPane for visual testing.
What I want to do:
What I want: I want the rectangle inside the CustomBox (as well as other components I'll add later) to fill up the size of the StackPane which they sit in and alter their size when the window is resized. I basically want them to mimic the size of that Pane.
Now to try explain whats going on, basically I have a class that's basically a square (There's going to be more stuff later) and I want to fill my "grid" with. When I first did this I used a GridPane to extend my class, I also used the commented out code to bind the properties and it worked "perfectly", it resized how I wanted with no issues, except the fact it lagged like crazy because the items ArrayList contains thousands of items so this will be a very long list. And then later when I was implementing the boxes to store images, that's when the massive lag problems started. My solution to this was to replace the GridPane with the HBox and VBox combo, and it very much fixed the lag issue, it also lets me do things I can't do with the GridPane. However, the problem in the gif I linked is what I'm facing. I've tried every combination of binding properties that I can think of but it still expands like crazy and I just have no idea whats causing it so I really hope someone here can help me out. I don't know tonnes about JavaFX but I'm here to learn, any help is greatly appreciated.
CodePudding user response:
I believe the root cause for your problem lies at: the square
width binding with CustomBox
width. You might wonder how this is a problem. You are allowing the CustomBox width to be relied on its content (a.k.a square) and your square width is relied on its parent width.. as now these two widths are interdependent to each other.. the width is increased exponentially..
One possible way to fix this, is to calculate the CustomBox size manually based on the ScrollPane viewport width. This way you are controlling the parent width manully and the contents width is handled by binding.
The code in the TestPanel will be:
private DoubleProperty size = new SimpleDoubleProperty();
double padding = 4; // 2px on either side
viewportBoundsProperty().addListener((obs, old, bounds) -> {
size.setValue((bounds.getWidth() - padding - ((ROW_MAX - 1) * SPACING)) / ROW_MAX);
});
CustomBox box = new CustomBox(item);
box.minWidthProperty().bind(size);
A complete working demo is below:
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
public class ScrollPaneContentDemo extends Application {
@Override
public void start(Stage stage) throws Exception {
List<Item> items = new ArrayList<>();
IntStream.range(1, 1000).forEach(i -> items.add(new Item()));
TestPanel root = new TestPanel(items);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.setTitle("ScrollPaneContent Demo");
stage.show();
}
class TestPanel extends ScrollPane {
private final int SPACING = 5;
private final int ROW_MAX = 6;
private DoubleProperty size = new SimpleDoubleProperty();
public TestPanel(List<Item> items) {
final VBox root = new VBox();
root.setSpacing(SPACING);
HBox row = null;
int count = 0;
for (Item item : items) {
if (count == ROW_MAX || row == null) {
row = new HBox();
row.setSpacing(SPACING);
root.getChildren().add(row);
count = 0;
}
CustomBox box = new CustomBox(item);
box.minWidthProperty().bind(size);
row.getChildren().add(box);
HBox.setHgrow(box, Priority.ALWAYS);
count ;
}
setFitToWidth(true);
setContent(root);
double padding = 4;
viewportBoundsProperty().addListener((obs, old, bounds) -> {
size.setValue((bounds.getWidth() - padding - ((ROW_MAX - 1) * SPACING)) / ROW_MAX);
});
}
}
class CustomBox extends StackPane {
private Item item;
private Rectangle square;
private int size = 20;
public CustomBox(Item item) {
setStyle("-fx-background-color:#99999950;");
this.item = item;
setPadding(new Insets(5, 5, 5, 5));
square = new Rectangle(size, size, Color.RED);
square.widthProperty().bind(widthProperty());
square.heightProperty().bind(heightProperty());
maxHeightProperty().bind(minWidthProperty());
maxWidthProperty().bind(minWidthProperty());
minHeightProperty().bind(minWidthProperty());
getChildren().add(square);
}
}
class Item {
}
}