B4J Library B4j Print JavaFX8 + 17

Here is a B4j library written in B4j to access the full Printer modules provided with JavaFX8. Full source code is available.

At it's simplest, you can print a node using:
Code:
    Dim P As Printer = Printer_Static.GetDefaultPrinter
    Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob2(P)
    PJ.PrintPage(lblTest)
    PJ.EndJob

Or with dialogs:

Code:
    Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob
    PJ.ShowPageSetupDialog(Null)
    PJ.ShowPrintDialog(Null)
    PJ.PrintPage(MainForm.RootPane)
    PJ.EndJob

Code to scale a view to print on a single page.
[CODE lang="b4x" title="Scale output"]Sub ScaleOutput(P As Printer,N As Node) As Node
Dim PL As PageLayout = P.GetDefaultPageLayout
Dim ScaleX,ScaleY As Double
Dim NJO As JavaObject = N
Dim JO As JavaObject = N
ScaleX = PL.GetPrintableWidth / JO.RunMethodJO("getBoundsInParent",Null).RunMethod("getWidth",Null)
ScaleY = PL.GetPrintableHeight / JO.RunMethodJO("getBoundsInParent",Null).RunMethod("getHeight",Null)
Dim SJO As JavaObject
SJO.InitializeNewInstance("javafx.scene.transform.Scale",Array(ScaleX,ScaleY))
NJO.RunMethodJO("getTransforms",Null).RunMethod("add",Array(SJO))
Return NJO
End Sub
[/CODE]

[CODE lang="b4x" title="Usage"] 'Print with dialogs
Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob
If PJ.ShowPageSetupDialog(Null) Then
If PJ.ShowPrintDialog(Null) Then
' PJ.PrintPage(MainForm.RootPane)
PJ.PrintPage(ScaleOutput(PJ.GetPrinter,MainForm.RootPane))
PJ.EndJob
Else
PJ.CancelJob
End If
Else
PJ.CancelJob
End If

'Removes transforms added by ScaleOutput
MainForm.RootPane.As(JavaObject).Runmethod("getTransforms",Null).as(List).Clear
[/CODE]

[CODE lang="b4x" title="Reset node size after scaling"]
'where N would be MainForm.Rootpane in the above example
N.As(JavaObject).Runmethod("getTransforms",Null).as(List).Clear[/CODE]

Depends on: JavaFX8, JavaObject

Documentation (apart from that in the library) is available here: http://docs.oracle.com/javase/8/javafx/api/index.html?javafx/print/Printer.html
Click on javafx.print in the All Classes Packages frame to see all the relevant classes.

I've ignored Enums where strings are acceptable for simplicity's sake.

