JavaFX中的Swing组件

JavaFX中的Swing组件,java,swing,javafx,Java,Swing,Javafx,我为即将到来的愚蠢问题提前道歉 JPanel为javaFX提供的paintComponents方法是否有替代品? 或者我应该使用嵌入Swing的JFXPanel吗 例如,我认为时间轴与Swing中的计时器相同,面板/油漆组件对应的是什么 编辑: 例如,我们将如何设置从x-y坐标到另一个坐标的圆的动画?(当然,不使用翻译) 我尝试使用画布绘制东西,但我不知道如何不断更新画布,比如在Swing中调用repaint()。下面是一个网格示例,它使用简单的绑定自动调整大小 import javafx.be

我为即将到来的愚蠢问题提前道歉

JPanel为javaFX提供的paintComponents方法是否有替代品? 或者我应该使用嵌入Swing的JFXPanel吗

例如,我认为时间轴与Swing中的计时器相同,面板/油漆组件对应的是什么

编辑: 例如,我们将如何设置从x-y坐标到另一个坐标的圆的动画?(当然,不使用翻译)


我尝试使用画布绘制东西,但我不知道如何不断更新画布,比如在Swing中调用repaint()。

下面是一个网格示例,它使用简单的绑定自动调整大小

import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;

public class Grid {
    private final Pane view = new Pane();

    private final int numColumns ;
    private final int numRows ;

    // arbitrary defaults of 20:
    private final DoubleProperty prefColumnWidth = new SimpleDoubleProperty(20);
    private final DoubleProperty prefRowHeight = new SimpleDoubleProperty(20);

    public Grid(int numColumns, int numRows) {
        this.numColumns = numColumns ;
        this.numRows = numRows ;

        for (int x = 0 ; x <= numColumns ; x++) {
            Line line = new Line();
            line.startXProperty().bind(view.widthProperty().multiply(x).divide(numColumns));
            line.endXProperty().bind(line.startXProperty());
            line.setStartY(0);
            line.endYProperty().bind(view.heightProperty());
            view.getChildren().add(line);
        }

        for (int y = 0 ; y <= numRows ; y++) {
            Line line = new Line();
            line.startYProperty().bind(view.heightProperty().multiply(y).divide(numRows));
            line.endYProperty().bind(line.startYProperty());
            line.setStartX(0);
            line.endXProperty().bind(view.widthProperty());
            view.getChildren().add(line);
        }

        view.prefWidthProperty().bind(prefColumnWidth.multiply(numColumns));
        view.prefHeightProperty().bind(prefRowHeight.multiply(numRows));
    }

    public final DoubleProperty prefColumnWidthProperty() {
        return this.prefColumnWidth;
    }


    public final double getPrefColumnWidth() {
        return this.prefColumnWidthProperty().get();
    }


    public final void setPrefColumnWidth(final double prefColumnWidth) {
        this.prefColumnWidthProperty().set(prefColumnWidth);
    }


    public final DoubleProperty prefRowHeightProperty() {
        return this.prefRowHeight;
    }


    public final double getPrefRowHeight() {
        return this.prefRowHeightProperty().get();
    }


    public final void setPrefRowHeight(final double prefRowHeight) {
        this.prefRowHeightProperty().set(prefRowHeight);
    }

    public Pane getView() {
        return view;
    }

    public int getNumColumns() {
        return numColumns;
    }

    public int getNumRows() {
        return numRows;
    }

}
有很多不同的方法可以用于此。请注意,上述方法实际上根本不需要子类化,因此您可以编写一个创建窗格的方法:

