palexdev / VirtualizedFX

GNU Lesser General Public License v3.0
46 stars 4 forks source link

`VFXGrid` Not Scrollable Despite Calling `makeScrollable()` #15

Open infinite-dev22 opened 1 week ago

infinite-dev22 commented 1 week ago

Description: I am experiencing an issue with the VFXGrid component in VirtualizedFX. Despite calling the makeScrollable() method, the grid is not scrollable. The cells are rendered efficiently, but the scrolling functionality does not seem to work.

Environment:

Steps to Reproduce:

Expected Behavior:

The grid should be scrollable when items exceed the visible area.

Actual Behavior:

The grid remains static, and no scrolling behavior is observed.

Minimal Reproducible Example (MRE): Item Type Class

public class Item {
    private String name;

    // Getters and Setters...
}

Grid Cell Class

public class ItemGridCell extends VBox implements VFXCell<Item> {
    private final Label nameLabel;
    private final StringProperty name = new SimpleStringProperty();
    protected final IntegerProperty index = new SimpleIntegerProperty();

    public ItemGridCell() {
        nameLabel = new Label();

        attachListeners();

        getChildren().addAll(nameLabel);
    }

    public String getName() {
        return this.nameProperty.get();
    }

    public void setName(String name) {
        this.nameProperty.set(name);
    }

    public StringProperty nameProperty() {
        return this.name;
    }

    public Integer getIndex() {
        return this.index.get();
    }

    public void setIndex(Integer index) {
        this.index.set(index);
    }

    public IntegerProperty indexProperty() {
        return this.index;
    }

    private void attachListeners() {
        nameProperty.addListener((_, _, name) -> {
            nameLabel.setText(name);
        });
    }

    @Override
    public Node getStyleableNode() {
        return super.getStyleableNode();
    }

    @Override
    public Node toNode() {
        return this;
    }

    @Override
    public void updateIndex(int i) {
        this.setIndex(i);
    }

    @Override
    public void updateItem(String name) {
        this.setName(name);
    }

    @Override
    public void beforeLayout() {
        VFXCell.super.beforeLayout();
    }

    @Override
    public void afterLayout() {
        VFXCell.super.afterLayout();
    }

    @Override
    public void onCache() {
        VFXCell.super.onCache();
    }

    @Override
    public void onDeCache() {
        VFXCell.super.onDeCache();
    }

    @Override
    public void dispose() {
        VFXCell.super.dispose();
    }
}

View Page Class

public class GridPage extends BorderPane {

    public GridPage() {
        setCenter(buildUI);
    }

    // Product UI.
    private VBox buildUI() {
        var stackpane = new StackPane(new Grid(itemsObservableList));
        stackpane.setPadding(new Insets(20d));

        var vbox = new VBox(stackpane);
        vbox.setPadding(new Insets(2.5d));
        VBox.setVgrow(vbox, Priority.ALWAYS);
        return vbox;
    }

    public static class Grid extends VFXGrid<Item, ItemGridCell> {
        public Grid(ObservableList<Item> items) {
            this(items, item -> {
                var cell = new ItemGridCell();
                cell.setName(item.getName);
                return cell;
            });
        }

        public Grid(ObservableList<Item> items, Function<Item, ItemGridCell> cellFactory) {
            super(items, cellFactory);
            // autoArrange();
            makeScrollable();
            setSpacing(25d, 25d);
            setCellSize(160, 250);
            setPadding(new Insets(5));
            setPrefSize(1000, 1000);
            setColumnsNum(12);
            setBufferSize(BufferSize.SMALL);
        }

        @Override
        public void setCellFactory(Function<Item, ItemGridCell> cellFactory) {
            super.setCellFactory(cellFactory);
        }

        @Override
        protected io.github.palexdev.mfxcore.controls.SkinBase<?, ?> buildSkin() {
            return new VFXGridSkin<>(this);
        }
    }
}

Additional Notes:

Could you please assist in resolving this issue?

palexdev commented 1 week ago

I think I know what the issue may be Did you add the VFXScrollPane.css stylesheet to the scroll pane or scene?

Check this

infinite-dev22 commented 1 week ago

Indeed, guilty as charged.

I must say, the approach with CSSFragment.Builder is quite forward-thinking when it comes to handling CSS. It would be more intuitive if .addSelector() accepted enum-like values representing CSS selectors, and if properties requiring numerical inputs (like sizes) could directly accept numeric values (e.g., doubles).

Additionally, it would enhance usability if .build() could encapsulate the functionality of .closeSelector(), making the API cleaner. This way, one could simply instantiate CSSFragment(sp) without the need for .applyOn(sp).

Minimal Reproducible Example (MRE):

CSSFragment(sp).addSelector(".css-class-selector")
               .padding(20)
               .background("transparent")
               .build();

This MRE condenses all of the following:

CSSFragment.Builder.build()
                   .addSelector(".css-class-selector")
                   .padding("20px")
                   .background("transparent")
                   .closeSelector()
                   .applyOn(sp);

Thank you for the solution you provided; it has been really helpful!

palexdev commented 1 week ago

I'll keep the issue open for now as a reminder to enhance this. I'm going to add the stylesheet to VFXScrollPane by default

Yeah I agree, the CSSFragment can indeed be improved. When I implemented it I was kinda in a hurry to release the new version and I didn't take too much time to polish the API, I made it simple and functional rather than convenient. I'll try to keep this in mind too

infinite-dev22 commented 1 week ago

I'm going to add the stylesheet to VFXScrollPane by default

This will actually be great, it will make the ScrollPane easily usable out-of-the-box with no extra configurations