当前位置: 首页 > 知识库问答 >
问题:

JavaFX-调整简单应用程序大小导致画布清除/重新绘制导致“闪烁”

欧阳何平
2023-03-14

这是我的控制器:

public class PrimaryController {

    public StackPane theRootPane;
    public CanvasPane theCanvasPane;
    int i = 1;

    public void initialize() {
        theCanvasPane  = new CanvasPane(500, 300);
        theRootPane.getChildren().addAll(theCanvasPane);

        Timeline theTimeline =
            new Timeline(new KeyFrame(Duration.millis(50), actionEvent -> UpdateCanvas(i++)));
        theTimeline.setCycleCount(Timeline.INDEFINITE);
        theTimeline.play();
    }

    private void UpdateCanvas(int diameter) {
        theCanvasPane.DrawCircleAtCenterOfCanvas(diameter);
    }

下面是我的CanvasPane类:

public class CanvasPane extends Pane {

private final Canvas theCanvas;
private GraphicsContext theGC;

public CanvasPane(double width, double height) {
    setWidth(width);
    setHeight(height);
    theCanvas = new Canvas(width, height);
    theGC = theCanvas.getGraphicsContext2D();

    getChildren().add(theCanvas);
    theCanvas.widthProperty().bind(this.widthProperty());
    theCanvas.heightProperty().bind(this.heightProperty());
    theCanvas.widthProperty().addListener(observable -> RedrawCanvas());
    theCanvas.heightProperty().addListener(observable -> RedrawCanvas());
}

private void RedrawCanvas() {
    ClearCanvas();
}

private void ClearCanvas() {
    theGC.clearRect(0, 0, theCanvas.widthProperty().doubleValue(),   theCanvas.heightProperty().doubleValue());
}

public void DrawCircleAtCenterOfCanvas(int diameter) {
    double centreX = theCanvas.widthProperty().doubleValue() / 2;
    double centreY = theCanvas.heightProperty().doubleValue() / 2;
    theGC.fillOval(centreX - diameter / 2.0, centreY - diameter / 2.0, diameter, diameter);
}

}

public class App extends Application {

    private static Scene scene;

    @Override
    public void start(Stage stage) throws IOException {
        scene = new Scene(loadFXML("primary"));
        stage.setScene(scene);
        //stage.setResizable(false);
        stage.show();
    }

    private static Parent loadFXML(String fxml) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
        return fxmlLoader.load();
    }

