簡體   English   中英

帶有layoutChildren()的JavaFX中的AutoScalePane

[英]AutoScalePane in JavaFX with layoutChildren()

我試圖創建一個自定義窗格,它將其內容縮放到窗格的可用空間。

我創建了一個演示應用程序,該應用程序使用SplitPane拆分舞台。 每個拆分包含一個AutoScalePane(請參閱FMXL)。 我希望AutoScalePane會根據可用空間來縮小/增加其內容(請使用分割條播放)

AutoScalePane的內容被分組在一個組中,隨着AutoScalePane邊界的變化,該組應進行縮放。

即使我收到正確的邊界並可以計算正確的縮放比例(檢查調試日志),Circle節點也不會縮放。

我假設我在layoutChildren()方法中犯了一個錯誤,但是看不到明顯的問題。

如果有更多JavaFX經驗的人可以幫助我,那就太好了:)

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

視圖控制器:

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視圖:

<?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-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 如果您通過layoutChildren方法調整比例,則無需注冊偵聽器。

至於縮放:您永遠不會真正修改scale屬性。 除了以下代碼段外,您沒有在其他任何地方更新Scale

double zoomFactor = Math.min(zoom.getX(), zoom.getY());
zoom.setX(zoomFactor);
zoom.setY(zoomFactor);

因此zoom.getX()zoom.getY()始終返回1 ,該值等於初始比例因子。

請注意,您可以將Scale矩陣直接應用於內容節點的transforms ,但這不會將中心用作縮放的樞軸點。

順便說一句:通過擴展Region而不是Pane ,可以將對children列表的訪問限制為protected ,從而阻止用戶對其進行修改。

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

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM