我的应用程序使用画布绘制图表,放置在多个选项卡窗格中。在宽屏显示器上,创建超过 10 个选项卡后,出现如下异常。 我认为这是来自 Canvas 的高视频内存使用率。
我的问题是,是否有任何方法可以释放 Canvas 内存使用量。我会为选项卡窗格中未选择的选项卡中的画布触发此操作。 我试着做 canvas.setSize(0,0),但这似乎并不总是有效。如果这适用于 canvas.setDisable(true) 就好了。
在高分辨率监视器上重现的代码。将标签数量减少到 5,一切正常。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class CanvasIssue extends Application {
private final StackPane root = new StackPane();
private final Scene scene = new Scene(root, 300, 250);
@Override
public void start(Stage stage) {
stage.setTitle("Sample Canvas");
TabPane tabPane = new TabPane();
for ( int i = 0; i < 30; i++) {
tabPane.getTabs().add(new Tab("Tab " + tabPane.getTabs().size(), setupCanvasPane()));
}
root.getChildren().add(tabPane);
stage.setScene(scene);
stage.sizeToScene();
setupCanvasPane();
stage.show();
}
private Pane setupCanvasPane(){
final BorderPane pane = new BorderPane();
final Canvas canvas = new Canvas(){
@Override
public boolean isResizable() {
return true;
}
@Override
public double prefWidth(double height) {
return getWidth();
}
@Override
public double prefHeight(double width) {
return getHeight();
}
};
pane.setCenter( canvas );
canvas.widthProperty().bind(pane.widthProperty());
canvas.heightProperty().bind(pane.heightProperty());
pane.widthProperty().addListener((o,p,c)-> paint(canvas));
paint( canvas );
return pane;
}
public void paint( Canvas canvas ){
GraphicsContext gr = canvas.getGraphicsContext2D();
gr.clearRect( 0,0, canvas.getWidth(), canvas.getHeight() );
gr.setFill( Color.web("#ffffff") );
gr.fillRect( 0,0,canvas.getWidth(), canvas.getHeight());
gr.setFont( Font.font( "Monospaced"));
gr.setFill( Color.BLACK );
gr.fillText("This is a", 50, 70 );
gr.setFill( Color.RED );
gr.fillText("demo", 50, 88 );
}
public static void main(String[] args) {
launch(args);
}
}
我通过更多选项卡获得的异常:
java.lang.NullPointerException: Cannot invoke "com.sun.prism.RTTexture.createGraphics()" because "<local9>" is null
at com.sun.javafx.sg.prism.NGCanvas$RenderBuf.validate(NGCanvas.java:214)
at com.sun.javafx.sg.prism.NGCanvas.initCanvas(NGCanvas.java:644)
at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:607)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.renderForClip(NGNode.java:2313)
at com.sun.javafx.sg.prism.NGNode.renderRectClip(NGNode.java:2207)
at com.sun.javafx.sg.prism.NGNode.renderClip(NGNode.java:2233)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2066)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.sg.prism.NGGroup.renderContent(NGGroup.java:270)
at com.sun.javafx.sg.prism.NGRegion.renderContent(NGRegion.java:579)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2072)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1964)
at com.sun.javafx.tk.quantum.ViewPainter.doPaint(ViewPainter.java:480)
at com.sun.javafx.tk.quantum.ViewPainter.paintImpl(ViewPainter.java:321)
at com.sun.javafx.tk.quantum.PresentingPainter.run(PresentingPainter.java:92)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305)
at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:126)
at java.base/java.lang.Thread.run(Thread.java:832)
我会尝试做的是虚拟化选项卡,以便仅当此选项卡成为选定选项卡时才分配画布,并在选择另一个选项卡时从场景图中删除画布。所以一次只存在一个可能的大画布。