1

I have a javafx TabPane that I want to be able to print. The TabPane has two tabs, and I want each tab to be printed on its own page. I created a button on one of the tabs with the onAction function to run a method called onPrint. The button will print a table within one tab and another table in the other.

The printer.fxml file

<ScrollPane fx:id="assessment"/>
    <Pane fx:id="printPane">
    <TabPane prefHeight="900.0" prefWidth="937.0" tabClosingPolicy="UNAVAILABLE">
        <Tab text="Issues">
                <AnchorPane fx:id="issuesTab" minHeight="0.0" minWidth="0.0" prefHeight="519.0" prefWidth="585.0">
                 <Text text="here is some text" />
                 <Button fx:id="print" layoutX="82.0" layoutY="60.0" mnemonicParsing="false" onAction="#onPrint" text="print" /> 
                </AnchorPane>
        </Tab>
        <Tab text="Function">
                <AnchorPane fx:id="FunctionTab" prefHeight="400.0" prefWidth="600.0">
                     <Text text="here is some text"/>
                </AnchorPane>
        </Tab>
</Pane>
</Scrollpane>

I've tried several different ways to get this to work properly. I'll walk through them below.

The printerController file is as follows:

public ScrollPane assessment; 
public Pane printerPane; 
public AnchorPane issuesTab;
public AnchorPane functionTab;


 public void onPrint(ActionEvent event) {
        printPane.getChildren().addAll(issuesTab, functionTab);
        Printer printer = Printer.getDefaultPrinter();
        PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.HARDWARE_MINIMUM);
        PrinterJob job = PrinterJob.createPrinterJob();
        job.getJobSettings().setPageRanges(new PageRange(1, 2));
        if (job.showPrintDialog(printPane.getScene().getWindow())){
            boolean success = job.printPage(pageLayout, printPane);
            if (success) {
                job.endJob();
            }
        }
    }

Currently this works but it adds both tables ontop of each other. I've tried to use the setPageRanges function to set a page range but I cannot get it to work propertly.

I then thought maybe I need to create a brand new pane for each tab and then add those to a group and it'll print separately.

    private Node toPrint;

    private Node printAllPages(){
        if(toPrint== null){
            Group group = new Group();
            group.getChildren().addAll(
                    new Pane(issuesTab),
                    new Pane(functionTab)
            );
            notToPrint = group;
        }
        return notToPrint;
    }
 public void onPrint(ActionEvent event) {
        PrinterJob job = PrinterJob.createPrinterJob();
        if(job.showPrintDialog(notToPrint.getScene().getWindow())){
            boolean success = job.printPage(printAllPages());
            if(success){
                job.endJob();
            }
        }


    }

However this results in the following error - Caused by: java.lang.NullPointerException: Cannot invoke "javafx.scene.Node.getScene()" because "this.notToPrint" is null. I also don't believe this is the right approach.

Are there any Printer, PageLayout or PrinterJob settings that I need to apply so that each AnchorPane can be printed on separate pages?


Edits made:

Per @SedJ601 advice on how to fix this issue. I went through the link he provided and decided to try this -

PrintController.java

    public TabPane allTabs;
   Printer printer = Printer.getDefaultPrinter();
        PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT);
        PrinterJob job = PrinterJob.createPrinterJob();

        if(job.showPrintDialog(allTabs.getScene().getWindow())){
            double pagePrintableHeight = pageLayout.getPrintableHeight();
            double pagePrintableWidth = pageLayout.getPrintableWidth();
            double scaleX = pagePrintableWidth / allTabs.getBoundsInParent().getWidth();
            double localScale = scaleX;


            double numberOfPages = Math.ceil((allTabs.getPrefWidth()) * localScale) / pagePrintableHeight;
            System.out.println(numberOfPages);

            for(int i = 0; i < numberOfPages; i++){ job.printPage(pageLayout, allTabs.get(i)); } job.endJob();
        }else{
            System.out.println("This did not work");
        }

Print.fxml

<ScrollPane fx:id="assessment">
<TabPane fx:id="allTabs" prefHeight="900.0" prefWidth="937.0" tabClosingPolicy="UNAVAILABLE">
    <Tab text="Issues">
        <content>
            <AnchorPane fx:id="issuesTab" minHeight="0.0" minWidth="0.0" prefHeight="519.0" prefWidth="585.0">
             <Text text="some text" />
            </AnchorPane>
        </content>
    </Tab>
    <Tab text="Function">
        <content>
            <AnchorPane fx:id="functionTab" prefHeight="400.0" prefWidth="600.0">
               <Text text="some text" />
            </AnchorPane>
        </content>
    </Tab>
