2017-04-04 49 views
1

簡介:JavaFX從畫布中刪除最後繪製的物體

我創建了一個畫布,我的目標是在您點擊畫布的地方創建圓圈。但我也希望能夠刪除我繪製的圈子或至少最後繪製的圈子。在圓圈背景顏色相同的地方重畫不是一個好的解決方案。因爲如果圈子下還有其他東西,他們也會被刪除。例如,在這個應用程序中,2個圓可能有交點,當您嘗試刪除第2個圓時,這些交點將是空的,這意味着也會刪除第一個圓的某個部分。所以我想創建第二個畫布。每次我在繪製圓圈前點擊畫布上的某處,我都會將主畫布分配給備份畫布。當我想刪除最後繪製的對象時,我可以加載備份畫布。

現在我試圖做我上面解釋過的,不能按照我打算做的那樣工作。事實上,我甚至在其他事情上看到了一些奇怪的現象(至少對我來說)。

我所做的是基本上創建2個相同大小的畫布。

public class Main extends Application { 
    double ldx, ldy, diameter; 
    Canvas lastCanvas = new Canvas(800,600); 
    Canvas pane1 = new Canvas(800,600); 

    @Override 
    public void start(Stage primaryStage) throws Exception{ 
     System.out.println("Hello"); 
     HBox root = new HBox(); 

     GraphicsContext gc = pane1.getGraphicsContext2D(); 
     pane1.setOnMouseClicked(new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent event) { 
       // Draw circle around x,y 
       lastCanvas = pane1; 
       diameter = 25.0; 
       ldx = event.getSceneX() - (diameter/2); 
       ldy = event.getSceneY() - (diameter/2); 
       gc.strokeOval(ldx, ldy, diameter, diameter); 
       System.out.println("Clicked"); 
      } 
     }); 
     VBox pane2 = new VBox(10); 
     pane2.setPrefSize(224,600); 
     Button button1 = new Button("Clear Last Drawn"); 
     button1.setOnMouseClicked(new EventHandler<MouseEvent>() { 
      @Override 
      public void handle(MouseEvent event) { 
       pane1 = lastCanvas; 
       System.out.println("Last canvas loaded"); 
      } 
     }); 
     pane2.getChildren().addAll(button1); 
     pane1.setStyle("-fx-background-color: #224488"); 
     pane2.setStyle("-fx-background-color: #224488"); 
     root.getChildren().addAll(pane1, pane2); 
     Scene scene1 = new Scene(root, 1024, 600); 
     primaryStage.setScene(scene1); 
     primaryStage.setTitle("Mouse Clicker"); 
     primaryStage.show(); 

    } 
} 

預期的行爲是,我每次點擊按鈕,它會加載lastCanvas這是畫布,然後繪製最後一個對象。但事實並非如此。我在button1的mouseevent裏面試過類似的東西

root.getChildren().removeAll(); 
root.getChildren().addAll(lastCanvas, pane2); 

這會在每次點擊按鈕時在控制檯上產生錯誤。另一個問題是我試圖創建第二個場景。

HBox root2 = new HBox(); 
root2.getChildren().addAll(lastCanvas, pane2); 

雖然我沒有在任何地方使用root2,但是這樣做令人驚訝地刪除了pane2上的所有內容。我在這裏所做的就是創建一個新的HBox並將pane2添加到該Hbox中。爲什麼這樣做會從我的primaryStage中刪除pane2而不是留下空白區域?

此外,如果您有其他建議刪除畫布上繪製的最後一個對象-once或直到canvas完全爲空,您也可以告訴我,而不是試圖解決我在上面的代碼中做錯了什麼。

+0

「這樣做令人驚訝地刪除了pane2上的所有內容,儘管我沒有在任何地方使用root2,我在這裏所做的只是創建一個新的HBox並將pane2添加到該hbox中。」=>從[Node doc](https:/ /docs.oracle.com/javase/8/javafx/api/javafx/scene/Node。如果一個程序向一個Parent(包括Group,Region等)添加一個子節點並且該節點已經是一個不同的Parent或一個Scene的根的子節點,那麼該節點會自動(並且默默)從其前父母「。每個問題的一個問題是好的:-) – jewelsea

回答

0

沒有分析這個問題,我建議你使用如下代碼解決方案爲基礎

private final double diameter = 25; 
    private final LinkedList<Point2D> centers = new LinkedList<>(); 
    private final Canvas pane1 = new Canvas(800, 600); 

    @Override 
    public void start(Stage primaryStage) throws Exception 
    { 
     System.out.println("Hello"); 
     HBox root = new HBox(); 

     pane1.setOnMouseClicked((MouseEvent event) -> 
     { 
      centers.add(new Point2D(event.getSceneX(), event.getSceneY())); 
      render(); 
      System.out.println("Clicked"); 
     }); 
     VBox pane2 = new VBox(10); 
     pane2.setPrefSize(224, 600); 
     Button button1 = new Button("Clear Last Drawn"); 
     button1.setOnMouseClicked((MouseEvent event) -> 
     { 
      if (!centers.isEmpty()) 
      { 
       centers.removeLast(); 
       render(); 
       System.out.println("Last canvas loaded"); 
      } 
     }); 
     pane2.getChildren().addAll(button1); 
     pane1.setStyle("-fx-background-color: #224488"); 
     pane2.setStyle("-fx-background-color: #224488"); 
     root.getChildren().addAll(pane1, pane2); 
     Scene scene1 = new Scene(root, 1024, 600); 
     primaryStage.setScene(scene1); 
     primaryStage.setTitle("Mouse Clicker Project (Berk YATKIN)"); 
     primaryStage.show(); 

    } 

    private void render() 
    { 
     pane1.getGraphicsContext2D().clearRect(0, 0, pane1.getWidth(), pane1.getHeight()); 
     centers.forEach((p) -> 
     { 
      pane1.getGraphicsContext2D().strokeOval(
        p.getX() - (diameter/2), 
        p.getY() - (diameter/2), 
        diameter, 
        diameter); 
     }); 
    } 
