After working hard and based in the @warakawa answer, I found the solution. As we all know, the implementation of the Listview is causing many headaches, because of this I wrote two classes that fixes the problem of "PREF_SIZE" (which has a constant of 400 for the height and width is calculated according to height). The skin class that I wrote calculates the size as we expect and also prevents ugly horizontal bar when the new property "fillWidth" is changed to "true", this property causes the cells to grow horizontally as much as possible. Regards.
ListViewFixed.java
package javafxapplication;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Skin;
public class ListViewFixed<T> extends javafx.scene.control.ListView<T>
{
// <editor-fold defaultstate="collapsed" desc="Properties">
private final BooleanProperty fillWidth = new SimpleBooleanProperty(this, "fillWidth");
public final BooleanProperty fillWidthProperty()
{
return fillWidth;
}
public final boolean isFillWidth()
{
return fillWidth.get();
}
public final void setFillWidth(boolean fillWidth)
{
this.fillWidth.set(fillWidth);
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Methods">
@Override
protected Skin createDefaultSkin()
{
return new ListViewFixedSkin(this);
}
// </editor-fold>
}
ListViewFixedSkin.java
package javafxapplication;
import java.util.Set;
import javafx.beans.Observable;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.IndexedCell;
import javafx.scene.control.ScrollBar;
import javafx.scene.layout.Region;
public class ListViewFixedSkin extends com.sun.javafx.scene.control.skin.ListViewSkin
{
// <editor-fold defaultstate="collapsed" desc="Fields">
private ListViewFixed listView;
private ScrollBar scrollBarHorizontal;
private ScrollBar scrollBarVertical;
private boolean fillWidthCache;
private double prefWidthCache;
private Region placeholderRegion;
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Constructors">
public ListViewFixedSkin(ListViewFixed listView)
{
super(listView);
this.listView = listView;
registerChangeListener(listView.fillWidthProperty(), "FILL_WIDTH");
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Methods">
private void updateFillWidth()
{
if (scrollBarHorizontal != null && scrollBarVertical != null && fillWidthCache != listView.isFillWidth())
{
if (listView.isFillWidth() && !fillWidthCache)
{
scrollBarHorizontal.visibleProperty().addListener(this::updateCellsPrefWidth);
scrollBarVertical.visibleProperty().addListener(this::updateCellsPrefWidth);
}
else
{
scrollBarHorizontal.visibleProperty().removeListener(this::updateCellsPrefWidth);
scrollBarVertical.visibleProperty().removeListener(this::updateCellsPrefWidth);
}
fillWidthCache = listView.isFillWidth();
}
}
private void updateCellsPrefWidth(Observable o)
{
final Insets insets = getSkinnable().getInsets();
final double prefWidth = getSkinnable().getWidth() + insets.getLeft() + insets.getRight() - scrollBarVertical.getWidth();
if (prefWidth != prefWidthCache)
{
for (int i = 0; i < flow.getCellCount(); i++)
{
final IndexedCell cell = flow.getCell(i);
if (!cell.isEmpty())
{
cell.setPrefWidth(prefWidth);
}
}
prefWidthCache = prefWidth;
}
}
private boolean showingPlaceHolder()
{
checkState();
if (getItemCount() == 0)
{
if (placeholderRegion == null)
{
updatePlaceholderRegionVisibility();
final Object obj = getChildren().get(getChildren().size() - 1);
if (obj instanceof Node && ((Region) obj).getStyleClass().contains("placeholder"))
{
placeholderRegion = (Region) obj;
}
}
if (placeholderRegion != null)
{
return true;
}
}
return false;
}
@Override
protected void handleControlPropertyChanged(String p)
{
super.handleControlPropertyChanged(p);
if ("FILL_WIDTH".equals(p))
{
updateFillWidth();
}
}
@Override
protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset)
{
if (showingPlaceHolder())
{
return super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
}
else
{
double computedHeight = topInset + bottomInset;
for (int i = 0; i < flow.getCellCount(); i++)
{
final IndexedCell cell = flow.getCell(i);
if (!cell.isEmpty())
{
computedHeight += cell.getHeight();
}
}
return computedHeight;
}
}
@Override
protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset)
{
double computedWidth = 0;
if (showingPlaceHolder())
{
computedWidth += placeholderRegion.getLayoutBounds().getWidth();
}
else
{
for (int i = 0; i < flow.getCellCount(); i++)
{
final IndexedCell cell = flow.getCell(i);
if (!cell.isEmpty() && cell.getWidth() > computedWidth)
{
computedWidth = cell.getWidth();
}
}
if (scrollBarVertical != null && scrollBarVertical.isVisible())
{
computedWidth += scrollBarVertical.getWidth();
}
}
if (computedWidth != 0)
{
return computedWidth + leftInset + rightInset;
}
else
{
return super.computePrefWidth(height, topInset, rightInset, bottomInset, leftInset);
}
}
@Override
protected void layoutChildren(double x, double y, double w, double h)
{
super.layoutChildren(x, y, w, h);
if (scrollBarHorizontal == null || scrollBarVertical == null)
{
final Set<Node> nodes = getSkinnable().lookupAll(".scroll-bar");
nodes.stream().forEach((node) ->
{
if (node instanceof ScrollBar)
{
final ScrollBar scrollBar = (ScrollBar) node;
if (scrollBar.getOrientation() == Orientation.HORIZONTAL)
{
scrollBarHorizontal = scrollBar;
}
else
{
scrollBarVertical = scrollBar;
}
}
});
updateFillWidth();
}
}
@Override
public void dispose()
{
if (fillWidthCache)
{
scrollBarHorizontal.visibleProperty().removeListener(this::updateCellsPrefWidth);
scrollBarVertical.visibleProperty().removeListener(this::updateCellsPrefWidth);
}
listView = null;
super.dispose();
}
// </editor-fold>
}
WARNING
There are some fixes to do at ListViewFixedSkin.java class. Where i pass methods by reference directly it should be stored before in an variable and then you pass the variable in add/attachments/remove/detachments methods. Otherwise this can cause memory problems.