Automatische Steuerung der letzten Spalte in JavaFX TableView

Überblick

Ich hatte Probleme beim Steuern der Spaltenbreite von JavaFX TableView, daher ein Hinweis zum Umgang damit.

Ich habe versucht, die letzte Spalte auf automatische Steuerung einzustellen, damit die Spalte bis zur vollen Breite der Tabelle gefüllt wird.

ColumnResizePolicy Es gibt einen Mechanismus namens ColumnResizePolicy zum Steuern der Spaltenbreite von JavaFx TableView. Dies scheint ein Mechanismus zu sein, der bestimmt, wie die Spaltenbreite zum Zeitpunkt des ersten Zeichnens und der Anpassung der Spaltenbreite gesteuert wird.

Standardmäßig werden zwei Typen vorbereitet

Konstante Überblick
UNCONSTRAINED_RESIZE_POLICY Es gibt kein bestimmtes Steuerelement, und die Spaltenbreite wird verarbeitet, wenn der Benutzer sie verschiebt.
CONSTRAINED_RESIZE_POLICY Gleiche Spaltenbreite zum Zeitpunkt des ersten Zeichnens usw. und andere Spalten zum Zeitpunkt der Expansion und Kontraktion der Säule gleichmäßig verarbeiten.

Wenn eine andere eindeutige Verarbeitung erforderlich ist, muss diese implementiert werden, und in Wirklichkeit handelt es sich um die Callback-Klasse.

public final void setColumnResizePolicy(Callback<ResizeFeatures, Boolean> callback)

In diesem Fall scheint es realisiert zu werden, indem die Breite jeder Spalte geändert und true zurückgegeben wird, wenn dies erfolgreich ist.

Was ich persönlich wollte, war die automatische Steuerung der Breite der letzten Spalte, die ich erreichen wollte:

Ich habe mich in TableView von JavaFx umgesehen und nach etwas gesucht, das nicht möglich war, aber es scheint, dass es nicht die Standardeinstellung ist. Deshalb habe ich es aufgegeben und implementiert. Ich habe es geschafft, das gewünschte Verhalten zu erreichen. Ich habe es nicht im Detail betrachtet, aber es scheint kein Problem für die Überprüfung der Operation zu sein.

public class ResizePolicy {

    public static <S> void setLastColumnResizePolicy(TableView<S> tableView) {
        //Festlegen der Größenänderungsrichtlinie
        tableView.setColumnResizePolicy(prop -> {
            if (prop.getTable().getWidth() < 0) {
                return false;
            }
            resizeTargetColumn(prop);
            resizeLastColumn(prop);
            return true;
        });

        //Fügen Sie nach dem automatischen Anpassen beim Doppelklicken einen Größenänderungsprozess hinzu
        addResizeBorderDoubleClickedEvent(tableView);
    }

    private static void resizeTargetColumn(TableView.ResizeFeatures<?> prop) {
        var targetColumn = prop.getColumn();
        var delta = prop.getDelta();

        if (delta != 0 && targetColumn.isResizable()) {
            var newWidth = targetColumn.getWidth() + delta;

            //Stellen Sie die endgültige Breite unter Berücksichtigung der maximalen und minimalen Breite ein
            if (newWidth > targetColumn.getMaxWidth()) {
                targetColumn.setPrefWidth(targetColumn.getMaxWidth());
            } else if (newWidth < targetColumn.getMinWidth()) {
                targetColumn.setPrefWidth(targetColumn.getMinWidth());
            } else {
                targetColumn.setPrefWidth(newWidth);
            }
        }
    }

