浏览代码

New control: MFXTableView (Part 1)
NOTE: It is put in a separate package because this won't be MaterialFX's preferred table view as right now I'm implementing a new table view which doesn't extend from JavaFX's one hence built from scratch following material design guidelines (see material.io).

MFXListCell: ripple generator event handler should not stay in the updateItem method.
MFXListViewSkin: add check for hideScrollbars in constructor so if it is true then the scrollbars start hidden.
MFXTreeItemSkin: overridden dispose method.
Signed-off-by: PAlex404 <alessandro.parisi406@gmail.com>

PAlex404 4 年之前
父节点
当前提交
0ac7ff5b74

+ 1 - 1
materialfx/src/main/java/io/github/palexdev/materialfx/controls/MFXComboBox.java

@@ -120,7 +120,7 @@ public class MFXComboBox<T> extends ComboBox<T> {
      * If the item is instanceof {@code Labeled} makes a "screenshot" of the graphic if not null,
      * and gets item's text. Otherwise calls {@code toString()} on the item.
      */
-    private void updateComboItem(ListCell<T> cell, T item, boolean empty) {
+    protected void updateComboItem(ListCell<T> cell, T item, boolean empty) {
 
         if (empty || item == null) {
             cell.setGraphic(null);

+ 9 - 6
materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/MFXListCell.java

@@ -116,8 +116,17 @@ public class MFXListCell<T> extends ListCell<T> {
                 NodeUtils.updateBackground(MFXListCell.this, newValue);
             }
         });
+
+        setupRippleGenerator();
     }
 
+    protected void setupRippleGenerator() {
+        this.addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
+            rippleGenerator.setGeneratorCenterX(mouseEvent.getX());
+            rippleGenerator.setGeneratorCenterY(mouseEvent.getY());
+            rippleGenerator.createRipple();
+        });
+    }
     //================================================================================
     // Styleable Properties
     //================================================================================
@@ -232,12 +241,6 @@ public class MFXListCell<T> extends ListCell<T> {
             if (!getChildren().contains(rippleGenerator)) {
                 getChildren().add(0, rippleGenerator);
             }
-
-            addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
-                rippleGenerator.setGeneratorCenterX(mouseEvent.getX());
-                rippleGenerator.setGeneratorCenterY(mouseEvent.getY());
-                rippleGenerator.createRipple();
-            });
         }
     }
 }

+ 182 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/cell/tableview/MFXTableRow.java