+0

我看到您的實現存儲每個圓圈,每次繪製一個圓時,它將清除整個畫布,然後再次繪製每個圓。我不確定這是否是一個好的解決方案,但至少它能夠正常工作,所以我非常感謝。順便說一下,我鑄造get.SceneX和get.SceneY浮動,因爲Point2D函數期望浮動參數希望它可以做到這一點。同樣在渲染函數中,它應該是「p.x」和「p.y」,而不是「p.getX()」和「p.getY」。再次感謝回覆,這對我來說已經足夠了。 – Vsky

+0

此外,您和我的創建MouseClick事件的方式有什麼區別嗎?我可能也會說IntelliJ的方式,因爲整個onMouseClick事件是自動生成的。 – Vsky

+0

關於Point2D,我使用'javafx.geometry.Point2D',我認爲你使用'com.sun.javafx.geom.Point2D'。 至於聽衆,我使用lamdas(Java 8)而不是匿名類。 [(差異)](http://stackoverflow.com/questions/22637900/java8-lambdas-vs-anonymous-classes)。最後,你應該把這個例子作爲一個概念證明,場景圖可能是一個更好的解決方案,但是畫布應該能夠每秒重繪數十萬個圓圈。 – geh

1

還沒有分析這個問題我想先問你爲什麼堅持用畫布的問題。場景圖更適合這類問題。您可以添加(幾乎)任意數量的圈子,並按您喜歡的順序刪除儘可能多的圈子。有什麼比這更容易?

+0

感謝您的回覆。我沒有堅持任何事情。我沒有這方面的知識,當我第一次搜索Java GUI編程時看到了兩件事:Swing和JavaFX。簡單地看後,我看到JavaFX更新,搖擺老舊,所以想用新的。在JavaFX的文檔中,我還看到它展示瞭如何在畫布上繪製對象,並認爲我可以使用它。沒有看到你提到的「場景圖」。但是如果你可以給我寫一個使用場景圖的話,我會很高興看看你的實現。謝謝。 – Vsky

0

你問它所以這裏是:

import javafx.application.Application; 
import javafx.scene.Scene; 
import javafx.scene.control.Button; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.Pane; 
import javafx.scene.layout.VBox; 
import javafx.scene.paint.Color; 
import javafx.scene.shape.Circle; 
import javafx.stage.Stage; 

public class Main extends Application { 
    @Override 
    public void start(Stage primaryStage) throws Exception{ 
     BorderPane root = new BorderPane(); 

     Pane graphicsPane = new Pane(); 
     root.setCenter(graphicsPane); 

     graphicsPane.setOnMouseClicked(e -> { 
      // Draw circle around x,y 
      Circle circle = new Circle(e.getX(), e.getY(), 50.0); 
      circle.setStroke(Color.RED); 
      circle.setStrokeWidth(4.0); 
      circle.setFill(null); 
      graphicsPane.getChildren().add(circle); 
     }); 

     VBox pane2 = new VBox(10); 
     pane2.setPrefWidth(224); 
     Button button1 = new Button("Clear Last Drawn"); 
     button1.setOnAction(e -> { 
      int numCircles = graphicsPane.getChildren().size(); 
      if (numCircles > 0) { 
       graphicsPane.getChildren().remove(numCircles - 1); 
      } 
     }); 

     pane2.getChildren().addAll(button1); 
     root.setRight(pane2); 
     graphicsPane.setStyle("-fx-background-color: #aaaaaa"); 
     pane2.setStyle("-fx-background-color: #224488"); 
     Scene scene1 = new Scene(root, 1024, 600); 
     primaryStage.setScene(scene1); 
     primaryStage.setTitle("Mouse Clicker"); 
     primaryStage.show(); 

    } 

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

} 

這是直接使用場景圖形解決方案。此示例還可以通過圖形選擇輕鬆擴展以移動圓周或刪除圓。所有用畫布都不容易的東西。

+0

感謝您的代碼。但有沒有辦法來過濾graphicsPane內的節點?因爲這樣它不會擦除最後繪製的圓,而是會擦除最後繪製的對象。那麼有沒有辦法讓graphicPane中只有Circle兒童? – Vsky

+0

當然。你只需遍歷列表並找到最後一個圓。 – mipa

+0

應禁止未經評論的評論。 – mipa