当前位置: 首页 > 知识库问答 >
问题:

Java FX缩放画布

曹涵润
2023-03-14

我的出发点如下:

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.*?>
<?import javafx.scene.image.*?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="scalingcanvas.FXMLDocumentController">
   <center>
      <AnchorPane BorderPane.alignment="CENTER">
         <children>
            <Canvas fx:id="canvas" height="200.0" width="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
         </children>
      </AnchorPane>
   </center>
   <top>
      <Label text="top" BorderPane.alignment="CENTER" />
   </top>
   <bottom>
      <Label text="bottom" BorderPane.alignment="CENTER" />
   </bottom>
   <left>
      <Label text="left" BorderPane.alignment="CENTER" />
   </left>
   <right>
      <Label text="right" BorderPane.alignment="CENTER" />
   </right>
</BorderPane>

Java FX控制器:

package scalingcanvas;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;

public class FXMLDocumentController implements Initializable {

    @FXML
    private Canvas canvas;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        System.out.printf("hi\n");
        GraphicsContext g2d = canvas.getGraphicsContext2D();
        double w = canvas.getWidth();
        double h = canvas.getHeight();
        g2d.setFill(Color.ALICEBLUE);
        g2d.fillRect(0, 0, w, h);
        g2d.setStroke(Color.BLUE);
        g2d.strokeOval(0, 0, w, h);
        g2d.strokeLine(0, 0, w, h);
        g2d.strokeLine(0, h, w, 0);
    }    
}
package scalingcanvas;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class ScalePanel extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

共有1个答案

何高歌
2023-03-14

根据我在这里找到的代码,我最终得出了这个解决方案:

/*
 * Based on http://gillius.org/blog/2013/02/javafx-window-scaling-on-resize.html
 */
package dsfxcontrols;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;

/**
 * A StackPane that <i>scales</i> its contents to fit (preserving aspect ratio),
 * or fill (scaling independently in X and Y) the available area.
 * <p>
 * Note <code>AutoScalingStackPane</code> applies to the contents a scaling
 * transformation rather than attempting to resize the contents.
 * <p>
 * If the contents is a Canvas with pixel dimension 50 by 50, after scaling the
 * Canvas still will have 50 by 50 pixels and the appearance may be pixelated
 * (this might be desired if the application is interfacing a camera and the
 * Canvas needs to match in size the camera's CCD size).
 * <p>
 * If the content contains FX Controls then these get magnified rather than
 * resized, that is all text and graphics are scaled (this might be desired for
 * Point of Sale full screen applications)
 * <p>
 * <h3>Known Limitations</h3>
 * Rescaling occurs only when the AutoScalingStackPane is resized, it does not
 * occur automatically if and when the content changes size.
 *
 *
 * @author michaelellis
 */
public class AutoScalingStackPane extends StackPane {

    /**
     * Force scale transformation to be recomputed based on the size of this
     * <code>AutoScalingStackPane</code> and the size of the contents.
     */
    public void rescale() {
        if (!getChildren().isEmpty()) {
            getChildren().forEach((c) -> {
                double xScale = getWidth() / c.getBoundsInLocal().getWidth();
                double yScale = getHeight() / c.getBoundsInLocal().getHeight();
                if (autoScale.get() == AutoScale.FILL) {
                    c.setScaleX(xScale);
                    c.setScaleY(yScale);
                } else if (autoScale.get() == AutoScale.FIT) {
                    double scale = Math.min(xScale, yScale);
                    c.setScaleX(scale);
                    c.setScaleY(scale);
                } else {
                    c.setScaleX(1d);
                    c.setScaleY(1d);
                }
            });
        }
    }

    private void init() {
        widthProperty().addListener((b, o, n) -> rescale());
        heightProperty().addListener((b, o, n) -> rescale());
    }

    /**
     * No argument constructor required for Externalizable (need this to work
     * with SceneBuilder).
     */
    public AutoScalingStackPane() {
        super();
        init();
    }

    /**
     * Convenience constructor that takes a content Node.
     *
     * @param content
     */
    public AutoScalingStackPane(Node content) {
        super(content);
        init();
    }

    /**
     * AutoScale scaling options:
     * {@link AutoScale#NONE}, {@link AutoScale#FILL}, {@link AutoScale#FIT}
     */
    public enum AutoScale {

        /**
         * No scaling - revert to behaviour of <code>StackPane</code>.
         */
        NONE,
        /**
         * Independently scaling in x and y so content fills whole region.
         */
        FILL,
        /**
         * Scale preserving content aspect ratio and center in available space.
         */
        FIT
    }

    // AutoScale Property
    private ObjectProperty<AutoScale> autoScale = new SimpleObjectProperty<AutoScale>(this, "autoScale",
            AutoScale.FIT);

    /**
     * AutoScalingStackPane scaling property
     *
     * @return AutoScalingStackPane scaling property
     * @see AutoScale
     */
    public ObjectProperty<AutoScale> autoScaleProperty() {
        return autoScale;
    }

    /**
     * Get AutoScale option
     *
     * @return the AutoScale option
     * @see AutoScale
     */
    public AutoScale getAutoScale() {
        return autoScale.getValue();
    }