@@ -0,0 +1,182 @@
+package io.github.palexdev.materialfx.controls.cell.tableview;
+
+import io.github.palexdev.materialfx.MFXResourcesLoader;
+import io.github.palexdev.materialfx.effects.RippleGenerator;
+import io.github.palexdev.materialfx.utils.NodeUtils;
+import javafx.css.*;
+import javafx.geometry.Insets;
+import javafx.scene.control.TableRow;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.layout.Background;
+import javafx.scene.layout.BackgroundFill;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.paint.Color;
+import javafx.scene.paint.Paint;
+import javafx.util.Duration;
+
+import java.util.List;
+
+public class MFXTableRow<T> extends TableRow<T> {
+    private static final StyleablePropertyFactory<MFXTableRow<?>> FACTORY = new StyleablePropertyFactory<>(TableRow.getClassCssMetaData());
+    private final String STYLE_CLASS = "mfx-table-row";
+    private final String STYLESHEET = MFXResourcesLoader.load("css/tableview/mfx-tablerow.css").toString();
+    private final RippleGenerator rippleGenerator;
+
+    public MFXTableRow() {
+        rippleGenerator = new RippleGenerator(this);
+        rippleGenerator.setRippleColor(Color.rgb(50, 150, 255));
+        rippleGenerator.setInDuration(Duration.millis(400));
+
+        initialize();
+    }
+
+    private void initialize() {
+        getStyleClass().add(STYLE_CLASS);
+
+        addEventHandler(MouseEvent.MOUSE_PRESSED, mouseEvent -> {
+            rippleGenerator.setGeneratorCenterX(mouseEvent.getX());
+            rippleGenerator.setGeneratorCenterY(mouseEvent.getY());
+            rippleGenerator.createRipple();
+        });
+
+        addListeners();
+    }
+
+    private void addListeners() {
+        tableViewProperty().addListener((observable, oldValue, newValue) -> {
+            if (newValue != null) {
+                rippleGenerator.rippleRadiusProperty().bind(newValue.widthProperty().divide(2.0));
+            }
+        });
+
+        selectedProperty().addListener((observable, oldValue, newValue) -> {
+            if (newValue) {
+                NodeUtils.updateBackground(MFXTableRow.this, getSelectedColor());
+            } else {
+                NodeUtils.updateBackground(MFXTableRow.this, Color.WHITE);
+            }
+        });
+
+        hoverProperty().addListener((observable, oldValue, newValue) -> {
+            if (isSelected() || isEmpty()) {
+                return;
+            }
+
+            if (newValue) {
+                if (getIndex() == 0) {
+                    setBackground(new Background(new BackgroundFill(getHoverColor(), CornerRadii.EMPTY, Insets.EMPTY)));
+                } else {
+                    NodeUtils.updateBackground(MFXTableRow.this, getHoverColor());
+                }
+            } else {
+                NodeUtils.updateBackground(MFXTableRow.this, Color.WHITE);
+            }
+        });
+
+        selectedColor.addListener((observableValue, oldValue, newValue) -> {
+            if (!newValue.equals(oldValue) && isSelected()) {
+                NodeUtils.updateBackground(MFXTableRow.this, newValue);
+            }
+        });
+    }
+
+    //================================================================================
+    // Styleable Properties
+    //================================================================================
+
+    /**
+     * Specifies the background color of the cell when it is selected.
+     */
+    private final StyleableObjectProperty<Paint> selectedColor = new SimpleStyleableObjectProperty<>(
+            StyleableProperties.SELECTED_COLOR,
+            this,
+            "selectedColor",
+            Color.rgb(180, 180, 255)
+    );
+
+    /**
+     * Specifies the background color of the cell when the mouse is hover.
+     */
+    private final StyleableObjectProperty<Paint> hoverColor = new SimpleStyleableObjectProperty<>(
+            StyleableProperties.HOVER_COLOR,
+            this,
+            "hoverColor",
+            Color.rgb(50, 150, 255, 0.15)
+    );
+
+    public Paint getSelectedColor() {
+        return selectedColor.get();
+    }
+
+    public StyleableObjectProperty<Paint> selectedColorProperty() {
+        return selectedColor;
+    }
+
+    public void setSelectedColor(Paint selectedColor) {
+        this.selectedColor.set(selectedColor);
+    }
+
+    public Paint getHoverColor() {
+        return hoverColor.get();
+    }
+
+    public StyleableObjectProperty<Paint> hoverColorProperty() {
+        return hoverColor;
+    }
+
+    public void setHoverColor(Paint hoverColor) {
+        this.hoverColor.set(hoverColor);
+    }
+
+    //================================================================================
+    // CssMetaData
+    //================================================================================
+    private static class StyleableProperties {
+        private static final List<CssMetaData<? extends Styleable, ?>> cssMetaDataList;
+
+        private static final CssMetaData<MFXTableRow<?>, Paint> SELECTED_COLOR =
+                FACTORY.createPaintCssMetaData(
+                        "-mfx-selected-color",
+                        MFXTableRow::selectedColorProperty,
+                        Color.rgb(180, 180, 255)
+                );
+
+        private static final CssMetaData<MFXTableRow<?>, Paint> HOVER_COLOR =
+                FACTORY.createPaintCssMetaData(
+                        "-mfx-hover-color",
+                        MFXTableRow::hoverColorProperty,
+                        Color.rgb(50, 150, 255, 0.15)
+                );
+
+        static {
+            cssMetaDataList = List.of(SELECTED_COLOR, HOVER_COLOR);
+        }
+
+    }
+
+    public static List<CssMetaData<? extends Styleable, ?>> getControlCssMetaDataList() {
+        return StyleableProperties.cssMetaDataList;
+    }
+
+    //================================================================================
+    // Override Methods
+    //================================================================================
+    @Override
+    public String getUserAgentStylesheet() {
+        return STYLESHEET;
+    }
+
+    @Override
+    public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
+        return getControlCssMetaDataList();
+    }
+
+    @Override
+    protected void updateItem(T item, boolean empty) {
+        super.updateItem(item, empty);
+
+        if (!getChildren().contains(rippleGenerator)) {
+            getChildren().add(0, rippleGenerator);
+        }
+    }
+}

