2015-08-01 15 views
10

Gần đây tôi đã muốn tạo một nền động trong JavaFX, tương tự như ví dụ Swing được xem here. Tôi đã sử dụng Canvas để vẽ, như được hiển thị trong Working with the Canvas APIAnimationTimer cho vòng vẽ, như được hiển thị trong Animation Basics. Thật không may, tôi không chắc chắn làm thế nào để thay đổi kích thước các Canvas tự động như là kèm theo Stage được thay đổi kích cỡ. Cách tiếp cận tốt là gì?Tự động thay đổi kích cỡ Canvas để điền vào các phụ huynh kèm theo

image

Trả lời

9

Trong ví dụ dưới đây, các tĩnh lồng lớp CanvasPane kết thúc tốt đẹp một thể hiện của Canvas trong một Pane và ghi đè layoutChildren() để làm cho kích thước vải phù hợp với kèm theo Pane. Lưu ý rằng Canvas trả về false từ isResizable(), vì vậy "cha mẹ không thể thay đổi kích thước trong bố cục" và Pane "không thực hiện bố cục ngoài việc định lại kích thước các trẻ có thể thay đổi thành kích thước ưa thích của chúng". widthheight được sử dụng để xây dựng canvas trở thành kích thước ban đầu của nó. Cách tiếp cận tương tự được sử dụng trong mô phỏng hạt Ensemble, Fireworks.java, để chia tỷ lệ hình nền trong khi vẫn giữ tỷ lệ khung hình.

Là một sang một bên, hãy lưu ý sự khác biệt khi sử dụng các màu bão hòa hoàn toàn so với bản gốc. Các liên quan examples này minh họa cách đặt điều khiển trên nền hoạt ảnh.

image

import java.util.LinkedList; 
import java.util.Queue; 
import java.util.Random; 
import javafx.animation.AnimationTimer; 
import javafx.application.Application; 
import javafx.beans.Observable; 
import javafx.scene.Scene; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.CheckBox; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.Pane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

/** 
* @see https://stackoverflow.com/a/31761362/230513 
* @see https://stackoverflow.com/a/8616169/230513 
*/ 

public class Baubles extends Application { 

    private static final int MAX = 64; 
    private static final double WIDTH = 640; 
    private static final double HEIGHT = 480; 
    private static final Random RND = new Random(); 
    private final Queue<Bauble> queue = new LinkedList<>(); 
    private Canvas canvas; 

    @Override 
    public void start(Stage stage) { 
     CanvasPane canvasPane = new CanvasPane(WIDTH, HEIGHT); 
     canvas = canvasPane.getCanvas(); 
     BorderPane root = new BorderPane(canvasPane); 
     CheckBox cb = new CheckBox("Animate"); 
     cb.setSelected(true); 
     root.setBottom(cb); 
     Scene scene = new Scene(root); 
     stage.setScene(scene); 
     stage.show(); 

     for (int i = 0; i < MAX; i++) { 
      queue.add(randomBauble()); 
     } 
     AnimationTimer loop = new AnimationTimer() { 
      @Override 
      public void handle(long now) { 
       GraphicsContext g = canvas.getGraphicsContext2D(); 
       g.setFill(Color.BLACK); 
       g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); 
       for (Bauble b : queue) { 
        g.setFill(b.c); 
        g.fillOval(b.x, b.y, b.d, b.d); 
       } 
       queue.add(randomBauble()); 
       queue.remove(); 
      } 
     }; 
     loop.start(); 
     cb.selectedProperty().addListener((Observable o) -> { 
      if (cb.isSelected()) { 
       loop.start(); 
      } else { 
       loop.stop(); 
      } 
     }); 
    } 

    private static class Bauble { 

     private final double x, y, d; 
     private final Color c; 

     public Bauble(double x, double y, double r, Color c) { 
      this.x = x - r; 
      this.y = y - r; 
      this.d = 2 * r; 
      this.c = c; 
     } 
    } 

    private Bauble randomBauble() { 
     double x = RND.nextDouble() * canvas.getWidth(); 
     double y = RND.nextDouble() * canvas.getHeight(); 
     double r = RND.nextDouble() * MAX + MAX/2; 
     Color c = Color.hsb(RND.nextDouble() * 360, 1, 1, 0.75); 
     return new Bauble(x, y, r, c); 
    } 

    private static class CanvasPane extends Pane { 

     private final Canvas canvas; 

     public CanvasPane(double width, double height) { 
      canvas = new Canvas(width, height); 
      getChildren().add(canvas); 
     } 

     public Canvas getCanvas() { 
      return canvas; 
     } 

     @Override 
     protected void layoutChildren() { 
      super.layoutChildren(); 
      final double x = snappedLeftInset(); 
      final double y = snappedTopInset(); 
      final double w = snapSize(getWidth()) - x - snappedRightInset(); 
      final double h = snapSize(getHeight()) - y - snappedBottomInset(); 
      canvas.setLayoutX(x); 
      canvas.setLayoutY(y); 
      canvas.setWidth(w); 
      canvas.setHeight(h); 
     } 
    } 

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

