JavaFX TableView parent column label not showing

I am having a problem getting a JavaFX TableView snapshot. I want to create a table image file without showing the scene. Everything works fine, except that the parent column labels disappear when the stage is not displayed.

I have a regular table with a sample Person (name, age, email -> (primary, secondary)):

TableView<Person> personTable = new TableView<>();

TableColumn<Person, String> nameColumn = new TableColumn<>( "Name" );
TableColumn<Person, Integer> ageColumn = new TableColumn<>( "Age" );

TableColumn<Person, String> emailColumn = new TableColumn<>( "Email" );
TableColumn<Person, String> primaryEmailColumn = new TableColumn<>( "Primary" );
TableColumn<Person, String> secondaryEmailColumn = new TableColumn<>( "Secondary" );

nameColumn.setCellValueFactory( cellDataFeatures -> cellDataFeatures.getValue().nameProperty() );
ageColumn.setCellValueFactory( cellDataFeatures -> cellDataFeatures.getValue().ageProperty().asObject() );
primaryEmailColumn.setCellValueFactory( cellDataFeatures -> cellDataFeatures.getValue().primaryEmailProperty() );
secondaryEmailColumn.setCellValueFactory( cellDataFeatures -> cellDataFeatures.getValue().secondaryEmailProperty() );

emailColumn.getColumns().addAll( primaryEmailColumn, secondaryEmailColumn );
personTable.getColumns().addAll( nameColumn, ageColumn, emailColumn );

personTable.setItems( generatePersonList() );

      

Creating an image file:

Scene scene = new Scene( personTable );
saveAsPng( personTable, "test2.png" );

      

Generated Image (1)

As you can see, the email column label (Email) is not displayed.

I can hack this by showing the scene, capturing the image and hiding the scene:

Scene scene = new Scene( personTable );
stage.setScene( scene );
stage.show();
saveAsPng( personTable, "test2.png" );
stage.close();

      

Generated Image (2)

My goal is to create a second image (labeled "Email") without showing the scene.

I assumed that only the columns that have values ​​associated with them have the graphics shown, so I tried the following to no avail:

emailColumn.setGraphic( new Label( "Test" ) );
emailColumn.setVisible( true );
emailColumn.getGraphic().setVisible( true );

      

saveAsPNG:

private void saveAsPng(Parent container, String path)
{
    File file = new File(path);
    WritableImage img = container.snapshot( null, null );
    RenderedImage renderedImage = SwingFXUtils.fromFXImage(img, null);
    try {
        ImageIO.write(renderedImage,"png", file);
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

      

Thank!

+3


source to share


1 answer


Whenever you do operations with Scene

that are not added in Stage

, you are missing the JavaFX layout computations (using CSS and layout) that occur as part of the momentum when a normal scene is shown.

In your case, since the scene is not showing, you need to actually force the layout manually by running the CSS and layout app before taking the shot.

You can easily do this by calling node.applyCss()

and node.layout

, according to the JavaFX JavaDoc:

public final void applyCss ()

Apply styles to this Node and its children, if any, as needed. This method usually does not need to be called directly, but can be used in conjunction with Parent.layout () to size a Node before the next pulse, or if the scene is not on the stage.

Provided that the Node script is non-zero, the CSS is applied to that Node regardless of whether or not that Node CSS state is pure. CSS styles are applied from the topmost parent of this Node, which has a non-pure CSS state that may affect the styling of other nodes. This method is no-op if the Node is not in the Stage. The stage should not be on stage.

This method does not call the Parent.layout () method. Typically, the caller will use the following sequence of operations.

parentNode.applyCss();
parentNode.layout();

      



In your case, this will work:

Scene scene = new Scene( personTable );
personTable.applyCss();
personTable.layout();
saveAsPng( personTable, "test2.png" );

      

Note that if you don't size the scene or table, the layout will use its pref size, so it should be convenient to provide the pref width for each of the columns before (you may already be doing it).

+1


source







All Articles