问题
So I am creating a map in JavaFX and I would like to have the whole map visible at times. However, the issue is that after I set the imageView to fit the screen size then adding it to the scrollPane my zoom function works fine, but once I zoom in I am not allowed to pan around the image. Below is the code that I have written.
package gameaspects;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class SourceCodeVersion8 extends Application{
final double SCALE_DELTA = 1.1;
public double SCALE_TOTAL = 1;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
AnchorPane mapAnchorO = addMapAnchor();
Scene mapScene = new Scene(mapAnchorO);
primaryStage.setScene(mapScene);
primaryStage.setFullScreen(true);
primaryStage.setResizable(false);
primaryStage.show();
}
//Creates an AnchorPane for the map
private AnchorPane addMapAnchor()
{
AnchorPane mapAnchor = new AnchorPane();
ScrollPane mapScrollO = addMapScroll();
mapAnchor.getChildren().add(mapScrollO);
AnchorPane.setLeftAnchor(mapScrollO, 0.0);
AnchorPane.setTopAnchor(mapScrollO, 0.0);
AnchorPane.setBottomAnchor(mapScrollO, 0.0);
AnchorPane.setRightAnchor(mapScrollO, 0.0);
return mapAnchor;
}
//Creates an ImageView for the map
private ImageView addMapView()
{
Image mapImage = new Image("WorldProvincialMap-v1.01.png");
ImageView mapView = new ImageView(mapImage);
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
int width = gd.getDisplayMode().getWidth();
int height = gd.getDisplayMode().getHeight();
mapView.setFitHeight(height);
mapView.setFitWidth(width);
return mapView;
}
//Creates a scrollPane for the map
private ScrollPane addMapScroll()
{
ScrollPane mapScroll = new ScrollPane();
ImageView mapViewO = addMapView();
mapScroll.setContent(mapViewO);
mapScroll.setPannable(true);
mapScroll.setVbarPolicy(ScrollBarPolicy.NEVER);
mapScroll.setHbarPolicy(ScrollBarPolicy.NEVER);
mapScroll.addEventFilter(ScrollEvent.ANY, e ->{
e.consume();
if(e.getDeltaY() == 0)
{
return;
}
double scaleFactor =
(e.getDeltaY() > 0)
? SCALE_DELTA
: 1/SCALE_DELTA;
if(scaleFactor * SCALE_TOTAL >= 1)
{
mapScroll.setScaleX(mapScroll.getScaleX() * scaleFactor);
mapScroll.setScaleY(mapScroll.getScaleY() * scaleFactor);
SCALE_TOTAL *= scaleFactor;
}
});
return mapScroll;
}
}
回答1:
You're scaling the ScrollPane
instead of the content. Furthermore even if you scale the ImageView
, scaleX
and scaleY
are not taken into account when it comes to calculating the content's size. Therefore the ImageView
should also be wrapped in a Group
:
private ScrollPane addMapScroll() {
ScrollPane mapScroll = new ScrollPane();
ImageView mapViewO = addMapView();
mapScroll.setContent(new Group(mapViewO));
mapScroll.setPannable(true);
mapScroll.setVbarPolicy(ScrollBarPolicy.NEVER);
mapScroll.setHbarPolicy(ScrollBarPolicy.NEVER);
mapScroll.addEventFilter(ScrollEvent.ANY, e -> {
e.consume();
if (e.getDeltaY() == 0) {
return;
}
double scaleFactor
= (e.getDeltaY() > 0)
? SCALE_DELTA
: 1 / SCALE_DELTA;
if (scaleFactor * SCALE_TOTAL >= 1) {
mapViewO.setScaleX(mapViewO.getScaleX() * scaleFactor);
mapViewO.setScaleY(mapViewO.getScaleY() * scaleFactor);
SCALE_TOTAL *= scaleFactor;
}
});
return mapScroll;
}
To "keep the center centered" you need to adjust he scroll positions accordingly:
if (scaleFactor * SCALE_TOTAL >= 1) {
Bounds viewPort = mapScroll.getViewportBounds();
Bounds contentSize = mapViewO.getBoundsInParent();
double centerPosX = (contentSize.getWidth() - viewPort.getWidth()) * mapScroll.getHvalue() + viewPort.getWidth() / 2;
double centerPosY = (contentSize.getHeight() - viewPort.getHeight()) * mapScroll.getVvalue() + viewPort.getHeight() / 2;
mapViewO.setScaleX(mapViewO.getScaleX() * scaleFactor);
mapViewO.setScaleY(mapViewO.getScaleY() * scaleFactor);
SCALE_TOTAL *= scaleFactor;
double newCenterX = centerPosX * scaleFactor;
double newCenterY = centerPosY * scaleFactor;
mapScroll.setHvalue((newCenterX - viewPort.getWidth()/2) / (contentSize.getWidth() * scaleFactor - viewPort.getWidth()));
mapScroll.setVvalue((newCenterY - viewPort.getHeight()/2) / (contentSize.getHeight() * scaleFactor -viewPort.getHeight()));
}
回答2:
I improved your version with a mouseDragHandler.
This should be the right solution for your problem!
package test;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ScrollPane.ScrollBarPolicy;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class test extends Application {
final double SCALE_DELTA = 1.1;
public double SCALE_TOTAL = 1;
public double dragDeltay;
public double dragDeltax;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
AnchorPane mapAnchorO = addMapAnchor();
Scene mapScene = new Scene(mapAnchorO);
primaryStage.setScene(mapScene);
primaryStage.setFullScreen(true);
primaryStage.setResizable(false);
primaryStage.show();
}
// Creates an AnchorPane for the map
private AnchorPane addMapAnchor() {
AnchorPane mapAnchor = new AnchorPane();
ScrollPane mapScrollO = addMapScroll();
mapAnchor.getChildren().add(mapScrollO);
AnchorPane.setLeftAnchor(mapScrollO, 0.0);
AnchorPane.setTopAnchor(mapScrollO, 0.0);
AnchorPane.setBottomAnchor(mapScrollO, 0.0);
AnchorPane.setRightAnchor(mapScrollO, 0.0);
return mapAnchor;
}
// Creates an ImageView for the map
private ImageView addMapView() {
Image mapImage = new Image("WorldProvincialMap-v1.01.png");
ImageView mapView = new ImageView(mapImage);
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
int width = gd.getDisplayMode().getWidth();
int height = gd.getDisplayMode().getHeight();
mapView.setFitHeight(height);
mapView.setFitWidth(width);
return mapView;
}
// Creates a scrollPane for the map
private ScrollPane addMapScroll() {
ScrollPane mapScroll = new ScrollPane();
ImageView mapViewO = addMapView();
mapScroll.setContent(mapViewO);
mapViewO.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
dragDeltax = mapViewO.getX() - mouseEvent.getScreenX();
dragDeltay = mapViewO.getY() - mouseEvent.getScreenY();
}
});
mapViewO.setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent mouseEvent) {
mapScroll.setTranslateX(mouseEvent.getScreenX() + dragDeltax);
mapScroll.setTranslateY(mouseEvent.getScreenY() + dragDeltay);
}
});
mapScroll.setVbarPolicy(ScrollBarPolicy.NEVER);
mapScroll.setHbarPolicy(ScrollBarPolicy.NEVER);
mapScroll.addEventFilter(ScrollEvent.ANY, e -> {
e.consume();
if (e.getDeltaY() == 0) {
return;
}
double scaleFactor = (e.getDeltaY() > 0) ? SCALE_DELTA : 1 / SCALE_DELTA;
if (scaleFactor * SCALE_TOTAL >= 1) {
mapScroll.setScaleX(mapScroll.getScaleX() * scaleFactor);
mapScroll.setScaleY(mapScroll.getScaleY() * scaleFactor);
SCALE_TOTAL *= scaleFactor;
}
});
return mapScroll;
}
}
来源:https://stackoverflow.com/questions/39529840/javafx-setfitheight-setfitwidth-for-an-image-used-within-a-scrollpane-disabl