+ 38 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/controls/tableview/MFXTableView.java

@@ -0,0 +1,38 @@
+package io.github.palexdev.materialfx.controls.tableview;
+
+import io.github.palexdev.materialfx.MFXResourcesLoader;
+import io.github.palexdev.materialfx.controls.cell.tableview.MFXTableRow;
+import io.github.palexdev.materialfx.skins.tableview.MFXTableViewSkin;
+import javafx.collections.ObservableList;
+import javafx.scene.control.Skin;
+import javafx.scene.control.TableView;
+
+public class MFXTableView<S> extends TableView<S> {
+    private final String STYLE_CLASS = "mfx-table-view";
+    private final String STYLESHEET = MFXResourcesLoader.load("css/tableview/mfx-tableview.css").toString();
+
+    public MFXTableView() {
+        initialize();
+    }
+
+    public MFXTableView(ObservableList<S> items) {
+        super(items);
+        initialize();
+    }
+
+    private void initialize() {
+        getStyleClass().add(STYLE_CLASS);
+        setRowFactory(row -> new MFXTableRow<>());
+        setFixedCellSize(27);
+    }
+
+    @Override
+    protected Skin<?> createDefaultSkin() {
+        return new MFXTableViewSkin<>(this);
+    }
+
+    @Override
+    public String getUserAgentStylesheet() {
+        return STYLESHEET;
+    }
+}

+ 5 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXListViewSkin.java

@@ -91,6 +91,11 @@ public class MFXListViewSkin<T> extends ListViewSkin<T> {
                         new KeyValue(hBar.opacityProperty(), 1.0, MFXAnimationFactory.getInterpolator()))
         );
 
+        if (listView.isHideScrollBars()) {
+            vBar.setOpacity(0.0);
+            hBar.setOpacity(0.0);
+        }
+
         setListeners();
     }
 

+ 7 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/skins/MFXTreeItemSkin.java

@@ -394,5 +394,12 @@ public class MFXTreeItemSkin<T> extends SkinBase<MFXTreeItem<T>> {
 
         return cell;
     }
+
+    @Override
+    public void dispose() {
+        if (getSkinnable() == null) return;
+        getSkinnable().getItems().removeListener(itemsListener);
+        super.dispose();
+    }
 }
 

+ 145 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/skins/tableview/MFXTableViewSkin.java