    private static void resizeLastColumn(TableView.ResizeFeatures<?> prop) {
        var table = prop.getTable();
        // -18.Wenn Sie nicht 0 setzen, wird eine Bildlaufleiste angezeigt. 18.0 wird nur durch Betrachten des Bildschirms entschieden
        var tableContentWidth = table.getWidth() - 18.0;

        //Berechnen Sie die Breite der letzten Spalte aus dem Gesamtwert außer der letzten Spalte und der Breite der Tabelle
        var columns = table.getVisibleLeafColumns();
        var columnsOfExcludedLastColumn = columns.stream().limit(columns.size() - 1);
        var widthsOfExcludedLastColumn = columnsOfExcludedLastColumn.map(TableColumnBase::getWidth);
        var lastColumnWidth = widthsOfExcludedLastColumn
                .reduce(tableContentWidth, (remainingWidth, columnWidth) -> remainingWidth - columnWidth);

        if (lastColumnWidth > 0) {
            var lastColumn = columns.get(columns.size() - 1);
            lastColumn.setPrefWidth(lastColumnWidth);
        }
    }

    private static <S> void addResizeBorderDoubleClickedEvent(TableView<S> tableView) {
        //Da Skin beim Zeichnen des Bildschirms null ist, registrieren Sie, was Sie als Ereignis tun möchten
        tableView.skinProperty().addListener((observable, oldValue, newValue) -> {
            var tableViewSkin = (TableViewSkin<?>) newValue;
            var tableViewSkinNodes = tableViewSkin.getChildren().stream();
            var tableHeaderRowNode = tableViewSkinNodes.filter(node -> node instanceof TableHeaderRow).findFirst();

            tableHeaderRowNode.ifPresent((node) -> {
                var tableHeaderRow = (TableHeaderRow) node;
                var tableColumnHeader = (NestedTableColumnHeader) tableHeaderRow.getChildren().get(1);

                tableColumnHeader.addEventFilter(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
                    //Bei Änderungen der Spaltenbreite ist die quadratische Linie das eigentliche Ereignisziel
                    //Und für Doppelklick auf Autofit
                    if (isRectangle(mouseEvent) && isDoubleClick(mouseEvent)) {

                        //Suchen Sie die Zielspalte anhand der Position der angeklickten quadratischen Linie und der Spaltenbreite
                        var rectangle = (Rectangle) mouseEvent.getTarget();
                        var columnPosition = 0.0;
                        for (var column : tableView.getColumns()) {
                            columnPosition += column.getWidth();
                            if (rectangle.getLayoutX() < columnPosition) {
                                //Wenn Sie die Größenänderungsrichtlinie zu diesem Zeitpunkt ausführen,
                                //Da die Breite nicht durch automatische Anpassung geändert wurde, wird die eigentliche Ausführung verschoben.
                                Platform.runLater(() -> {
                                    var columnResizePolicy = tableView.getColumnResizePolicy();
                                    columnResizePolicy.call(new TableView.ResizeFeatures<S>(tableView, column, -0.1));
                                });
                                break;
                            }
                        }
                    }
                });
            });
        });
    }

    private static boolean isRectangle(MouseEvent mouseEvent) {
        return mouseEvent.getTarget() instanceof Rectangle;
    }

    private static boolean isDoubleClick(MouseEvent mouseEvent) {
        return mouseEvent.getClickCount() == 2 && mouseEvent.isPrimaryButtonDown();
    }

}

Eigentlich habe ich versucht, es als Klasse anstatt als statisch zu erstellen, aber ich habe aufgrund eines allgemeinen Problems eine Warnung erhalten, und ich dachte, es wäre eine gute Idee, es mit SuppressWarnings zu löschen, also habe ich es zu einer statischen Methode gemacht. .. ..

ResizeFeatures ist eine generische Klasse, aber die setColumnResizePolicy-Methode behandelt sie roh. Wenn Sie also die Typdeklaration selbst durchführen, wird sie nicht mit einem Typfehler akzeptiert. Ich habe das Gefühl, eine Warnung zu erhalten, wenn ich nicht tippe.

Warum passiert das? .. ..

Recommended Posts

Automatische Steuerung der letzten Spalte in JavaFX TableView
Organisiertes Memo im Kopf (Java - Control Syntax)