2017-04-07 82 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()'方法在需要時被調用:這不會自動發生。 –

相關問題