web-dev-qa-db-fra.com

colonne javafx en taille de table ajustement automatique

remarquez que TableView dans javafx a deux stratégies de redimensionnement des colonnes: CONSTRAINED_RESIZE_POLICY et UNCONSTRAINED_RESIZE_POLICY, mais je veux que les colonnes soient redimensionnées pour s’ajuster au contenu de leurs cellules. 

30
yelliver

Après 3 ans, je reviens encore sur ce problème. Certaines suggestions calculent la taille du texte des données dans chaque cellule (c'est compliqué en fonction de la taille de la police, de la famille de police, du remplissage ...).

Mais je me rends compte que lorsque je clique sur l'en-tête divider on du tableau, il est redimensionné pour s'adapter au contenu que je veux. J'ai donc finalement trouvé la méthode resizeColumnToFitContent dans TableViewSkin , mais c'est protected méthode, nous pouvons résoudre par réflexion:

import com.Sun.javafx.scene.control.skin.TableViewSkin;
import javafx.scene.control.Skin;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import Java.lang.reflect.InvocationTargetException;
import Java.lang.reflect.Method;

public class GUIUtils {
    private static Method columnToFitMethod;

    static {
        try {
            columnToFitMethod = TableViewSkin.class.getDeclaredMethod("resizeColumnToFitContent", TableColumn.class, int.class);
            columnToFitMethod.setAccessible(true);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    public static void autoFitTable(TableView tableView) {
        tableView.getItems().addListener(new ListChangeListener<Object>() {
            @Override
            public void onChanged(Change<?> c) {
                for (Object column : tableView.getColumns()) {
                    try {
                        columnToFitMethod.invoke(tableView.getSkin(), column, -1);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}

Notez que nous appelons " tableView.getItems () ", nous devons donc appeler cette fonction après setItems ()

22
yelliver

Après avoir testé les solutions précédentes, j’en ai finalement trouvé une qui fonctionnait pour moi… donc voici la mienne (appelez la méthode après avoir inséré les données dans le tableau):

public static void autoResizeColumns( TableView<?> table )
{
    //Set the right policy
    table.setColumnResizePolicy( TableView.UNCONSTRAINED_RESIZE_POLICY);
    table.getColumns().stream().forEach( (column) ->
    {
        //Minimal width = columnheader
        Text t = new Text( column.getText() );
        double max = t.getLayoutBounds().getWidth();
        for ( int i = 0; i < table.getItems().size(); i++ )
        {
            //cell must not be empty
            if ( column.getCellData( i ) != null )
            {
                t = new Text( column.getCellData( i ).toString() );
                double calcwidth = t.getLayoutBounds().getWidth();
                //remember new max-width
                if ( calcwidth > max )
                {
                    max = calcwidth;
                }
            }
        }
        //set the new max-widht with some extra space
        column.setPrefWidth( max + 10.0d );
    } );
}
5
HarleyDavidson

Je pense que le simple fait de redéfinir une fonction de rappel renvoyant true résoudra votre problème, il désactivera le redimensionnement des colonnes et toutes les colonnes seront redimensionnées pour correspondre au contenu de leurs cellules.

Exemple:

TableView<String[]> table = new TableView<>();
table.setColumnResizePolicy(new Callback<TableView.ResizeFeatures, Boolean>() {
  @Override
  public Boolean call(ResizeFeatures p) {
     return true;
  }
});
5
vipul mittal

J'ai utilisé les autres solutions sur cette question et cela fonctionne plutôt bien. Cependant, l'inconvénient est que la largeur de TableView est supérieure à la largeur requise de TableColumns ensemble. J'ai créé un hack pour résoudre ce problème, et cela fonctionne bien:

orderOverview.setColumnResizePolicy((param) -> true );
Platform.runLater(() -> FXUtils.customResize(orderOverview));

où FXUtils.customResize () est créé comme suit:

public static void customResize(TableView<?> view) {

    AtomicDouble width = new AtomicDouble();
    view.getColumns().forEach(col -> {
        width.addAndGet(col.getWidth());
    });
    double tableWidth = view.getWidth();

    if (tableWidth > width.get()) {
        TableColumn<?, ?> col = view.getColumns().get(view.getColumns().size()-1);
        col.setPrefWidth(col.getWidth()+(tableWidth-width.get()));
    }

}

J'espère que cela pourrait être utile pour d'autres personnes aussi!

2
bashoogzaad

Ou pour faire court:

// automatically adjust width of columns depending on their content
configAttributeTreeTable.setColumnResizePolicy((param) -> true );
2
stefanil

Si vous voulez qu'une seule colonne remplisse la largeur restante d'un tableau, j'ai trouvé une solution assez simple, courte et ne nécessitant pas la solution de réflexion hacky décrite ci-dessus:

DoubleBinding usedWidth = columnA.widthProperty().add(columnB.widthProperty()).add(columnC.widthProperty());

fillingColumn.prefWidthProperty().bind(tableView.widthProperty().subtract(usedWidth));
2
Jeff S.
myTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
for(TableColumn column: myTable.getColumns())
{           
    column.setMinWidth(200);                                        
}
0
darkrepulser1957

Ce code redimensionne automatiquement toutes les largeurs de colonne en proportions relationnelles par rapport à la largeur du tableau, 
alors qu'il peut fixer la largeur de la première colonne à une valeur donnée lorsque la largeur de la table est inférieure à x

        // To generalize the columns width proportions in relation to the table width,
        // you do not need to put pixel related values, you can use small float numbers if you wish,
        // because it's the relative proportion of each columns width what matters here:

        final float[] widths = { 1.2f, 2f, 0.8f };// define the relational width of each column 

        // whether the first column should be fixed
        final boolean fixFirstColumm = true; 

        // fix the first column width when table width is lower than:
        final float fixOnTableWidth = 360; //pixels 

        // calulates sum of widths
        float sum = 0;
        for (double i : widths) {
            sum += i;
        }

        // calculates the fraction of the first column proportion in relation to the sum of all column proportions
        float firstColumnProportion = widths[0] / sum;

        // calculate the fitting fix width for the first column, you can change it by your needs, but it jumps to this width
        final float firstColumnFixSize = fixOnTableWidth * firstColumnProportion;

        // set the width to the columns
        for (int i = 0; i < widths.length; i++) {
            table.getColumns().get(i).prefWidthProperty().bind(table.widthProperty().multiply((widths[i] / sum)));
            // ---------The exact width-------------^-------------^
    if (fixFirstColumm)
            if (i == 0) {
                table.widthProperty().addListener(new ChangeListener<Number>() {
                    @Override
                    public void changed(ObservableValue<? extends Number> arg0, Number oldTableWidth, Number newTableWidth) {

                        if (newTableWidth.intValue() <= fixOnTableWidth) {

                            // before you can set new value to column width property, need to unbind the autoresize binding
                            table.getColumns().get(0).prefWidthProperty().unbind();
                            table.getColumns().get(0).prefWidthProperty().setValue(firstColumnFixSize);

                        } else if (!table.getColumns().get(0).prefWidthProperty().isBound()) {

                            // than readd the autoresize binding if condition table.width > x
                            table.getColumns().get(0).prefWidthProperty()
                                    .bind(table.widthProperty().multiply(firstColumnProportion));
                        }

                    }
                });
            }
        }
</ pre>

conseil pour placer le code dans une classe séparée TableAutoresizeModel, vous pourrez y effectuer d'autres calculs, par exemple, en masquant des colonnes, ajoutez un programme d'écoute ...

0
Henryk
public static void autoFillColumn(TableView<?> table, int col) {
    double width = 0;
    for (int i = 0; i < table.getColumns().size(); i++) {
        if (i != col) {
            width += table.getColumns().get(i).getWidth();
        }
    }
    table.getColumns().get(col).setPrefWidth(table.getWidth() - width);
}
0
Guillermo