@@ -0,0 +1,145 @@
+package io.github.palexdev.materialfx.skins.tableview;
+
+import io.github.palexdev.materialfx.controls.factories.MFXAnimationFactory;
+import javafx.animation.KeyFrame;
+import javafx.animation.KeyValue;
+import javafx.animation.Timeline;
+import javafx.geometry.Insets;
+import javafx.geometry.Orientation;
+import javafx.scene.Node;
+import javafx.scene.control.ScrollBar;
+import javafx.scene.control.TableRow;
+import javafx.scene.control.TableView;
+import javafx.scene.control.skin.TableViewSkin;
+import javafx.scene.control.skin.VirtualFlow;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Region;
+import javafx.util.Duration;
+
+import java.util.Set;
+
+public class MFXTableViewSkin<T> extends TableViewSkin<T> {
+    //================================================================================
+    // Properties
+    //================================================================================
+    private final VirtualFlow<?> virtualFlow;
+    private final Pane header;
+
+    private final ScrollBar vBar;
+    private final ScrollBar hBar;
+
+    private final Timeline hideBars;
+    private final Timeline showBars;
+
+    public MFXTableViewSkin(TableView<T> tableView) {
+        super(tableView);
+
+        virtualFlow = (VirtualFlow<?>) tableView.lookup(".virtual-flow");
+        header = (Pane) tableView.lookup("TableHeaderRow");
+
+        this.vBar = new ScrollBar();
+        this.hBar = new ScrollBar();
+        bindScrollBars(tableView);
+        getChildren().addAll(vBar, hBar);
+
+        vBar.setManaged(false);
+        vBar.setOrientation(Orientation.VERTICAL);
+        vBar.getStyleClass().add("mfx-scroll-bar");
+        vBar.visibleProperty().bind(vBar.visibleAmountProperty().isNotEqualTo(0));
+
+        hBar.setManaged(false);
+        hBar.setOrientation(Orientation.HORIZONTAL);
+        hBar.getStyleClass().add("mfx-scroll-bar");
+        hBar.visibleProperty().bind(hBar.visibleAmountProperty().isNotEqualTo(0));
+
+        hideBars = new Timeline(
+                new KeyFrame(Duration.millis(400),
+                        new KeyValue(vBar.opacityProperty(), 0.0, MFXAnimationFactory.getInterpolator()),
+                        new KeyValue(hBar.opacityProperty(), 0.0, MFXAnimationFactory.getInterpolator()))
+        );
+        showBars = new Timeline(
+                new KeyFrame(Duration.millis(400),
+                        new KeyValue(vBar.opacityProperty(), 1.0, MFXAnimationFactory.getInterpolator()),
+                        new KeyValue(hBar.opacityProperty(), 1.0, MFXAnimationFactory.getInterpolator()))
+        );
+    }
+
+    private void bindScrollBars(TableView<?> tableView) {
+        final Set<Node> nodes = tableView.lookupAll("VirtualScrollBar");
+        for (Node node : nodes) {
+            if (node instanceof ScrollBar) {
+                ScrollBar bar = (ScrollBar) node;
+                if (bar.getOrientation().equals(Orientation.VERTICAL)) {
+                    bindScrollBars(vBar, bar);
+                } else if (bar.getOrientation().equals(Orientation.HORIZONTAL)) {
+                    bindScrollBars(hBar, bar);
+                }
+            }
+        }
+    }
+
+    private void bindScrollBars(ScrollBar scrollBarA, ScrollBar scrollBarB) {
+        scrollBarA.valueProperty().bindBidirectional(scrollBarB.valueProperty());
+        scrollBarA.minProperty().bindBidirectional(scrollBarB.minProperty());
+        scrollBarA.maxProperty().bindBidirectional(scrollBarB.maxProperty());
+        scrollBarA.visibleAmountProperty().bindBidirectional(scrollBarB.visibleAmountProperty());
+        scrollBarA.unitIncrementProperty().bindBidirectional(scrollBarB.unitIncrementProperty());
+        scrollBarA.blockIncrementProperty().bindBidirectional(scrollBarB.blockIncrementProperty());
+    }
+
+    private double estimateHeight() {
+        double borderWidth = snapVerticalInsets();
+
+        double cellsHeight = 0;
+        for (int i = 0; i < virtualFlow.getCellCount(); i++) {
+            TableRow<?> cell = (TableRow<?>) virtualFlow.getCell(i);
+
+            cellsHeight += cell.getHeight();
+        }
+
+        return cellsHeight + borderWidth;
+    }
+
+    private double snapVerticalInsets() {
+        return getSkinnable().snappedBottomInset() + getSkinnable().snappedTopInset();
+    }
+
+    //================================================================================
+    // Override Methods
+    //================================================================================
+    @Override
+    protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
+        final int itemsCount = getSkinnable().getItems().size();
+        if (getSkinnable().maxHeightProperty().isBound() || itemsCount <= 0) {
+            return super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
+        }
+
+        final double fixedCellSize = getSkinnable().getFixedCellSize();
+        double computedHeight = fixedCellSize != Region.USE_COMPUTED_SIZE ?
+                fixedCellSize * itemsCount + snapVerticalInsets() : estimateHeight();
+        double height = super.computePrefHeight(width, topInset, rightInset, bottomInset, leftInset);
+        if (height > computedHeight) {
+            height = computedHeight;
+        }
+
+        if (getSkinnable().getMaxHeight() > 0 && computedHeight > getSkinnable().getMaxHeight()) {
+            return getSkinnable().getMaxHeight();
+        }
+
+        return height;
+    }
+
+    @Override
+    protected void layoutChildren(double x, double y, double w, double h) {
+        super.layoutChildren(x, y, w, h);
+
+        final double headerH = header.getHeight();
+
+        Insets insets = getSkinnable().getInsets();
+        final double prefWidth = vBar.prefWidth(-1);
+        vBar.resizeRelocate(w - prefWidth - insets.getRight(), insets.getTop() + headerH, prefWidth, h - insets.getTop() - insets.getBottom() - headerH);
+
+        final double prefHeight = hBar.prefHeight(-1);
+        hBar.resizeRelocate(insets.getLeft() + 5, h - prefHeight - insets.getBottom() + 20, w - insets.getLeft() - insets.getRight() - 20, prefHeight);
+    }
+}

