2017-04-07 39 views
0

我为即将到来的愚蠢问题提前道歉。JavaFX中的Swing paintComponents

是否有替换JPAnel for javaFX的paintComponents方法? 或者我应该只使用嵌入Swing的JFXPanel?

例如我想到时间轴和Swing中的Timer是一样的,Panel/paintComponents对应的事情是什么?

编辑: 例如,我们将如何去动画从x-y坐标到另一个坐标的圆? (当然,没有使用TranslateTransition)

我试图用画布绘画,但我无法弄清楚如何不断更新画布,就像在Swing中调用repaint()一样?

+0

我猜你必须使用JavaFx画布。 – Sedrick

+1

JavaFX中的图形原语通过Prism运行,Prism在很多情况下都会遵循本地图形工具包。因此没有'paintComponent'的直接等价物(因为没有通用的Graphics对象来绘制)。您可以按照@SedrickJefferson的建议,使用['Canvas'](http://docs.oracle.com/javase/8/javafx/api/javafx/scene/canvas/Canvas.html),或者可能使用子类'根据需要使用“Shape”和“Text”元素作为子节点,并覆盖'layoutChildren()'(以及确定维度的方法)。 –

+0

如果您可以更具体地了解您正在尝试做什么,那么您可能会收到更多有用的建议。 –

回答

1

这是一个网格的例子,它使用简单的绑定自动调整大小。

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

} 

这里有一个简单的测试:

import javafx.application.Application; 
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); 
     Scene scene = new Scene(grid.getView()); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

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

有一堆,你可以使用此不同的方法。需要注意的是上面的方法并不真正需要的子类在所有的,所以你可以只写创建窗格的方法:

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

或者,如果你想要的东西更接近做事的AWT /春路,你可以继承Region,使用Canvas,并覆盖Region.layoutChildren()layoutChildren()方法被称为布局过程的一部分(如果区域更改大小,将会触发该方法)。在这其中我添加填充支持:

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

我很感谢你给了这个努力,并感谢你,但我还是不明白,为什么我不得不作出这么大的力气出这个,而不是能够只是调用重绘(),并把它做了什么? JavaFX在Swing方面有很多改进,我发现Swing非常混乱,但这对我来说是一件好事。 – Random

+0

@MertDuman我没有看到如何定义计算行位置的repaint()方法比表示行的位置作为绑定更容易。代码基本不相同吗?这样做的优点是重绘时,需要这个网格,现在的JavaFX自动知道:你没有指定和JavaFX的框架可以最大限度地优化重绘(即只重绘,如果事情发生了变化,并且只有在脉冲重绘 - 因此它不会重新计算每行更改的布局,只是在任何行更改时重新计算布局)。 –

+0

@MertDuman同样,正如我在第一条评论中提到的,这里的行(可能取决于您的平台)实际上是使用本机(硬件加速的)图形绘制的;如果您明确地使用无法完成的Java代码绘制它们。 –

0

在JavaFX中,具有GraphicsContext纸面唯一事情是一个Canvas。所以你可以扩展Canvas并添加一个获取Canas.getGraphicsContext2D()的repaint()方法,并从那里做它自己的绘画。

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

+0

我要补充一点,重绘()方法应该做的第一件事就是调用clearRect(0,0,的getWidth (),getHeight())在画布'GraphicsContext。否则,您将在之前的repaint()调用中完成所有绘图中的工件。 – BinaryDigit09

+0

您仍然需要找到一种方法来确保您的'repaint()'方法在需要时被调用:这不会自动发生。 –