V0.6 fix improperly formed XMLmessage displayed in IDE help (post #6)
V0.7 added #RaisesSynchronousEvents to PrinterJob module as described here : https://www.b4x.com/android/forum/t...ble-getting-jfx8print-dialogs-to-work.133964/
V 0.8 Released as a B4xLib Enums now return string values instead of ENum objects.
V0.9
  • Added JobSettings.SetOutputPath (Javafx 17+)
  • GetPrinterByName to Printer_Static
  • SearchPrinters to Printer_Static
  • Added MaintainAspectRatio to the ScaleOutput example method


Full code is in Printer.zip if you just want to look at the project without unzipping the B4xlib
Enjoy

Update V0.9

JavaFX17
adds SetOutputFile to JobSettings, which means you can now print to PDF without dialogs while setting the target filepath. Something like this:

[CODE lang="b4x" title="JavafX 17+"] Dim P As Printer = Printer_Static.GetPrinterByName("Microsoft Print to PDF")
If Initialized(P) Then
Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob2(P)
PJ.GetJobSettings.SetOutputFile("D:\Test.pdf")
PJ.PrintPage(ScaleOutput(P,MainForm.RootPane, True))
PJ.PrintPage(lblTest)
PJ.EndJob
Else
Log("Printer Not found")
End If

'Removes transforms added by ScaleOutput
MainForm.RootPane.As(JavaObject).Runmethod("getTransforms",Null).as(List).Clear
[/CODE]

This is intended to work with print drivers that allow redirecting the print to a file. Tested with Microsoft Print to PDF driver.

You will get an entry in the Logs if you try to use this with JavaFX < 17.

For convenience I have added Printer_Static.GetPrinterByName method as in the example code, and a Printer_Static.SearchPrinters("PDF"). See post #142 for an example.

Also added MaintainAspectRatio to the ScaleOutput Method:

[CODE lang="b4x" title="Scale Output"]Sub ScaleOutput(P As Printer, N As Node, MaintainAspectRatio As Boolean) As Node
Dim PL As PageLayout = P.GetDefaultPageLayout
Dim ScaleX,ScaleY As Double
Dim NJO As JavaObject = N
Dim JO As JavaObject = N
ScaleX = PL.GetPrintableWidth / JO.RunMethodJO("getBoundsInParent",Null).RunMethod("getWidth",Null)
ScaleY = PL.GetPrintableHeight / JO.RunMethodJO("getBoundsInParent",Null).RunMethod("getHeight",Null)
If MaintainAspectRatio Then
ScaleX = Min(ScaleX, ScaleY)
ScaleY = ScaleX
End If
Dim SJO As JavaObject
SJO.InitializeNewInstance("javafx.scene.transform.Scale",Array(ScaleX,ScaleY))
NJO.RunMethodJO("getTransforms",Null).RunMethod("add",Array(SJO))
Return NJO
End Sub[/CODE]
 

Attachments

Last edited:
Example of using PrinterStatic.SearchPrinters:

B4X:
'    Search Printer Example

    Dim L As List = Printer_Static.SearchPrinters("PDF")
    

    If L.Size = 0 Then
        Log("Printer Not found")
    Else If L.Size > 1 Then


'        Could offer selection
'        Alternatively you could Select the first printer in the list
'        If you don't care which printer driver is used.

        Log("Multile Printers found")
        
    Else
        Dim P As Printer = L.Get(0)
        If Initialized(P) Then
            Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob2(P)
            PJ.GetJobSettings.SetOutputFile("D:\Test.pdf")
            PJ.PrintPage(ScaleOutput(P,MainForm.RootPane, True))
            PJ.PrintPage(lblTest)
            PJ.EndJob
        Else
            Log("Printer Not found")
        End If
    End If
 
Hmm,

I currently use the following to get all printers.
[CODE lang="b4x" title="What I currently use"]
Dim Printers As List = Printer_Static.GetAllPrinters
For Each P As Printer In Printers
If P.GetName.StartsWith(PrinterName) Then Return P
Next

OR

'Printers
For Each P As Printer In Printer_Static.GetAllPrinters
CmbPrinters.Items.Add(P.GetName)
Next
[/CODE]
I then start printing documents.

I lean heavily on your library for all client projects, so the first thing that I'll do is to test your library and also xCharts if that has an updated.

Okay @stevel05, this is very nice indeed, thank you for the update 👍
Example of using PrinterStatic.SearchPrinters:

B4X:
'    Search Printer Example

    Dim L As List = Printer_Static.SearchPrinters("PDF")
   

    If L.Size = 0 Then
        Log("Printer Not found")
    Else If L.Size > 1 Then


'        Could offer selection
'        Alternatively you could Select the first printer in the list
'        If you don't care which printer driver is used.

        Log("Multile Printers found")
       
    Else
        Dim P As Printer = L.Get(0)
        If Initialized(P) Then
            Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob2(P)
            PJ.GetJobSettings.SetOutputFile("D:\Test.pdf")
            PJ.PrintPage(ScaleOutput(P,MainForm.RootPane, True))
            PJ.PrintPage(lblTest)
            PJ.EndJob
        Else
            Log("Printer Not found")
        End If
    End If

Cheers 🍻
 
Back
Top