6 Replies Latest reply: May 9, 2013 5:18 AM by jsmith RSS

    Zoom In, Zoom Out

    917173
      Hello, I did not understand what happens when the square in the following code is zoomed. Please try this code for me. Another problem is happening when applying the zoom out.
      Help :)
      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.beans.value.ChangeListener;
      import javafx.beans.value.ObservableValue;
      import javafx.event.ActionEvent;
      import javafx.event.EventHandler;
      import javafx.geometry.Bounds;
      import javafx.geometry.Pos;
      import javafx.scene.Group;
      import javafx.scene.Node;
      import javafx.scene.Scene;
      import javafx.scene.chart.LineChart;
      import javafx.scene.chart.NumberAxis;
      import javafx.scene.chart.XYChart;
      import javafx.scene.control.Button;
      import javafx.scene.control.RadioButton;
      import javafx.scene.control.ScrollPane;
      import javafx.scene.control.ToggleButton;
      import javafx.scene.control.ToggleGroup;
      import javafx.scene.effect.DropShadow;
      import javafx.scene.layout.*;
      import javafx.scene.shape.Rectangle;
      import javafx.stage.Stage;
      
      
      public class TestZoomController extends Application {
      
          final Button scale1 = new Button("Scale+");
          final Button scale2 = new Button("Scale-");
          ZoomController zoomController;
          final ScrollPane scrollPane = new ScrollPane();
          final StackPane nodeContainer = new StackPane();
          Node node = new Rectangle(0, 0, 100, 100);
      
          public static void main(String[] args) {
              launch(args);
          }
      
          @Override
          public void start(final Stage stage) throws Exception {
      
      
              zoomController = new ZoomController(nodeContainer);
              scale1.setOnAction(new EventHandler<ActionEvent>() {
                  @Override
                  public void handle(ActionEvent actionEvent) {
                      zoomController.zoomIn();
                      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()));
                          }
                      });
      
                  }
              });
              scale2.setOnAction(new EventHandler<ActionEvent>() {
                  @Override
                  public void handle(ActionEvent actionEvent) {
                      zoomController.zoomOut();
                      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()));
                          }
                      });
      
                  }
              });
              nodeContainer.getChildren().add(node);
      
      
             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()));
                  }
              });
      
      
      
              VBox controlPane = new VBox(10);
              controlPane.setStyle("-fx-background-color: linear-gradient(to bottom, gainsboro, silver); -fx-padding: 10;");
              controlPane.getChildren().addAll(
                      HBoxBuilder.create().spacing(10).fillHeight(false).children(scale1, scale2).build());
      
              VBox layout = new VBox();
              VBox.setVgrow(scrollPane, Priority.ALWAYS);
              layout.getChildren().addAll(scrollPane, controlPane);
      
      
      
              final Scene scene = new Scene(layout, 300, 300);
              stage.setScene(scene);
              stage.show();
      
      
      
          }
      }
      import javafx.animation.KeyFrame;
      import javafx.animation.KeyValue;
      import javafx.animation.Timeline;
      import javafx.beans.InvalidationListener;
      import javafx.beans.Observable;
      import javafx.beans.property.DoubleProperty;
      import javafx.beans.property.SimpleDoubleProperty;
      import javafx.beans.value.ChangeListener;
      import javafx.beans.value.ObservableValue;
      import javafx.event.EventHandler;
      import javafx.geometry.Pos;
      import javafx.scene.Cursor;
      import javafx.scene.Group;
      import javafx.scene.Node;
      import javafx.scene.Parent;
      import javafx.scene.input.MouseEvent;
      import javafx.scene.input.ScrollEvent;
      import javafx.scene.layout.StackPane;
      import javafx.scene.shape.Rectangle;
      import javafx.util.Duration;
      
      public class ZoomController extends StackPane {
      
          private int deltaCount = 0;
          private final double DEFAULT_ZOOM = 1.0;
          private DoubleProperty zoomMax = new SimpleDoubleProperty(10.0);
          private DoubleProperty zoomMin = new SimpleDoubleProperty(0.1);
          private DoubleProperty zoomDelta = new SimpleDoubleProperty(1.2);
          private DoubleProperty zoom = new SimpleDoubleProperty(DEFAULT_ZOOM);
          private Group contentWrapper;
      
          public ZoomController(final Node content) {
              super();
              zoom.addListener(new ChangeListener<Number>() {
                  @Override
                  public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
                      System.out.println("Zoom=" + zoom.doubleValue());
                      content.scaleXProperty().bind(zoom);
                      content.scaleYProperty().bind(zoom);
                      content.translateXProperty();
                  }
              });
      
              content.setOnScroll(new EventHandler<ScrollEvent>() {
                  public void handle(ScrollEvent event) {
                      if (event.getDeltaY() > 0) {
                          zoomIn();
                      } else {
                          zoomOut();
                      }
                  }
              });
          }
      
          public void zoomIn() {
              double zoomValue = DEFAULT_ZOOM * Math.pow(zoomDelta.get(), deltaCount + 1);
              System.out.println("Zoooom " + zoomValue);
              if (zoomValue > zoomMax.get()) {
                  setZoom(zoomMax.get());
                  return;
              }
      
              deltaCount++;
              setZoom(zoomValue);
      
          }
      
          public void zoomOut() {
              double zoomValue = DEFAULT_ZOOM * Math.pow(zoomDelta.get(), deltaCount - 1);
              System.out.println("Zoooom " + zoomValue);
              if (zoomValue < zoomMin.get()) {
                  setZoom(zoomMin.get());
                  return;
              }
      
              deltaCount--;
              setZoom(zoomValue);
          }
      
          public void setZoom(double zoomValue) {
              zoom.set(zoomValue);
          }
      }
      帖子经 914170编辑过

      帖子经 914170编辑过
        • 1. Re: Zoom In, Zoom Out
          917173
          Hello any Help please?
          • 2. Re: Zoom In, Zoom Out
            917173
            Hello,

            Here is a better description for my problem.
            In fact when the content is zoomed enough to show the scroll bars, when i click on the scene to see what's happen on my square, no more scroll bars are shown :(
            • 3. Re: Zoom In, Zoom Out
              James_D
              ScrollPane seems to have been a bit buggy, and (very unusually for JavaFX) the responses to bug reports on JIRA for ScrollPane have been somewhat unhelpful.

              The [url http://docs.oracle.com/javafx/2/api/javafx/scene/control/ScrollPane.html]Javadocs for ScrollPane state
              >
              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.
              >

              If you change
              scrollPane.setContent(nodeContainer);
              to
              scrollPane.setContent(new Group(nodeContainer));
              then the scroll pane viewport behaves a lot better. The scroll bars are still not responding correctly: this seems to be a manifestation of [url https://javafx-jira.kenai.com/browse/RT-11253]RT-11253, which was withdrawn.
              • 4. Re: Zoom In, Zoom Out
                James_D
                It looks as though the issue may be to do with the way you are adjusting the preferred size of the Pane containing the Rectangle.

                I'm not sure you need to do this at all; the preferred size of the Pane is going to be "just big enough to hold the rectangle" as it is. Perhaps you added that code in, trying to get the ScrollPane to behave correctly? The way to do this is to wrap the nodeContainer in a Group.

                This seems to work:
                import javafx.application.Application;
                import javafx.event.ActionEvent;
                import javafx.event.EventHandler;
                import javafx.scene.Group;
                import javafx.scene.Scene;
                import javafx.scene.control.Button;
                import javafx.scene.control.ScrollPane;
                import javafx.scene.layout.*;
                import javafx.scene.paint.Color;
                import javafx.scene.shape.Line;
                import javafx.scene.shape.Rectangle;
                import javafx.stage.Stage;
                
                public class TestZoomController extends Application {
                
                  final Button scale1 = new Button("Scale+");
                  final Button scale2 = new Button("Scale-");
                  ZoomController zoomController;
                  final ScrollPane scrollPane = new ScrollPane();
                  final Pane nodeContainer = new Pane();
                  Rectangle node = new Rectangle(0, 0, 100, 100);
                
                  public static void main(String[] args) {
                    launch(args);
                  }
                
                  @Override
                  public void start(final Stage stage) throws Exception {
                
                    zoomController = new ZoomController(nodeContainer);
                
                    scale1.setOnAction(new EventHandler<ActionEvent>() {
                      @Override
                      public void handle(ActionEvent actionEvent) {
                        zoomController.zoomIn();
                      }
                    });
                    scale2.setOnAction(new EventHandler<ActionEvent>() {
                      @Override
                      public void handle(ActionEvent actionEvent) {
                        zoomController.zoomOut();
                      }
                    });
                    node.setStroke(Color.BLACK);
                    node.setFill(Color.ALICEBLUE);
                    nodeContainer.getChildren().add(node);
                
                    // draw a grid so the zoom is more evident:
                    for (int i = 0; i <= 10; i++) {
                      nodeContainer.getChildren().addAll(
                          new Line(i * 10, 0, i * 10, 100),
                          new Line(0, i * 10, 100, i * 10)
                      );
                    }
                
                //  scrollPane.setContent(nodeContainer);
                    scrollPane.setContent(new Group(nodeContainer));
                
                    VBox controlPane = new VBox(10);
                    controlPane.setStyle("-fx-background-color: linear-gradient(to bottom, gainsboro, silver); -fx-padding: 10;");
                    controlPane.getChildren().addAll(HBoxBuilder.create().spacing(10).fillHeight(false).children(scale1, scale2).build());
                
                    VBox layout = new VBox();
                    VBox.setVgrow(scrollPane, Priority.ALWAYS);
                    layout.getChildren().addAll(scrollPane, controlPane);
                
                    final Scene scene = new Scene(layout, 300, 300);
                    stage.setScene(scene);
                    stage.show();
                
                  }
                }
                • 5. Re: Zoom In, Zoom Out
                  917173
                  Hello
                  Thank a lot for your answer, this works much better than before.
                  With this, i still have 2 problems.
                  1/ How to force my rectangle to be at the center from beginning, when zooming In and Out.
                  2/scroll bars seems not to work properly in some cases. When playing with zoom, it seems that some times when the scroll bars should appear it do not while the rectangle is not all shown , and when clicking twice on the scene they appear.
                  The Opposite happens too, the are presenet when they should not, when clicking on the seen, they disappear.
                  • 6. Re: Zoom In, Zoom Out
                    jsmith
                    Try jdk8 and see if your issues are resolved.
                    http://jdk8.java.net/download.html

                    Try this sample (CenteredNodeInScrollPaneExample.java):
                    https://gist.github.com/jewelsea/1442298
                    The sample is like the 3rd small program I wrote in JavaFX, so it may not be the best coded, but maybe something there is helpful for you.