Масштабирование в 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 адаптировался к представлению содержимого?

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


person sarcan    schedule 12.09.2012    source источник
comment
Масштабируемая панорамируемая панель прокрутки: stackoverflow.com/a/44314455/1386911   -  person Daniel Hári    schedule 01.06.2017


Ответы (2)


Я реализовал масштабирование в ScrollPane for Graphs и других узлах в этом примере областей просмотра, преобразований и границ макета в 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())
        );
      }
    });
  }
});
person jewelsea    schedule 12.09.2012
comment
Благодарю за ваш ответ. Код производит несколько довольно странных побочных эффектов (например, при уменьшении масштаба полосы прокрутки не будут правильно адаптироваться, пока не будут перемещены), но подход, безусловно, правильный. Это мне очень помогло. - person sarcan; 13.09.2012

В соответствии с документом 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. 
person Nuntipat Narkthong    schedule 13.07.2013