JavaFX: подгонять столбцы TableView к содержимому, чтобы избежать его сокращения. - PullRequest
0 голосов
/ 18 мая 2018

У меня следующая проблема: когда я создаю TableView и помещаю данные в столбцы, столбцы автоматически подгоняются под содержимое.Но если там много строк (более 30), JavaFX оптимизирует ширину столбцов до средней длины всего контента.

В первом примере я поместил длинные строки в таблицу, и все в порядке.

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Example extends Application {

    @Override
    public void start(Stage stage) {

        // Init data
        ObservableList<Person> persons = FXCollections.observableArrayList();
        persons.add(new Person("Maximus-Superman", "Power", "Maximus-Superman.Power@test.com"));
        persons.add(new Person("Max", "Powerstrongsupercool", "Max.Powerstrongsupercool@test.com"));
        persons.add(new Person("Maximus-Superman", "Powerstrongsupercool", "Maximus-Superman.Powerstrongsupercool@test.com"));
        for (int i = 0; i < 100; i++) {
            persons.add(new Person("Max", "Power", "Max.Power@test.com"));
        }
        // Init table
        TableView<Person> table = new TableView<Person>();
        table.setMaxWidth(Double.MAX_VALUE);
        table.setMaxHeight(Double.MAX_VALUE);
        table.setItems(persons);

        // Init columns
        TableColumn<Person, String> firstname = new TableColumn<Person, String>("Firstname");
        firstname.setCellValueFactory(new PropertyValueFactory<Person, String>("firstname"));
        table.getColumns().add(firstname);

        TableColumn<Person, String> lastname = new TableColumn<Person, String>("Lastname");
        lastname.setCellValueFactory(new PropertyValueFactory<Person, String>("lastname"));
        table.getColumns().add(lastname);

        TableColumn<Person, String> email = new TableColumn<Person, String>("E-Mail");
        email.setCellValueFactory(new PropertyValueFactory<Person, String>("email"));
        table.getColumns().add(email);

        // Init Stage
        Scene scene = new Scene(table, 400, 150);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    public class Person {

        private String firstname;
        private String lastname;
        private String email;

        public Person(String firstname, String lastname, String email) {
            this.firstname = firstname;
            this.lastname = lastname;
            this.email = email;
        }

        // Getters and Setters

    }
}

Выглядит хорошо ...

enter image description here

Во втором примере я поместил короткие строки сначала в таблицу и по крайней мередлинные струны.В этом примере JavaFX выбирает маленькую ширину столбца, и содержимое сокращается.

public class Example extends Application {

    @Override
    public void start(Stage stage) {

        // Init data
        ObservableList<Person> persons = FXCollections.observableArrayList();
        for (int i = 0; i < 100; i++) {
            persons.add(new Person("Max", "Power", "Max.Power@test.com"));
        }
        persons.add(new Person("Maximus-Superman", "Power", "Maximus-Superman.Power@test.com"));
        persons.add(new Person("Max", "Powerstrongsupercool", "Max.Powerstrongsupercool@test.com"));
        persons.add(new Person("Maximus-Superman", "Powerstrongsupercool", "Maximus-Superman.Powerstrongsupercool@test.com"));
        [...]

выглядит плохо ...

enter image description here

Как мне избежать этого?

РЕДАКТИРОВАТЬ 19.05.2018

Ссылки в комментариях не работали.

Итак, я обнаружил проблему в источнике JavaFx: в методе updateScene () для maxRows установлено значение 30. Невозможно изменить значение, поскольку все задействованные методы защищены или являются частными.,

Комментарий правильный.Создание таблицы может занять много времени, если в таблице много строк.Но иногда разработчик знает много возможных строк таблицы, или можно рисковать большим временем загрузки.

Одним из решений является обращение в Oracle для создания setter () для значения max.строк.Таким образом, разработчик может выбрать макс.строки для каждого столбца в отдельности.

public class TableColumnHeader extends Region {

    [...]

    private void updateScene() {
        // RT-17684: If the TableColumn widths are all currently the default,
        // we attempt to 'auto-size' based on the preferred width of the first
        // n rows (we can't do all rows, as that could conceivably be an unlimited
        // number of rows retrieved from a very slow (e.g. remote) data source.
        // Obviously, the bigger the value of n, the more likely the default
        // width will be suitable for most values in the column
        final int n = 30; // ------------------------------------------> This is the problem!
        if (! autoSizeComplete) {
            if (getTableColumn() == null || getTableColumn().getWidth() != DEFAULT_COLUMN_WIDTH || getScene() == null) {
                return;
            }
            doColumnAutoSize(getTableColumn(), n);
            autoSizeComplete = true;
        }
    }

    [...]

    private void doColumnAutoSize(TableColumnBase<?,?> column, int cellsToMeasure) {
        double prefWidth = column.getPrefWidth();

        // if the prefWidth has been set, we do _not_ autosize columns
        if (prefWidth == DEFAULT_COLUMN_WIDTH) {
            getTableViewSkin().resizeColumnToFitContent(column, cellsToMeasure);
        }
    }

    [...]

}

public class TableViewSkin<T> extends TableViewSkinBase<T, T, TableView<T>, TableViewBehavior<T>, TableRow<T>, TableColumn<T, ?>> {

    [...]

    @Override protected void resizeColumnToFitContent(TableColumn<T, ?> tc, int maxRows) {
        if (!tc.isResizable()) return;

        // final TableColumn<T, ?> col = tc;
        List<?> items = itemsProperty().get();
        if (items == null || items.isEmpty()) return;

        Callback/*<TableColumn<T, ?>, TableCell<T,?>>*/ cellFactory = tc.getCellFactory();
        if (cellFactory == null) return;

        TableCell<T,?> cell = (TableCell<T, ?>) cellFactory.call(tc);
        if (cell == null) return;

        // set this property to tell the TableCell we want to know its actual
        // preferred width, not the width of the associated TableColumnBase
        cell.getProperties().put(TableCellSkin.DEFER_TO_PARENT_PREF_WIDTH, Boolean.TRUE);

        // determine cell padding
        double padding = 10;
        Node n = cell.getSkin() == null ? null : cell.getSkin().getNode();
        if (n instanceof Region) {
            Region r = (Region) n;
            padding = r.snappedLeftInset() + r.snappedRightInset();
        }

        int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows); // ------------------> if maxRows equals -1 every item will be checked
        double maxWidth = 0;
        for (int row = 0; row < rows; row++) {
            cell.updateTableColumn(tc);
            cell.updateTableView(tableView);
            cell.updateIndex(row);

            if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
                getChildren().add(cell);
                cell.applyCss();
                maxWidth = Math.max(maxWidth, cell.prefWidth(-1));
                getChildren().remove(cell);
            }
        }

        // dispose of the cell to prevent it retaining listeners (see RT-31015)
        cell.updateIndex(-1);

        // RT-36855 - take into account the column header text / graphic widths.
        // Magic 10 is to allow for sort arrow to appear without text truncation.
        TableColumnHeader header = getTableHeaderRow().getColumnHeaderFor(tc);
        double headerTextWidth = Utils.computeTextWidth(header.label.getFont(), tc.getText(), -1);
        Node graphic = header.label.getGraphic();
        double headerGraphicWidth = graphic == null ? 0 : graphic.prefWidth(-1) + header.label.getGraphicTextGap();
        double headerWidth = headerTextWidth + headerGraphicWidth + 10 + header.snappedLeftInset() + header.snappedRightInset();
        maxWidth = Math.max(maxWidth, headerWidth);

        // RT-23486
        maxWidth += padding;
        if(tableView.getColumnResizePolicy() == TableView.CONSTRAINED_RESIZE_POLICY) {
            maxWidth = Math.max(maxWidth, tc.getWidth());
        }

        tc.impl_setWidth(maxWidth);
    }

    [...]

}

Другим решением является запуск MouseEvent в заголовке прямоугольника TableColumn.

enter image description here

Если имеется MouseEvent с ClickCount, равным 2, и PrimaryButton не работает, вызывается метод resizeColumnToFitContent () со значением для maxRows, равным -1,

int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows);

