Масштабирование в JavaFX и ScrollPanes


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

Для простоты я опубликую короткий пример, в котором мой график заменен меткой:

public class TestApp extends Application {
    @Override public void start(final Stage stage) throws Exception {
        final Label label = new Label("Hello World");
        label.getTransforms().setAll(new Scale(0.5, 0.5));

        label.setStyle("-fx-background-color:blue");
        label.setFont(new Font(200));

        final ScrollPane scrollPane = new ScrollPane();
        scrollPane.setContent(label);

        stage.setScene(new Scene(scrollPane));
        stage.setWidth(200);
        stage.setHeight(100);
        stage.show();
    }

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

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

Я пытался до сих пор:

  • Игра с метками min и pref size
  • обертывание метки внутри группы (полосы прокрутки не появятся вообще)
  • масштабирование заключающей группы, а не метки

Что я упускаю? Что я могу сделать, чтобы заставить ScrollPane адаптироваться к представлению содержимого?

Спасибо за помощь.

2 5

2 ответа:

Я реализовал масштабирование в ScrollPane для графов и других узлов в Этот пример видовых экранов scrollpane, преобразований и границ макета в JavaFX.

Код был реализован, когда я впервые изучал JavaFX, поэтому, конечно, код может быть чище, и, возможно, есть более простые способы выполнить это (например, используя группу в качестве контейнера для масштабируемого узла, как предложено в документацииScrollPane ).

Один ключ к получению решения, которое я хотел (Полосы прокрутки появляются только тогда, когда вы увеличены, и узел больше, чем видимый видовой экран), был такой код:

// create a container for the viewable node.
final StackPane nodeContainer = new StackPane();
nodeContainer.getChildren().add(node);

// place the container in the scrollpane and adjust the pane's viewports as required.
final ScrollPane scrollPane = new ScrollPane();
scrollPane.setContent(nodeContainer);
scrollPane.viewportBoundsProperty().addListener(
  new ChangeListener<Bounds>() {
  @Override public void changed(ObservableValue<? extends Bounds> observableValue, Bounds oldBounds, Bounds newBounds) {
    nodeContainer.setPrefSize(
      Math.max(node.getBoundsInParent().getMaxX(), newBounds.getWidth()),
      Math.max(node.getBoundsInParent().getMaxY(), newBounds.getHeight())
    );
  }
});

...

// adjust the view layout based on the node scalefactor.
final ToggleButton scale = new ToggleButton("Scale");
scale.setOnAction(new EventHandler<ActionEvent>() {
  @Override public void handle(ActionEvent actionEvent) {
    if (scale.isSelected()) {
      node.setScaleX(3); node.setScaleY(3);
    } else {
      node.setScaleX(1); node.setScaleY(1);
    }
    // runlater as we want to size the container after a layout pass has been performed on the scaled node.
    Platform.runLater(new Runnable() { 
      @Override public void run() {
        nodeContainer.setPrefSize(
          Math.max(nodeContainer.getBoundsInParent().getMaxX(), scrollPane.getViewportBounds().getWidth()),
          Math.max(nodeContainer.getBoundsInParent().getMaxY(), scrollPane.getViewportBounds().getHeight())
        );
      }
    });
  }
});

В соответствии с документом ScrollPane вы можете попытаться обернуть панель в группу, так что ScrollPane прокручивается визуальной привязкой, а не фактической привязкой макета.

ScrollPane layout calculations are based on the layoutBounds rather than the
boundsInParent (visual bounds) of the scroll node. If an application wants the
scrolling to be based on the visual bounds of the node (for scaled content etc.),
they need to wrap the scroll node in a Group.