我想将VBox中的一组节点居中,并在组超出父VBox的边界时缩放该组。
我尝试了以下设置:ScrollPane包含一个VBox,它应该以一组节点(例如圆、线等)为中心。
节点是动态添加的:myCustomPane. getContentPane().get儿童().addAll(椭圆,线)
不幸的是,(红色)组既不居中,也不在窗口中可见。但是我确实看到了(橙色)ScalablePane、(蓝色)VBox和所有节点。
public class ScalablePane extends ScrollPane {
private Property<Group> contentPaneProperty = new SimpleObjectProperty<>();
public ScalablePane() {
setContentPane(new Group());
setPannable(true);
setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
setFitToHeight(true); // center
setFitToWidth(true); // center
setStyle("-fx-background-color: orange;");
}
public final void setContentPane(Group contentPane) {
contentPane.setManaged(false);
contentPane.setStyle("-fx-background-color: red;");
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBox.setManaged(true);
vBox.getChildren().add(contentPane);
vBox.setStyle("-fx-background-color: blue;");
setContent(vBox);
contentPaneProperty.setValue(contentPane);
}
public Group getContentPane() {
return contentPaneProperty.getValue();
}
}
用法:
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
ScalablePane pane = new ScalablePane();
Circle circle = new Circle(200, 40, 20);
Circle circle2 = new Circle(100, 150, 20);
pane.getContentPane().getChildren().addAll(circle, circle2);
Scene scene = new Scene(pane, 400, 400);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
更新:添加了拖动支持
我尝试为我的节点添加拖动支持,以便我可以检查内部窗格何时重新缩放。我还将组更改为简单窗格,以便我可以使内部窗格的边界可见。不幸的是,内部窗格(红色)不能对子节点进行捕捉。如何强制内容窗格获取其子窗格的大小,并在其大小超过父边界时重新缩放?
public class ScalablePane extends ScrollPane {
private final Pane contentPane;
private final Scale contentScaleTransform;
public ScalablePane() {
contentPane = new Pane();
contentScaleTransform = new Scale(1, 1);
initializeScrollPane();
initializeContentPane();
}
public void initializeScrollPane() {
setPannable(true);
setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
setFitToHeight(true); // center
setFitToWidth(true); // center
setStyle("-fx-background-color: orange;");
}
private final void initializeContentPane() {
contentPane.setStyle("-fx-background-color: red;");
VBox vBox = new VBox();
VBox.setMargin(contentPane, new Insets(10));
vBox.setAlignment(Pos.CENTER);
vBox.setManaged(true);
vBox.getChildren().add(contentPane);
vBox.setStyle("-fx-background-color: blue;");
setContent(vBox);
contentPane.layoutBoundsProperty()
.addListener(new ChangeListener<Bounds>() {
@Override
public void changed(ObservableValue<? extends Bounds> observable,
Bounds oldValue, Bounds newValue) {
double parentWidth = getContentPane().getParent().getLayoutBounds()
.getWidth() - 10;
double parentHeight = getContentPane().getParent().getLayoutBounds()
.getHeight() - 10;
if (parentHeight > 0 && parentWidth > 0) {
if (newValue.getHeight() > parentHeight
|| newValue.getWidth() > parentWidth) {
computeScale();
}
}
}
});
}
public void computeScale() {
double realWidth = getContentPane().prefWidth(getWidth());
double realHeight = getContentPane().prefHeight(getHeight());
double leftAndRight = getInsets().getLeft() + getInsets().getRight();
double topAndBottom = getInsets().getTop() + getInsets().getBottom();
double contentWidth = getWidth() - leftAndRight;
double contentHeight = getHeight() - topAndBottom;
double scaleX = contentWidth / realWidth;
double scaleY = contentHeight / realHeight;
double scale = Math.min(scaleX, scaleY);
getContentScaleTransform().setX(scale);
getContentScaleTransform().setY(scale);
getContentPane().resize(contentWidth / getContentScaleTransform().getX(),
contentHeight / getContentScaleTransform().getY());
}
public Pane getContentPane() {
return contentPane;
}
public final Scale getContentScaleTransform() {
return contentScaleTransform;
}
}
用法:
public class Main extends Application {
private double dragOriginalSceneX;
private double dragOriginalSceneY;
@Override
public void start(Stage primaryStage) {
try {
ScalablePane pane = new ScalablePane();
Circle circle = new Circle(200, 40, 20);
Circle circle2 = new Circle(100, 150, 20);
addDragSupport(circle, pane);
addDragSupport(circle2, pane);
pane.getContentPane().getChildren().addAll(circle, circle2);
Scene scene = new Scene(pane, 400, 400);
primaryStage.setScene(scene);
primaryStage.sizeToScene();
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
private void addDragSupport(Circle node, ScalablePane graphPane) {
node.setOnMousePressed(e -> {
dragOriginalSceneX = e.getSceneX()
/ graphPane.getContentScaleTransform().getX();
dragOriginalSceneY = e.getSceneY()
/ graphPane.getContentScaleTransform().getY();
});
node.setOnMouseDragged(e -> {
Circle circle = (Circle) e.getSource();
circle.setManaged(true);
double eventX = e.getSceneX()
/ graphPane.getContentScaleTransform().getX();
double eventY = e.getSceneY()
/ graphPane.getContentScaleTransform().getY();
double offsetX = eventX - dragOriginalSceneX;
double offsetY = eventY - dragOriginalSceneY;
double newX = circle.getCenterX() + offsetX;
double newY = circle.getCenterY() + offsetY;
circle.setCenterX(newX);
circle.setCenterY(newY);
// remember last coordinates
dragOriginalSceneX = eventX;
dragOriginalSceneY = eventY;
});
}
我想我有这个工作的方式,你想要的,除了缩放给它一个尝试,让我知道,如果它的工作原理,你也不能添加CSS到一个组这里是一个例子,一个组可以做的事情,如果你正在寻找更多的信息https://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html#group
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.VBox;
public class ScalablePane extends ScrollPane {
// private Property<Group> contentPaneProperty = new SimpleObjectProperty<>();
private Group contentPane = new Group();
public ScalablePane() {
setContentPane(/*new Group()*/);
setPannable(true);
setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
setFitToHeight(true); // center
setFitToWidth(true); // center
setStyle("-fx-background-color: orange;");
}
public final void setContentPane(/*Group contentPane*/) {
// contentPane.setManaged(false);
contentPane.setStyle("-fx-background-color: red;");
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
vBox.setManaged(true);
vBox.getChildren().add(contentPane);
vBox.setStyle("-fx-background-color: blue;");
setContent(vBox);
// contentPaneProperty.setValue(contentPane);
}
public Group getContentPane() {
return contentPane;
}
}