My application uses canvases to draw diagrams, placed in multiple tab panes. On wide screen monitors, after creating more than 10 tabs I got exceptions like below. I think this comes from the Canvas high video memory usage.
My question is, if is any way to release the Canvas memory usage. I would trigger this for the canvases in the un-selected tabs in the tab pane. I tried to do canvas.setSize(0,0), but this seems not to work always. It would be great if this would work on canvas.setDisable(true).
Code to reproduce on a monitor with high resolution. Decrease the number of tabs to 5 and everything works fine.
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);
}
}
The exception I get by higher number of tabs:
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)