Bản trình diễn hay .. + 1 .. – Reimeus

2

Không thể bạn làm điều này với một Binding không? Sau đây dường như để sản xuất các kết quả tương tự mà không cần phải thêm lớp dẫn xuất.

import java.util.LinkedList; 
import java.util.Queue; 
import java.util.Random; 
import javafx.animation.AnimationTimer; 
import javafx.application.Application; 
import javafx.beans.Observable; 
import javafx.beans.binding.DoubleBinding; 
import javafx.scene.Scene; 
import javafx.scene.canvas.Canvas; 
import javafx.scene.canvas.GraphicsContext; 
import javafx.scene.control.CheckBox; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.paint.Color; 
import javafx.stage.Stage; 

/** 
* @see http://stackoverflow.com/a/31761362/230513 
* @see http://stackoverflow.com/a/8616169/230513 
*/ 

public class Baubles extends Application { 

private static final int MAX = 64; 
private static final double WIDTH = 640; 
private static final double HEIGHT = 480; 
private static final Random RND = new Random(); 
private final Queue<Bauble> queue = new LinkedList<>(); 
private Canvas canvas; 

@Override 
public void start(Stage stage) { 
    canvas = new Canvas(WIDTH, HEIGHT); 
    BorderPane root = new BorderPane(canvas); 
    CheckBox cb = new CheckBox("Animate"); 
    cb.setSelected(true); 
    root.setBottom(cb); 
    Scene scene = new Scene(root); 
    stage.setScene(scene); 
    stage.show(); 

    // Create bindings for resizing. 
    DoubleBinding heightBinding = root.heightProperty() 
      .subtract(root.bottomProperty().getValue().getBoundsInParent().getHeight()); 
    canvas.widthProperty().bind(root.widthProperty()); 
    canvas.heightProperty().bind(heightBinding); 

    for (int i = 0; i < MAX; i++) { 
     queue.add(randomBauble()); 
    } 
    AnimationTimer loop = new AnimationTimer() { 
     @Override 
     public void handle(long now) { 
      GraphicsContext g = canvas.getGraphicsContext2D(); 
      g.setFill(Color.BLACK); 
      g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); 
      for (Bauble b : queue) { 
       g.setFill(b.c); 
       g.fillOval(b.x, b.y, b.d, b.d); 
      } 
      queue.add(randomBauble()); 
      queue.remove(); 
     } 
    }; 
    loop.start(); 
    cb.selectedProperty().addListener((Observable o) -> { 
     if (cb.isSelected()) { 
      loop.start(); 
     } else { 
      loop.stop(); 
     } 
    }); 
} 

private static class Bauble { 

    private final double x, y, d; 
    private final Color c; 

    public Bauble(double x, double y, double r, Color c) { 
     this.x = x - r; 
     this.y = y - r; 
     this.d = 2 * r; 
     this.c = c; 
    } 
} 

private Bauble randomBauble() { 
    double x = RND.nextDouble() * canvas.getWidth(); 
    double y = RND.nextDouble() * canvas.getHeight(); 
    double r = RND.nextDouble() * MAX + MAX/2; 
    Color c = Color.hsb(RND.nextDouble() * 360, 1, 1, 0.75); 
    return new Bauble(x, y, r, c); 
} 

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

Cảm ơn bạn đã đề xuất 'Ràng buộc'. Tôi có đúng để suy ra rằng ràng buộc sẽ phải thay đổi cho một bố cục 'root' khác không? Tôi chỉ kiểm tra 'CanvasPane' trong' BorderPane' và 'StackPane'. – trashgod

+0

Các chi tiết sẽ cần phải thay đổi, nhưng một cái gì đó tương tự nên làm việc. Ngoài ra, ví dụ này không hoàn toàn chung cho một 'BorderPane' vì một số chi tiết sẽ cần thay đổi nếu bạn có các nút ở vị trí trên cùng, bên trái hoặc bên phải. – clartaq

+0

Ah, tôi hiểu; trong một 'StackPane', tôi có thể' bind() '' canvas.heightProperty() 'trực tiếp vào' root.heightProperty() '. Cho đến nay tôi nghĩ rằng 'CanvasPane' là linh hoạt hơn, nhưng cộng với một cho một sự thay thế hữu ích và một ví dụ cụ thể về số học 'Binding'. – trashgod

Các vấn đề liên quan