JavaFX: сделать вертикальную полосу прокрутки подходящей для родительского узла в TableView - PullRequest
2 голосов
/ 11 марта 2019

У меня есть TableView, который прокручивается по вертикали, и я хотел бы, чтобы ScrollBar расширялся до верхней части своего родительского AnchorPane и находился поверх квадрата заполнителя в правом верхнем углу.Смотрите ниже, что это такое по умолчанию.Обратите внимание, что мой заливочный узел белый, это не столбец таблицы в правом верхнем углу.

enter image description here

и ниже этой строки - то, что я хочу, правильнореализован другой программой.

enter image description here

Я смог добиться этого, выполнив

Platform.runLater(() ->
{
    ScrollBar someScrollBar = (ScrollBar) someTable.lookup(".scroll-bar:vertical");
    someScrollBar.setTranslateY(-12);
    someScrollBar.setScaleY(1.2);
}
);

, где someTable - это TableViewсделано в FXML и упоминается в функции инициализации контроллера.

enter image description here

Это выглядит хорошо, но масштабируется неправильно.Если содержащий AnchorPane изменяет размер по вертикали, он выглядит ужасно.

Может кто-нибудь предложить лучший способ сделать это?

Большое вам спасибо за ваше время.

1 Ответ

3 голосов
/ 11 марта 2019

Пользовательский макет полос прокрутки не поддерживается. И мой первоначальный комментарий вам нужен пользовательский TableViewSkin с пользовательским TableHeaderRow: последний отвечает за управление .. ну, к сожалению, tableHeader - это только часть истории.

  • TableHeaderRow действительно отвечает за размещение заголовка таблицы
  • но: TableHeaderRow ничего не может сделать для разметки вертикальной полосы прокрутки - когда он пытается сделать это в переопределенном layoutChildren(), он сразу сбрасывается
  • сброс происходит в VirtualFlow (который является родителем полосы прокрутки)

Итак, в конце дня нам нужно

  • пользовательский TableHeaderRow, который сигнализирует о необходимости увеличения и перемещения scrollBar: пример ниже устанавливает маркер, если scrollBar видим (tbd: проверьте, видим ли menuButton или нет) с желаемой дополнительной высотой в карте свойств scrollBar
  • пользовательский VirtualFlow, который может обрабатывать маркер и фактически делает макет по мере необходимости: приведенный ниже пример проверяет маркер и изменяет размеры / перемещает scrollBar, если необходимо.
  • пользовательский TableViewSkin для внедрения обоих (через переопределенные фабричные методы)

Пример написан для fx11, должен работать для fx10, но не для fx9, потому что последний не позволяет предоставить пользовательский VirtualFlow:

public class TableWithoutCorner extends Application {

    /**
     * Custom TableHeaderRow that requests a larger vbar height
     * if needed.
     */
    private static class MyTableHeader extends TableHeaderRow {

        private Region cornerAlias;
        private ScrollBar vBar;
        private TableViewSkinBase skin;

        public MyTableHeader(TableViewSkinBase skin) {
            super(skin);
            this.skin = skin;
        }

        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            adjustCornerLayout();
        }

        private void adjustCornerLayout() {
            checkAlias();
            // tbd: check also if corner is visible
            if (!vBar.isVisible()) {
                vBar.getProperties().remove("DELTA");
            } else { 
                vBar.getProperties().put("DELTA", getHeight());
            }
        }

        private void checkAlias() {
            if (cornerAlias == null) {
                cornerAlias = (Region) lookup(".show-hide-columns-button");
            }
            if (vBar == null) {
                vBar = (ScrollBar) skin.getSkinnable().lookup(".scroll-bar:vertical");
            }
        }

    }

    /**
     * Custom VirtualFlow that respects additinal height for its 
     * vertical ScrollBar.
     */
    private static class MyFlow extends VirtualFlow {

        private ScrollBar vBar;
        private Region clip;

        public MyFlow() {
            // the scrollbar to adjust
            vBar = (ScrollBar) lookup(".scroll-bar:vertical");
            // the clipped container to use for accessing viewport dimensions
            clip = (Region) lookup(".clipped-container");

        }

        /**
         * Overridden to adjust vertical scrollbar's height and y-location
         * after calling super.
         */
        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            adjustVBar();
        }

        /**
         * Adjusts vBar height and y-location by the height as
         * requested by the table header.
         */
        protected void adjustVBar() {
            if (vBar.getProperties().get("DELTA") == null) return;
            double delta = (double) vBar.getProperties().get("DELTA");
            vBar.relocate(clip.getWidth(), - delta);
            vBar.resize(vBar.getWidth(), clip.getHeight() + delta);
        }

    }

    /**
     * Boilerplate: need custom TableViewSkin to inject a custom TableHeaderRow and
     * custom VirtualFlow.
     */
    private static class MyTableViewSkin<T> extends TableViewSkin<T> {

        public MyTableViewSkin(TableView<T> control) {
            super(control);
        }

        @Override
        protected TableHeaderRow createTableHeaderRow() {
            return new MyTableHeader(this);
        }

        @Override
        protected VirtualFlow<TableRow<T>> createVirtualFlow() {
            return new MyFlow();
        }

    }

    private Parent createContent() {
        TableView<Locale> table = new TableView<>(FXCollections.observableArrayList(Locale.getAvailableLocales())) {

            @Override
            protected Skin<?> createDefaultSkin() {
                return new MyTableViewSkin(this);
            }

        }; 
        TableColumn<Locale, String> col = new TableColumn<>("Name");
        col.setCellValueFactory(new PropertyValueFactory<>("displayName"));
        table.getColumns().addAll(col);
        return table;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        //stage.setTitle(FXUtils.version());
        stage.show();
    }

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

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(TableWithoutCorner.class.getName());

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