</TabPane>

However this is printing only the first tab. I tried setting the numberOfPages value equal to 10.0 and still only the first tab prints. How do I edit either the for loop to loop through both tabs or change the numberOfPages to accurately find all pages?

11
  • I would follow the strategy to add AnchorPanes for each tab content, then you can you can use PrinterJob class to print each node separately
    – vmicrobio
    Commented Apr 17 at 14:16
  • 1
    Check your spelling printerPane vs printPane.
    – SedJ601
    Commented Apr 17 at 14:32
  • If you want to print the AnchorPanes on two different pages, print the AnchorPanes individually and not the Print(er)Pane
    – SedJ601
    Commented Apr 17 at 14:34
  • 1
    Yeah, that means you want to print them individually. Do something like this -> for(int i = 0; i < numberOfPages; i++) { job.printPage(pageLayout, tblvMain); } Where you loop through the AnchorPanes.
    – SedJ601
    Commented Apr 17 at 14:53
  • 2
    When replying to comments, especially if you are writing code in comments, it is often better to edit the question and put the replies and the code (with appropriate formatting) in the question. You can quote somebody else's comment when doing that if context is needed. It is just really hard to understand the current state of the question when everything is back and forth in comments and the code in comments is unformatted snippets.
    – jewelsea
    Commented Apr 17 at 19:44

1 Answer 1

1

If you are going to only have two Tabs then I think the following code should work.

public void onPrint(ActionEvent event) {
        printPane.getChildren().addAll(issuesTab, functionTab);
        Printer printer = Printer.getDefaultPrinter();
        PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.HARDWARE_MINIMUM);
        PrinterJob job = PrinterJob.createPrinterJob();
        job.getJobSettings().setPageRanges(new PageRange(1, 2));
        if (job.showPrintDialog(printPane.getScene().getWindow())){
            //if the number of tabs is variable use a loop and print each tab.
            boolean success = job.printPage(pageLayout, issuesTab);
            boolean successTwo = job.printPage(pageLayout, functionTab);
            if (success && successTwo) {
                job.endJob();
            }
            else{
                System.out.println("Printing Error!");
           }
        }
    }

I typed the above code in here without testing it. It may have errors.

Here is a MCVE.

//Original code from https://jenkov.com/tutorials/javafx/tabpane.html
import javafx.application.Application;
import javafx.collections.ObservableList;
import javafx.print.PageLayout;
import javafx.print.PageOrientation;
import javafx.print.Paper;
import javafx.print.Printer;
import javafx.print.PrinterJob;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TabPane;
import javafx.scene.control.Tab;
import javafx.scene.control.Label;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

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

    @Override
    public void start(Stage primaryStage) {       
        TabPane tabPane = new TabPane();
        VBox.setVgrow(tabPane, Priority.ALWAYS);
        
        StackPane stackPane1 = new StackPane(new Label("This is tab 1"));
        StackPane stackPane2 = new StackPane(new Label("This is tab 2"));
        StackPane stackPane3 = new StackPane(new Label("This is tab 3"));

        Tab tab1 = new Tab("Tab 1", stackPane1);
        Tab tab2 = new Tab("Tab 2"  , stackPane2);
        Tab tab3 = new Tab("Tab 3" , stackPane3);

        tabPane.getTabs().add(tab1);
        tabPane.getTabs().add(tab2);
        tabPane.getTabs().add(tab3);
        
        VBox root = new VBox(tabPane);
        Scene scene = new Scene(root, 500, 500);
        
        Button button = new Button("Print Nodes");
        button.setOnAction(actionEvent -> {
            printNodes(tabPane.getTabs(), scene);
        });        
        root.getChildren().add(button);
        
        primaryStage.setScene(scene);
        primaryStage.setTitle("JavaFX App");

        primaryStage.show();
    }
    
    
    public void printNodes(ObservableList<Tab> nodesFromSameScene, Scene scene)
    {
        boolean control = true;
        
        Printer printer = Printer.getDefaultPrinter();
        PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.HARDWARE_MINIMUM);
        PrinterJob job = PrinterJob.createPrinterJob();
        
        if (job.showPrintDialog(scene.getWindow()))
        {
            for(int i = 0; i < nodesFromSameScene.size(); i++)
            {
                if(!job.printPage(pageLayout, nodesFromSameScene.get(i).getContent()))
                {
                    control = false;
                    break;
                }            
            }

            if(control)
            {
                job.endJob();
            }
            else
            {
                System.out.println("Printing Error!");
            }
        }        
    }
}

Output - Saved as PDF instead of printing!

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.