private Pane createGrid(int numColumns, int numRows) {

    Pane view = new Pane();

    for (int x = 0 ; x <= numColumns ; x++) {
        Line line = new Line();
        line.startXProperty().bind(view.widthProperty().multiply(x).divide(numColumns));
        line.endXProperty().bind(line.startXProperty());
        line.setStartY(0);
        line.endYProperty().bind(view.heightProperty());
        view.getChildren().add(line);
    }

    for (int y = 0 ; y <= numRows ; y++) {
        Line line = new Line();
        line.startYProperty().bind(view.heightProperty().multiply(y).divide(numRows));
        line.endYProperty().bind(line.startYProperty());
        line.setStartX(0);
        line.endXProperty().bind(view.widthProperty());
        view.getChildren().add(line);
    }

    view.setPrefSize(20*numColumns, 20*numRows);
    return view ;
}
这里有一个测试:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class GridTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        Grid grid = new Grid(10,10);
        grid.setPadding(new Insets(20));
        Scene scene = new Scene(grid, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

在JavaFX中,只有画布具有GraphicsContext绘图表面。因此,您可以扩展画布并添加一个repaint()方法,该方法获取Canas.getGraphicsContext2D()并从中进行自己的绘制


进一步说,您可以扩展窗格并将覆盖的画布作为子节点(将窗格和画布宽度/高度属性绑定在一起)。然后您就有了一个支持自定义绘制(并通过画布事件对鼠标事件作出反应)的父组件,就像Swing中的JPanel一样。

我猜您必须使用JavaFx画布。JavaFx中的图形原语通过Prism运行,在许多情况下,Prism将遵从本机图形工具包。因此,没有直接等效的
paintComponent
(因为没有对要绘制的
图形
对象的一般访问)。正如@SedrickJefferson所建议的,您可以根据需要使用一个或子类
Region
并覆盖
layoutChildren()
(以及确定维度的方法),使用
Shape
s和
Text
元素作为子节点。如果您可以更具体地说明您正在尝试执行的操作,您可能会得到更多有用的建议。听起来您试图使用JavaFX,但试图避免按预期的方式使用它。将圆从一个位置设置为另一个位置的动画的方法是使用
TranslateTransition
时间线
,或可能使用
动画计时器
,具体取决于具体要求。为什么要在没有动画API的情况下执行此操作?(不过,
repaint()
的等价物在
Parent
中;在
Canvas
中没有真正的等价物-您可以为
Canvas
设置动画)。过渡很好,但它们不能做所有事情。是的,我给出的例子可以很容易地用转换来完成,但我更感兴趣的是我可以更新我正在做的事情。我感谢你在这方面所做的努力,谢谢你,但我仍然不明白为什么我必须为此付出这么多的努力,而不是仅仅调用repaint()来完成它?JavaFX比Swing有很多改进,我发现Swing非常混乱,但这对我来说是一个麻烦。@MertDuman我不知道定义一个计算行位置的
repaint()
方法比将行位置表示为绑定更容易。代码不是基本相同吗?这里的优点是JavaFX现在自动知道何时需要重新绘制这个网格:您不必指定,JavaFX框架可以最大限度地优化重新绘制(也就是说,只有在某些东西发生变化时才重新绘制,并且只在脉冲上重新绘制-因此它不会在每一条线发生变化时重新计算布局,任何一条线发生变化时只重新计算一次)。@MertDuman并且,正如我在第一次评论中提到的,这里的线(可能,取决于您的平台)实际上是使用本机绘制的(硬件加速)图形;如果用Java代码显式绘制它们,则无法完成。g.drawLine(0,0,0,this.getHeight());g.drawLine(0,0,this.getWidth(),0);这是绘制两行代码所需的代码,当屏幕大小改变时,这两行代码会调整大小。@MertDuman在JavaFX中几乎没有比这两行代码更多的代码了,不是吗?我认为这仅仅是熟悉程度让你觉得swing在这里更容易。我应该补充一点,这个repaint()方法应该做的第一件事就是调用clearRect(0,0,getWidth(),getHeight())在画布的GraphicsContext上。否则,您将在上一次重新绘制()调用中从所有绘制中获得工件。您仍然需要找到一种方法来确保在需要时调用了
重新绘制()
方法:这不会自动发生。
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.Region;

public class Grid extends Region {

    private Canvas canvas ;
    private final int numColumns ;
    private final int numRows ;

    public Grid(int numColumns, int numRows) {
        this.numColumns = numColumns ;
        this.numRows = numRows ;
        canvas = new Canvas();
        getChildren().add(canvas);
    }

    @Override
    protected void layoutChildren() {
        double w = getWidth() - getPadding().getLeft() - getPadding().getRight() ;
        double h = getHeight() - getPadding().getTop() - getPadding().getBottom() ;

        canvas.setWidth(w+1);
        canvas.setHeight(h+1);

        canvas.setLayoutX(getPadding().getLeft());
        canvas.setLayoutY(getPadding().getRight());

        GraphicsContext gc = canvas.getGraphicsContext2D();
        gc.clearRect(0, 0, w, h);

        for (int i = 0 ; i <= numColumns ; i++) {

            // adding 0.5 here centers the line in the physical pixel,
            // making it appear crisper:
            double x = w*i/numColumns + 0.5;

            gc.strokeLine(x, 0, x, h);
        }

        for (int j = 0 ; j <= numRows ; j++) {
            double y = h*j/numRows + 0.5 ;
            gc.strokeLine(0, y, w, y);
        }
    }

    @Override
    protected double computePrefWidth(double height) {
        return 20 * numColumns;
    }

    @Override
    protected double computePrefHeight(double width) {
        return 20 * numRows ;
    }

}
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class GridTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        Grid grid = new Grid(10,10);
        grid.setPadding(new Insets(20));
        Scene scene = new Scene(grid, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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