JavaFX имеет полосу прокрутки, прозрачную для всех элементов (область прокрутки, текстовая область и т. Д.) - PullRequest
2 голосов
/ 23 мая 2019

То, что я ищу, это полоса прокрутки, похожая на IntelliJ IDE:

  • дорожка полностью прозрачная
  • без кнопок
  • thumb имеет частичную прозрачность
  • прокрутка идет вверх / вниз до самого конца дорожки

IntelliJ example

Единственный способ, которым я мог сделать это до сих пор, - это иметь этот код, но это не украшает мою стадию, чего я не хочу, и это больше похоже на обходной путь, чем на фактический контроль над полосой прокрутки. Использование этого решения потребует значительных изменений и повсеместного применения сплошных фонов только потому, что корень изменился. Код до сих пор:

Main

primaryStage.initStyle(StageStyle.TRANSPARENT);
root.getScene().setFill(Color.TRANSPARENT);

CSS

* {
    -fx-background: transparent;
}

.scroll-pane {
    -fx-background-color: transparent;
}

Код дает (синий фон - обои для рабочего стола, я только хочу, чтобы он был прозрачным внутри границ сцены - не так, как на рисунке ниже)

Current code output


* ОБНОВЛЕНИЕ

@ john16384 спасибо за ваш вклад. Основываясь на вашем примере, я попробовал несколько вариантов, к сожалению, не очень удовлетворительно. Происходит то, что вы упомянули, область прокрутки резервирует область для полос прокрутки, имеющих другой фон. Смотрите прикрепленные примеры (полосы прокрутки зеленые). Если я применяю barPolicy, чтобы полосы прокрутки никогда не исчезали полностью.

fx1 fx2

Я мог бы подумать о другом подходе, например, иметь панель или vbox и добавлять к ней полосы прокрутки, но пока я не смог найти хороший пример, где их можно настроить.

1 Ответ

2 голосов
/ 23 мая 2019

Вы можете довольно легко сделать полосы прокрутки прозрачными:

.scroll-bar .track {
  -fx-fill: transparent;
}

Кнопки, которые вы не можете удалить, если не используете свой собственный скин:

.scroll-bar {
   -fx-skin: "hs.mediasystem.util.javafx.control.MinimalScrollBarSkin";
}

Наконец, на скриншоте IntelliJ есть содержимое полосы прокрутки, отображаемой через полосу прокрутки. Теперь это немного сложнее, поскольку полоса прокрутки по-прежнему будет резервировать место, и фон будет его родителем, а не содержимым ScrollPane.

Этого можно достичь, только написав свой собственный ScrollPane (создайте его подкласс, а в его layoutChildren выполните пользовательское позиционирование содержимого и наложите прозрачные полосы прокрутки на содержимое).

У меня нет примера для этого, но этого можно достичь.

В любом случае, вот код для MinimalScrollBarSkin (могут быть более простые способы добиться этого, но у меня это сработало):

package hs.mediasystem.util.javafx.control;

import javafx.beans.binding.Bindings;
import javafx.beans.binding.NumberBinding;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.Skin;
import javafx.scene.layout.Region;
import javafx.scene.shape.Rectangle;

/**
 * Scrollbar skin without increment/decrement buttons.
 */
public class MinimalScrollBarSkin implements Skin<ScrollBar> {

  private ScrollBar scrollBar;
  private Region group;
  private Rectangle track = new Rectangle();
  private Rectangle thumb = new Rectangle();

  public MinimalScrollBarSkin(final ScrollBar scrollBar) {
    this.scrollBar = scrollBar;

    this.group = new Region() {
      NumberBinding range = Bindings.subtract(scrollBar.maxProperty(), scrollBar.minProperty());
      NumberBinding position = Bindings.divide(Bindings.subtract(scrollBar.valueProperty(), scrollBar.minProperty()), range);

      {
        // Children are added unmanaged because for some reason the height of the bar keeps changing
        // if they're managed in certain situations... not sure about the cause.
        getChildren().addAll(track, thumb);

        track.setManaged(false);
        track.getStyleClass().add("track");

        thumb.setManaged(false);
        thumb.getStyleClass().add("thumb");

        scrollBar.orientationProperty().addListener(obs -> setup());

        setup();
      }

      private void setup() {
        track.widthProperty().unbind();
        track.heightProperty().unbind();

        if(scrollBar.getOrientation() == Orientation.HORIZONTAL) {
          track.relocate(0, -16);
          track.widthProperty().bind(scrollBar.widthProperty());
          track.setHeight(16);
        }
        else {
          track.relocate(-16, 0);
          track.setWidth(16);
          track.heightProperty().bind(scrollBar.heightProperty());
        }

        thumb.xProperty().unbind();
        thumb.yProperty().unbind();
        thumb.widthProperty().unbind();
        thumb.heightProperty().unbind();

        if(scrollBar.getOrientation() == Orientation.HORIZONTAL) {
          thumb.relocate(0, -16);
          thumb.widthProperty().bind(Bindings.max(16, scrollBar.visibleAmountProperty().divide(range).multiply(scrollBar.widthProperty())));
          thumb.setHeight(16);
          thumb.xProperty().bind(Bindings.subtract(scrollBar.widthProperty(), thumb.widthProperty()).multiply(position));
        }
        else {
          thumb.relocate(-16, 0);
          thumb.setWidth(16);
          thumb.heightProperty().bind(Bindings.max(16, scrollBar.visibleAmountProperty().divide(range).multiply(scrollBar.heightProperty())));
          thumb.yProperty().bind(Bindings.subtract(scrollBar.heightProperty(), thumb.heightProperty()).multiply(position));
        }
      }

      @Override
      protected double computeMaxWidth(double height) {
        if(scrollBar.getOrientation() == Orientation.HORIZONTAL) {
          return Double.MAX_VALUE;
        }

        return 16;
      }

      @Override
      protected double computeMaxHeight(double width) {
        if(scrollBar.getOrientation() == Orientation.VERTICAL) {
          return Double.MAX_VALUE;
        }

        return 16;
      }
    };
  }

  @Override
  public void dispose() {
    scrollBar = null;
    group = null;
  }

  @Override
  public Node getNode() {
    return group;
  }

  @Override
  public ScrollBar getSkinnable() {
    return scrollBar;
  }
}

Обновление

Можно показывать полосу прокрутки так, как вы этого хотите. Вот скриншот из моего приложения, где я сделал большой палец прокрутки 96 пикселей в ширину (полоса по-прежнему 16 пикселей):

enter image description here

Как видите, содержимое панели показывается большим пальцем. Я не уверен, почему вы получаете зарезервированную область на сером фоне. Его там быть не должно.

Я просмотрел стили, которые у меня были связаны с полосой прокрутки или панелью прокрутки, и, возможно, вам все еще нужен один из них (я подозреваю, последний, который устанавливает прозрачную панель прокрутки):

.scroll-bar
{
  -fx-skin: "hs.mediasystem.util.javafx.control.MinimalScrollBarSkin";
  -fx-background-color: transparent;
}

.scroll-bar .track
{
  -fx-stroke-width: 1;
  -fx-stroke: -c-dark-glass;
  -fx-arc-width: 16px;
  -fx-arc-height: 16px;
  -fx-fill: transparent;
}

.scroll-bar .thumb
{
  -fx-fill: -c-glass;
  -fx-arc-width: 16px;
  -fx-arc-height: 16px;
}

.list-view,
.scroll-pane,
.scroll-pane > .viewport
{
  -fx-background-color: transparent;
}
...