在JavaFX和ScrollPanes中进行缩放

时间:2012-09-12 18:26:18

标签: javafx-2

我一直在尝试使用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 个答案:

答案 0 :(得分:8)

根据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. 

答案 1 :(得分:3)

我在ScrollPane for Graphs和其他节点中实现了缩放 this example of scrollpane viewports, transforms and layout bounds in JavaFX

代码是在我第一次学习JavaFX时实现的,因此代码可能更清晰,也许有更简单的方法来实现这一点(例如,使用Group作为{{3}中建议的缩放节点的容器})。

获得我想要的解决方案的一个关键(ScrollBars仅在您放大并且节点大于可见视口时出现)是此代码:

// 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())
        );
      }
    });
  }
});