jfx gui controles javafx-2

javafx-2 - gui - oracle combobox javafx



¿Cómo consigues que JavaFX ListView sea la altura de sus elementos? (9)

Si creo un ListView:

new ListView<>(FXCollections.observableArrayList("1", "2", "3"))

Espero que cree un ListView con 3 filas. Pero no lo hace. Crea un ListView de 17 o más filas. ¿Hay una manera de decirle a ListView que siempre tenga la altura tal que cualquier elemento que se encuentre en ella siempre se muestre pero no haya filas en blanco?

Tener ancho automático también sería útil, por lo que siempre es tan ancho como la fila más ancha.

Un propósito de esto es que luego podría ser usado en un ScrollPane. Sé que tiene sus propias barras de desplazamiento, pero no ofrecen el control suficiente.


¿Estás buscando eso?

.list-cell:empty { -fx-opacity: 0; }

Esto ocultará las celdas vacías.


Acabo de descubrir que la respuesta de Paul Marshall se puede reducir a una línea usando Bindings.size que crea una propiedad jfx numérica que representa el tamaño de una lista observable:

listView.prefHeightProperty().bind(Bindings.size(itemListProperty).multiply(LIST_CELL_HEIGHT));

Lamentablemente, la altura de la celda de la lista todavía debe tener el código AFAIK.


Basé mi respuesta en las respuestas proporcionadas por @scribbleslims y @Alexandre Mazari

listView.setPrefHeight(listView.getItems().size() * LIST_CELL_HEIGHT);

Tienes que definir LIST_CELL_HEIGHT por tu cuenta.

En mi caso, utilicé 29.501.


Desafortunadamente, no hay una propiedad de tamaño agradable y limpia de una lista de observables para que nos unamos. En su lugar, es factible agregando un ListChangeListener en la lista, al menos, así es como lo he hecho en el pasado. Por defecto, el tamaño de cada fila debe ser de 24 px, y necesitamos un píxel adicional en la parte superior e inferior de los bordes de ListView. De lo contrario, todavía tenemos la barra de desplazamiento de ListView mostrando. Primero, crearemos el ObservableList y el ListView, y estableceremos la altura inicial del ListView:

/* * Each row in a ListView should be 24px tall. Also, we have to add an extra * two px to account for the borders of the ListView. */ final int ROW_HEIGHT = 24; final ObservableList items = FXCollections.observableArrayList("1", "2", "3"); final ListView list = new ListView(items); // This sets the initial height of the ListView: list.setPrefHeight(items().size() * ROW_HEIGHT + 2);

Ahora tenemos que agregar un ListChangeListener a ObservableList. Cuando la lista cambia, simplemente cambiamos la altura establecida de ListView para que coincida con el nuevo número de filas. Si sabemos que nunca vamos a agregar o eliminar elementos de la Lista observable que respalda el ListView, entonces podemos excluir al oyente. Nuevamente, la altura es el número de filas por la altura por fila más dos píxeles adicionales para los bordes:

/* * This listener will resize the ListView when items are added or removed * from the ObservableList that is backing the ListView: */ items.addListener(new ListChangeListener() { @Override public void onChanger(ListChangeListener.Change change) { list.setPrefHeight(items.size() * ROW_HEIGHT + 2); } });

Referencias: JavaFX ListView Documentation , JavaFX ObservableList Documentation


Después de trabajar duro y basarme en la respuesta de @warakawa, encontré la solución. Como todos sabemos, la implementación de Listview está causando muchos dolores de cabeza, debido a esto escribí dos clases que solucionan el problema de "PREF_SIZE" (que tiene una constante de 400 para la altura y el ancho se calcula de acuerdo con la altura). La clase de máscara que escribí calcula el tamaño como esperamos y también evita la fea barra horizontal cuando la nueva propiedad "fillWidth" se cambia a "true", esta propiedad hace que las celdas crezcan horizontalmente tanto como sea posible. Saludos.

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> }


El sistema de reputación de me impide comentar sobre la respuesta de Paul Marshall, pero quería agregar a cualquier otra persona que vea esto que su estimación de 24px para las filas está "generalmente" confirmada por la documentación oficial de JavaFX. http://download.java.net/jdk8/jfxdocs/javafx/scene/control/ListView.html :

En general, las células son alrededor de 24px ...

Entonces, si bien estoy de acuerdo en que "[f] la configuración de la altura de la fila, el ancho del borde, etc., de alguna manera el estilo o las cosas complicadas son confusas, pero probablemente la única forma de hacerlo" puede ser cierta, comenzando con una suposición que está respaldada La documentación oficial es un buen lugar para comenzar y parece tener como resultado listas de aspecto decente en mis pruebas en un ListView (con Java 7).


Encontré una solución relativamente fácil, aunque todavía ligeramente intrincada, que funciona bajo el supuesto de que todas las celdas no vacías tienen la misma altura: en lugar de analizar css o algo listView.getItems() , agregue un InvalidationListener a su listView.getItems() ; la primera vez que su lista de artículos no está vacía, recursivamente recorre los elementos ListView hasta que encuentre una instancia de ListCell donde !cell.isEmpty() , y almacene el valor de cell.getHeight() . Asegúrese de envolver ese código en un Platform.runLater() para que se ejecute una vez que se realice el diseño de ListView . Una vez que tenga esa altura, multiplíquelo por listView.getItems().size() y llame a listView.setMaxHeight con el valor resultante (aún dentro de InvalidationListener ).


Intente establecer PrefHeight (doble) en la subclase de ListCell. Por ejemplo en mi código

@Override public void updateItem(File item, boolean empty) { super.updateItem(item, empty); if (empty) { setText(null); setGraphic(null); } else { setText(item.getName()); setGraphic(null); setPrefHeight(getSize(item)/getsize(folder)); } }