请注意,您可以将 Scale 矩阵直接应用于内容节点的 transforms ,但这不会将中心用作缩放的枢轴点. BTW:通过扩展 Region (而不是 Pane ),您可以将对 children 列表的访问限制为受 protected 阻止用户对其进行修改. 公共类AutoScalePane扩展了Region {私人最终小组内容= new Group();公共AutoScalePane(){content.setManaged(false);//避免按内容限制大小getChildren().add(content);}/***将节点添加到AutoScalePane** @param子节点*/public void addChildren(Node ... children){content.getChildren().addAll(children);requestLayout();}@Override受保护的void layoutChildren(){final Bounds groupBounds = content.getBoundsInLocal();最后的double paneWidth = getWidth();最后的double paneHeight = getHeight();最后的double insetTop = getInsets().getTop();最后的double insetRight = getInsets().getRight();最后的double insetLeft = getInsets().getLeft();最后的double insertBottom = getInsets().getBottom();最后的double contentWidth =(paneWidth-insetLeft-insetRight);最后的double contentHeight =(paneHeight-insetTop-insertBottom);//飞涨double factorX = contentWidth/groupBounds.getWidth();double factorY = contentHeight/groupBounds.getHeight();双因素= Math.min(factorX,factorY);content.setScaleX(factor);content.setScaleY(factor);layoutInArea(content,insetLeft,insetTop,contentWidth,contentHeight,getBaselineOffset(),HPos.CENTER,VPos.CENTER);}} I am trying to created a custom pane, which scales it's content to the available space of the pane.I created a demo application, which splits the Stage with a SplitPane. Each split contains one AutoScalePane (see FMXL). I would expect the AutoScalePane to shrink/grow its content according to the available space (please play with the split bar)The content of the AutoScalePane is grouped in a Group, which should be scaled, as the AutoScalePane boundaries change.Even though, I receive the correct bounds and can compute the right zoom ratio (check debug log), the Circle nodes are not scaled..I assume that I made a mistake in the layoutChildren() method, but I can't see an obvious issue.It would be great if somebody with more JavaFX experience could help me :)public class Main extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { Parent root = FXMLLoader.load(getClass().getResource("sample.fxml")); primaryStage.setTitle("AutoScalePane Test"); primaryStage.setScene(new Scene(root, 700, 200)); primaryStage.show(); }}View Controller:public class Controller { @FXML public AutoScalePane scalePaneLeft; @FXML public AutoScalePane scalePaneRight; @FXML public void initialize() { fillLeftContent(); fillRightContent(); } private void fillLeftContent() { Circle circle1 = new Circle(100, 300, 10); Circle circle2 = new Circle(150, 300, 10); Circle circle3 = new Circle(200, 300, 10); Circle circle4 = new Circle(250, 300, 10); scalePaneLeft.addChildren(new Node[] {circle1, circle2, circle3, circle4}); } private void fillRightContent() { Circle circle1 = new Circle(100, 200, 20); Circle circle2 = new Circle(150, 200, 20); Circle circle3 = new Circle(200, 200, 20); Circle circle4 = new Circle(250, 200, 20); scalePaneRight.addChildren(new Node[] {circle1, circle2, circle3, circle4}); }}FXML View:<?import javafx.scene.control.SplitPane?><?import javafx.scene.layout.AnchorPane?><?import sample.AutoScalePane?><AnchorPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml"> <SplitPane dividerPositions="0.3" orientation="HORIZONTAL" AnchorPane.topAnchor="0" AnchorPane.bottomAnchor="0" AnchorPane.leftAnchor="0" AnchorPane.rightAnchor="0" style="-fx-background-color: #2c5069;"> <AutoScalePane fx:id="scalePaneLeft" style="-fx-background-color: #943736;"/> <AutoScalePane fx:id="scalePaneRight" style="-fx-background-color: #d27452;"/> </SplitPane></AnchorPane>Auto-scale Pane: /** * Auto-scales its content according to the available space of the Pane. * The content is always centered * */ public class AutoScalePane extends Pane { private Group content = new Group(); private Scale zoom = new Scale(1, 1); public AutoScalePane() { layoutBoundsProperty().addListener((o) -> { autoScale(); }); content.scaleXProperty().bind(zoom.xProperty()); content.scaleYProperty().bind(zoom.yProperty()); getChildren().add(content); } /** * Adds nodes to the AutoScalePane * * @param children nodes */ public void addChildren(Node... children) { content.getChildren().addAll(children); requestLayout(); } private void autoScale() { if (getHeight() > 0 && getWidth() > 0 && content.getBoundsInParent().getWidth() > 0 && content.getBoundsInParent().getHeight() > 0) { // scale double scaleX = getWidth() / content.getBoundsInParent().getWidth(); double scaleY = getHeight() / content.getBoundsInParent() .getHeight(); System.out.println("*************** DEBUG ****************"); System.out.println("Pane Width: " + getWidth()); System.out.println("Content Bounds Width: " + content .getBoundsInParent() .getWidth()); System.out.println("Pane Height: " + getHeight()); System.out.println("Content Bounds Height: " + content .getBoundsInParent() .getHeight()); System.out.println("ScaleX: " + scaleX); System.out.println("ScaleY: " + scaleY); double zoomFactor = Math.min(scaleX, scaleY); zoom.setX(zoomFactor); zoom.setY(zoomFactor); requestLayout(); } } @Override protected void layoutChildren() { final double paneWidth = getWidth(); final double paneHeight = getHeight(); final double insetTop = getInsets().getTop(); final double insetRight = getInsets().getRight(); final double insetLeft = getInsets().getLeft(); final double insertBottom = getInsets().getBottom(); final double contentWidth = (paneWidth - insetLeft - insetRight) * zoom.getX(); final double contentHeight = (paneHeight - insetTop - insertBottom) * zoom.getY(); layoutInArea(content, 0, 0, contentWidth, contentHeight, getBaselineOffset(), HPos.CENTER, VPos.CENTER); } } 解决方案 layoutChildren is invoked on a change of the size of the node. You don't need to register a listener if you adjust the scale from the layoutChildren method.As for the zoom: You never really modify the scale properties. You don't update the Scale anywhere but in this snippet:double zoomFactor = Math.min(zoom.getX(), zoom.getY());zoom.setX(zoomFactor);zoom.setY(zoomFactor);so zoom.getX() and zoom.getY() always return 1 which is equal to the initial scale factor.Note that you can apply the Scale matrix to the transforms of the content node directly, but this wouldn't use the center as a pivot point of the zoom.BTW: By extending Region instead of Pane you restrict the access to the children list to protected which prevents users from modifying it.public class AutoScalePane extends Region { private final Group content = new Group(); public AutoScalePane() { content.setManaged(false); // avoid constraining the size by content getChildren().add(content); } /** * Adds nodes to the AutoScalePane * * @param children nodes */ public void addChildren(Node... children) { content.getChildren().addAll(children); requestLayout(); } @Override protected void layoutChildren() { final Bounds groupBounds = content.getBoundsInLocal(); final double paneWidth = getWidth(); final double paneHeight = getHeight(); final double insetTop = getInsets().getTop(); final double insetRight = getInsets().getRight(); final double insetLeft = getInsets().getLeft(); final double insertBottom = getInsets().getBottom(); final double contentWidth = (paneWidth - insetLeft - insetRight); final double contentHeight = (paneHeight - insetTop - insertBottom); // zoom double factorX = contentWidth / groupBounds.getWidth(); double factorY = contentHeight / groupBounds.getHeight(); double factor = Math.min(factorX, factorY); content.setScaleX(factor); content.setScaleY(factor); layoutInArea(content, insetLeft, insetTop, contentWidth, contentHeight, getBaselineOffset(), HPos.CENTER, VPos.CENTER); }} 这篇关于带有layoutChildren()的JavaFX中的AutoScalePane的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
07-29 12:39
查看更多