    /**
     * Set the AutoScale option
     *
     * @param newAutoScale
     * @see AutoScale
     *
     */
    public void setAutoScale(AutoScale newAutoScale) {
        autoScale.setValue(newAutoScale);
    }
}

AutoScalingStackPane应用缩放转换来缩放其内容,以填充或适合StackPane大小(保留纵横比)。我添加了一个AutoScale属性,允许您选择缩放选项(无、适合、缩放)。

如果您编译到一个Jar,它就可以在SceneBuilder中使用(和测试)。下面是我使用它的fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.web.*?>
<?import java.lang.*?>
<?import dsfxcontrols.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.shape.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import scalingcanvas.*?>
<?import javafx.scene.text.*?>
<?language javascript?>

<BorderPane fx:id="root" prefHeight="324.0" prefWidth="318.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1">

    <top>
        <Label text="top" BorderPane.alignment="CENTER" />
    </top>
    <bottom>
        <Label fx:id="bottom" text="bottom" BorderPane.alignment="CENTER" />
    </bottom>
    <left>
        <Label text="left" BorderPane.alignment="CENTER" />
    </left>
    <right>
        <Label text="right" BorderPane.alignment="CENTER" />
    </right>
    <center>
        <AutoScalingStackPane minHeight="20.0" minWidth="20.0" style="-fx-border-color: blue; -fx-background-color: aliceblue;" BorderPane.alignment="CENTER">

            <children>
                <Group>
                    <children>
                        <Circle fill="#c891c9b2" radius="100.0" stroke="BLACK" strokeType="INSIDE" />
                        <Circle fill="#ff781f62" layoutX="73.0" layoutY="111.0" radius="79.0" stroke="BLACK" strokeType="INSIDE" />
                        <Rectangle arcHeight="5.0" arcWidth="5.0" fill="DODGERBLUE" height="129.0" layoutX="-22.0" layoutY="-19.0" opacity="0.24" stroke="#f80000" strokeType="INSIDE" strokeWidth="3.0" width="141.0" />
                        <Button layoutX="-86.0" layoutY="150.0" mnemonicParsing="false" onAction="bottom.setText(Date());timeLabel.setText(Date());" text="Hello" />
                  <Label fx:id="timeLabel" alignment="CENTER" layoutX="-86.0" layoutY="-70.0" text="Label" textAlignment="CENTER">
                     <font>
                        <Font name="Brush Script MT Italic" size="12.0" />
                     </font>
                  </Label>
                    </children>
                </Group>
            </children>
        </AutoScalingStackPane>
    </center>
</BorderPane>
 类似资料:
  • 我的JavaFX 8应用程序中有以下代码,用于控制添加到场景中的画布元素的变换比例: 问题是,就像它所说的,附加到转换中,并且由于浮点精度,每次滚动时缩放级别都会略有不同。 由于某些原因,我必须修改图形上下文转换,而不是直接修改画布(换句话说,要进行翻译,我必须使用transform.setTx(…) 而不是画布。setTranslateX(…) 。 解决方案是设置转换的尺度,同时考虑枢轴点(即鼠

  • 缩放画布时,有什么方法可以阻止这种模糊吗?我想这和GPU插值有关。但我这里需要的是一个像素完美的“像素化”变焦。只需使用最近的“真实”相邻像素的颜色。 我在这里看到了解决方案,但在这两个解决方案中,有一个建议工作(#1/#4),#4肯定是CPU扩展,而#1我猜也是。 这种缩放需要快速——我希望能够支持多达20-25层(可能是StackPane中的画布,但我对其他想法持开放态度,只要它们不融化中央处

  • 我想在JavaFX中实现一个linechart,它应该是可缩放/可滚动的。 我使用SceneBuilder创建图表,所有数据都正确显示。我的目标是用户能够放大和滚动到侧面(x轴)。

  • 问题内容: 如何才能平滑地为画布创建缩放动画?GWT提供了一种获取滚轮数量的方法和。 这里的问题是,每个车轮运动都会执行此方法,并且如果我在该方法本身中调用画布重绘,事情会变得很滞后。 因此,我想到了以某种方式制作缩放动画的方法。但是如何? 我考虑过创建一个,但没有真正的主意,因为只有mousewheelevent作为起点,而用户没有完成用滚轮缩放的终点… 问题答案: 这是我用来缩放图像的可伸缩图

  • 除了平移和旋转,HTML5的画布API还提供了缩放画布上下文的手段。本节,我们将使用scale()方法来按比例缩小画布上下文的高度。 图4-5 缩放画布上下文 绘制步骤 按照以下步骤,绘制一个按比例缩小的矩形: 1. 定义画布上下文,及矩形的尺寸: window.onload = function(){ var canvas  = document.getElementById("myCan

  • 我一直在尝试使用JavaFX中的缩放转换,但还没有完全理解它。基本上,我有一个窗格包含一个复杂的图形,并希望能够撤销它。缩放部分本身工作得很好,但是,封闭的滚动窗格将不适应图形。 为了简单起见,我将发布一个简短的示例,其中我的图被一个标签替换: null 我错过了什么?如何使滚动窗格适应内容视图? 谢谢你的帮助。