    public static void main(String[] args) {
        launch();
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="theRootPane" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.xxx.PrimaryController" />

共有1个答案

何向荣
2023-03-14

ChangeListener中更新画布可能比在InvalidationListener中更新画布更好,这将导致更少的重绘。无论哪种方式,您都应该:

>

  • 确保在画布大小更改时重新绘制圆圈(使用当前代码,只要画布大小更改,您就会清除画布,但直到下一个关键帧才重新绘制圆圈,因此在这两个关键帧之间会出现一些空白画布):

     public class CanvasPane extends Pane {
    
         private final Canvas theCanvas;
         private GraphicsContext theGC;
    
         private int currentDiameter ;
    
         public CanvasPane(double width, double height) {
             setWidth(width);
             setHeight(height);
             theCanvas = new Canvas(width, height);
             theGC = theCanvas.getGraphicsContext2D();
    
             getChildren().add(theCanvas);
             theCanvas.widthProperty().bind(this.widthProperty());
             theCanvas.heightProperty().bind(this.heightProperty());
             theCanvas.widthProperty().addListener((obs, oldWidth, newWidth) -> redrawCanvas());
             theCanvas.heightProperty().addListener((obs, oldHeight, newHeight) -> redrawCanvas());
         }
    
         public void increaseDiameter() {
             currentDiameter++;
             redrawCanvas();
         }
    
         private void redrawCanvas() {
             clearCanvas();
             drawCircleAtCenterOfCanvas();
         }
    
         private void clearCanvas() {
             theGC.clearRect(0, 0, theCanvas.widthProperty().doubleValue(), theCanvas.heightProperty().doubleValue());
         }
    
         public void drawCircleAtCenterOfCanvas() {
             currentDiameter = currentDiameter ;
             double centreX = theCanvas.widthProperty().doubleValue() / 2;
             double centreY = theCanvas.heightProperty().doubleValue() / 2;
             theGC.fillOval(centreX - currentDiameter / 2.0, centreY - currentDiameter / 2.0, currentDiameter, currentDiameter);
         }
     }
    

    而且

    public class PrimaryController {
    
         @FXML
         private StackPane theRootPane;
         @FXML
         private CanvasPane theCanvasPane;
    
         public void initialize() {
             theCanvasPane  = new CanvasPane(500, 300);
             theRootPane.getChildren().addAll(theCanvasPane);
    
             Timeline theTimeline =
                 new Timeline(new KeyFrame(Duration.millis(50), actionEvent -> updateCanvas()));
             theTimeline.setCycleCount(Timeline.INDEFINITE);
             theTimeline.play();
         }
    
         private void updateCanvas() {
             theCanvasPane.increaseDiameter();
         }
     }
    
     public class PrimaryController {
    
         @FXML
         private StackPane theRootPane;
    
         private Circle circle ;
    
         public void initialize() {
    
             circle = new Circle();
             theRootPane.getChildren().addAll(circle);
    
             Timeline theTimeline =
                 new Timeline(new KeyFrame(Duration.millis(50), actionEvent -> updateCircle()));
             theTimeline.setCycleCount(Timeline.INDEFINITE);
             theTimeline.play();
         }
    
         private void updateCircle() {
             circle.setRadius(circle.getRadius()+0.5);
         }
     }
    

  •  类似资料:
    • 我编写了这段代码,可以在JavaFX画布上绘制。它可以很好地工作,但我不知道如何重新绘制画布(比如在Swing中),以便在新画布上重新开始绘制。这是我的代码,非常感谢你的帮助!马里奥

    • 问题内容: 在放入HashMap期间发生冲突时,是否会调整地图大小或将条目添加到该特定存储桶中的列表中? 问题答案: 当您说“冲突”时,您是指相同的哈希码吗?哈希码用于确定要使用HashMap中的哪个存储桶,并且该存储桶由具有相同哈希码的所有条目的链表组成。然后在返回或引导(获取/放入)之前比较条目的相等性(使用.equals())。 请注意,这是专门用于HashMap的(因为这是您所要求的),而

    • 问题 我有一个大小适中的javaFX窗口,看起来运行良好,直到我调整应用程序中任何窗口的大小。调整后,具有下拉或类似操作的所有组件(即。,,)变得非常慢。 原因 我已经把问题缩小到一个进度条,如果我从场景中删除进度条,我可以随心所欲地调整窗口大小,如果我添加它,那么任何窗口都会调整大小,它们开始变得没有反应大约半秒钟;如果我做了很多调整大小,有时会长达两秒钟。 窗口 窗口视图,以便您可以看到所有组

    • 每次我尝试通过清除控制台按钮清除eclipse中的控制台时,都会导致eclipse意外死亡。

    • 问题内容: 我现在正在编写一个JApplet,每当我调用super.paint()时,该applet都会闪烁。我正在使用双缓冲(先绘制图像,然后渲染该图像),但我认为super.paint()正在清除屏幕或其他东西,打败了我的双缓冲。 我知道我应该使用paintComponents(),但是由于某些原因,当我调用“ currentScreen.Draw(g)”时,它不会显示屏幕的绘制。 谁能帮我这

    • 我目前正在使用画布开发一个JavaFX-Drawing-Application。在GraphicsContext的帮助下,我使用beginPath()和lineTo()方法绘制线条,但我无法找到实现橡皮擦的适当方法。