-1 означает все строки в TableView.

public class NestedTableColumnHeader extends TableColumnHeader {

    [...]

    private static final EventHandler<MouseEvent> rectMousePressed = new EventHandler<MouseEvent>() {
        @Override public void handle(MouseEvent me) {
            Rectangle rect = (Rectangle) me.getSource();
            TableColumnBase column = (TableColumnBase) rect.getProperties().get(TABLE_COLUMN_KEY);
            NestedTableColumnHeader header = (NestedTableColumnHeader) rect.getProperties().get(TABLE_COLUMN_HEADER_KEY);

            if (! header.isColumnResizingEnabled()) return;

            if (me.getClickCount() == 2 && me.isPrimaryButtonDown()) {
                // the user wants to resize the column such that its
                // width is equal to the widest element in the column
                header.getTableViewSkin().resizeColumnToFitContent(column, -1); // -----------------------> this method should be call and everything is fine
            } else {
                // rather than refer to the rect variable, we just grab
                // it from the source to prevent a small memory leak.
                Rectangle innerRect = (Rectangle) me.getSource();
                double startX = header.getTableHeaderRow().sceneToLocal(innerRect.localToScene(innerRect.getBoundsInLocal())).getMinX() + 2;
                header.dragAnchorX = me.getSceneX();
                header.columnResizingStarted(startX);
            }
            me.consume();
        }
    };

    [...]

}

Итак, возможно ли создать новый MouseEvent с ClickCount, равным 2, и PrimaryButtonDown-boolean, равный true, и запустить его в TableColumn?

И: Как я могу связатьсяOracle, чтобы порадовать их для создания setter () для maxRows в следующем выпуске?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...