+ 3 - 0
materialfx/src/main/java/module-info.java

@@ -12,12 +12,15 @@ module MaterialFX.materialfx.main {
     exports io.github.palexdev.materialfx.controls;
     exports io.github.palexdev.materialfx.controls.base;
     exports io.github.palexdev.materialfx.controls.cell;
+    exports io.github.palexdev.materialfx.controls.cell.tableview;
     exports io.github.palexdev.materialfx.controls.enums;
     exports io.github.palexdev.materialfx.controls.factories;
+    exports io.github.palexdev.materialfx.controls.tableview;
     exports io.github.palexdev.materialfx.effects;
     exports io.github.palexdev.materialfx.font;
     exports io.github.palexdev.materialfx.notifications;
     exports io.github.palexdev.materialfx.skins;
+    exports io.github.palexdev.materialfx.skins.tableview;
     exports io.github.palexdev.materialfx.utils;
     exports io.github.palexdev.materialfx.validation;
     exports io.github.palexdev.materialfx.validation.base;

+ 25 - 0
materialfx/src/main/resources/io/github/palexdev/materialfx/css/tableview/mfx-tablerow.css

@@ -0,0 +1,25 @@
+.mfx-table-row {
+    -fx-background-insets: 0.0;
+    -fx-text-fill: black;
+    -fx-padding: 0 -3 0 3;
+
+    -mfx-hover-color: rgba(50, 150, 255, 0.15);
+}
+
+.mfx-table-row:odd,
+.mfx-table-row:even {
+    -fx-background-color: white;
+}
+
+.mfx-table-row:filled:hover,
+.mfx-table-row:selected .label {
+    -fx-text-fill: black;
+}
+
+.table-row-cell .text {
+    -fx-fill: -fx-text-background-color;
+}
+
+.table-row-cell:selected .text {
+    -fx-fill: black;
+}

+ 184 - 0
materialfx/src/main/resources/io/github/palexdev/materialfx/css/tableview/mfx-tableview.css

@@ -0,0 +1,184 @@
+/*
+ *     Copyright (C) 2021 Parisi Alessandro
+ *     This file is part of MaterialFX (https://github.com/palexdev/MaterialFX).
+ *
+ *     MaterialFX is free software: you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation, either version 3 of the License, or
+ *     (at your option) any later version.
+ *
+ *     MaterialFX is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with MaterialFX.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Base */
+.mfx-table-view {
+    -fx-focus-color: transparent;
+    -fx-faint-focus-color: transparent;
+    -fx-border-color: lightgray;
+    -fx-background-radius: 2;
+    -fx-border-radius: 2;
+    -fx-padding: 0 0 10 0;
+}
+
+/* Look up colors */
+
+.mfx-table-view {
+    -mfx-selection-bar: transparent;
+    -mfx-selection-bar-non-focused: transparent;
+    -mfx-box-border: transparent;
+    -fx-table-cell-border-color: transparent;
+
+    -fx-selection-bar: -mfx-selection-bar;
+    -fx-selection-bar-non-focused: -mfx-selection-bar;
+    -fx-box-border: -mfx-box-border;
+
+    -mfx-track-color: rgb(225, 225, 225);
+    -mfx-thumb-color: rgb(157, 157, 157);
+    -mfx-thumb-hover-color: rgb(88, 88, 88);
+}
+.mfx-table-view .column-header,
+.mfx-table-view .column-header-background,
+.mfx-table-view .column-header-background .filler {
+    -fx-background-color: transparent;
+    -fx-border-color: transparent;
+}
+
+.mfx-table-view .column-header {
+    -fx-border-color: #f3f3f3 #f3f3f3 #f3f3f3 transparent;
+    -fx-border-width: 0 2 0 0;
+}
+
+.mfx-table-view .column-header .label {
+    -fx-text-fill: #2e3440;
+    -fx-padding: 16 0 16 0;
+}
+
+.mfx-table-view .column-header .arrow,
+.mfx-table-view .column-header .sort-order-dot {
+    -fx-background-color: #2e3440;
+}
+
+.mfx-table-view .column-header:last-visible {
+    -fx-border-width: 0 2 0 1;
+}
+
+.mfx-table-view .column-header-background {
+    -fx-border-width: 0 0 1 0;
+    -fx-border-color: #F3F3F3;
+}
+
+.mfx-table-view .column-overlay {
+    -fx-background-color: rgb(180, 180, 255);
+}
+
+.mfx-table-view .column-resize-line,
+.mfx-table-view .column-drag-header {
+    -fx-background-color: rgb(150, 180, 255);
+}
+
+/* Remove JavaFX crap */
+
+
+.mfx-table-view > .virtual-flow > .corner {
+    -fx-background-color: transparent ;
+}
+.mfx-table-view > .virtual-flow > .scroll-bar,
+.mfx-table-view > .virtual-flow > .scroll-bar .decrement-arrow,
+.mfx-table-view > .virtual-flow > .scroll-bar .increment-arrow,
+.mfx-table-view > .virtual-flow > .scroll-bar .decrement-button,
+.mfx-table-view > .virtual-flow > .scroll-bar .increment-button {
+    -fx-pref-width: 0;
+    -fx-pref-height: 0;
+}
+
+.mfx-table-view .scroll-bar:horizontal .increment-button,
+.mfx-table-view .scroll-bar:horizontal .decrement-button {
+    -fx-background-color: transparent;
+    -fx-background-radius: 0.0em;
+    -fx-padding: 0.0 0.0 10.0 0.0;
+}
+
+
+.mfx-table-view .scroll-bar:vertical .increment-button,
+.mfx-table-view .scroll-bar:vertical .decrement-button {
+    -fx-background-color: transparent;
+    -fx-background-radius: 0.0em;
+    -fx-padding: 0.0 10.0 0.0 0.0;
+
+}
+
+.mfx-table-view .scroll-bar .increment-arrow,
+.mfx-table-view .scroll-bar .decrement-arrow {
+    -fx-shape: " ";
+    -fx-padding: 0.15em 0.0;
+}
+
+.mfx-table-view .scroll-bar:horizontal .increment-arrow,
+.mfx-table-view .scroll-bar:horizontal .decrement-arrow {
+    -fx-shape: " ";
+    -fx-padding: 0.0 0.05em;
+}
+
+.mfx-table-view .scroll-bar:vertical .increment-arrow,
+.mfx-table-view .scroll-bar:vertical .decrement-arrow {
+    -fx-shape: " ";
+    -fx-padding: 0.0 0.05em;
+}
+
+/* Customize ScrollBars */
+
+.mfx-table-view .mfx-scroll-bar:horizontal .track {
+    -fx-background-color: -mfx-track-color;
+    -fx-border-color: transparent;
+    -fx-background-radius: 2.0em;
+    -fx-border-radius: 2.0em;
+    -fx-background-insets: 3;
+}
+.mfx-table-view .mfx-scroll-bar:vertical .track {
+    -fx-background-color: -mfx-track-color;
+    -fx-border-color: transparent;
+    -fx-background-radius: 2.0em;
+    -fx-border-radius: 2.0em;
+    -fx-background-insets: 3;
+}
+
+.mfx-table-view .mfx-scroll-bar .decrement-arrow,
+.mfx-table-view .mfx-scroll-bar .increment-arrow {
+    -fx-pref-width: 0;
+    -fx-pref-height: 0;
+}
+
+.mfx-table-view .mfx-scroll-bar:vertical {
+    -fx-background-color: transparent;
+    -fx-pref-width: 12;
+    -fx-pref-height: 12;
+    -fx-padding: 5 0.5 5 0.5;
+}
+
+.mfx-table-view .mfx-scroll-bar:horizontal {
+    -fx-background-color: transparent;
+    -fx-pref-width: 12;
+    -fx-pref-height: 12;
+    -fx-padding: 0.5 5 0.5 5;
+}
+
+.mfx-table-view .mfx-scroll-bar:horizontal .thumb,
+.mfx-table-view .mfx-scroll-bar:vertical .thumb {
+    -fx-background-color: -mfx-thumb-color;
+    -fx-background-insets: 2.0, 0.0, 0.0;
+    -fx-background-radius: 2.0em;
+}
+
+.mfx-table-view .mfx-scroll-bar:horizontal .thumb:hover,
+.mfx-table-view .mfx-scroll-bar:vertical .thumb:hover {
+    -fx-background-color: -mfx-thumb-hover-color;
+    -fx-background-insets: 1.5, 0.0, 0.0;
+    -fx-background-radius: 2.0em;
+}
+