B4J Library B4j Print JavaFX8

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:
B4X:
    Dim P As Printer = Printer_Static.GetDefaultPrinter
    Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob2(P)
    PJ.PrintPage(lblTest)
    PJ.EndJob

Or with dialogs:

B4X:
    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.
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

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

Reset node size after scaling:
'where N would be MainForm.Rootpane in the above example
N.As(JavaObject).Runmethod("getTransforms",Null).as(List).Clear

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.

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

Attachments

  • jFX8Print.b4xlib
    11.1 KB · Views: 642
  • Printer.zip
    14.2 KB · Views: 354
Last edited:

stevel05

Expert
Licensed User
Longtime User
OK while you're working on it, just a hint. The node you print does not have to be on a layout. You can create a second webview of a different size or with a different css file attached, which is not attached to the Rootnode of a form to load the page and print it. I tend to do this for all nodes as it does not display any changes required and the user doesn't see a 'jumpy' image.
 

afields

Member
Licensed User
hello to all! well i'm back. i had use
B4X:
Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob
    PJ.ShowPageSetupDialog(Null)
    PJ.ShowPrintDialog(Null)
    Dim WVJO As JavaObject = WebView1
    WVJO.RunMethodJO("getEngine",Null).RunMethod("print",Array(PJ.GetObject))
    PJ.EndJob

with the zebra's printer and with the html code that i've pointed early i've got a card printed at both sides.
However ( there's always a however..) i've got no bakground image because the print method is in default mode that is with no backgroud printing. i think that with webkitPrintColorAdjust it's possible to have it but how?
thank you!
 

AndrewF

Member
Licensed User
Longtime User
I am using this library to print text on my form in a label control on a receipt printer. The printer is going thru the motions of printing, and makes a line feed but no text is printed on the page. I have also tried with a text box (same result) and printing the form which shows a black line on the paper. Why can't I see the results of the label? The printer is working ok. The job is processed by windows.

B4X:
Dim P As Printer = GetPrinter("HPRT MPT-II")
    If P <> Null And P.IsInitialized Then
        Dim PJ As PrinterJob = PrinterJob_Static.CreatePrinterJob2(P)
        LblRct.TextColor=fx.Colors.Black
                PJ.PrintPage(LblRct)
        PJ.EndJob
    Else
        Log("Printer not found")
    End If
 

stevel05

Expert
Licensed User
Longtime User
Possibly because you are changing the text colour just before you are printing it. Try putting a Sleep statement in between setting the colour and printing the page. Try some different values to see if a longer sleep helps.
 

afields

Member
Licensed User
hello again!
i had not attached webkitPrintColorAdjust to the webview with style property because i think that it cannot be attached in that way.
So i had used it directy in the html document. Using webkitPrintColorAdjust directly in the body tag, i was able to print some background in the back but not in the front card!
Why? i've searched and had came to the conclusion that the webkitPrintColorAdjust does not work inside the tag body!
So i've created a style element and then used it after the body tag.in a div.. Now i'm able to have background printed in front and back of the card.
I would like to say that i've see that that situation is comum and that there aparently other solutions to use like those that i've seen in maxlapides.com/forcing-browsers-print-backgrounds/
thank you all
 

Peter Simpson

Expert
Licensed User
Longtime User
Good morning Steve,
This is an excellent library, but.

I downloaded your library and example, when I run your example project and something strange happens, the word 'Test' get stretched vertically. I've attached 2 screenshots and a PDF file of your own example.

Before (Not stretched):
Before.png


After (Stretched):
After.png


Please see the attached PDF printout, this is your own example without any changes whatsoever to it, I just downloaded and ran your example.


Thank you...
 

Attachments

  • JavaFX Print Job.pdf
    8.5 KB · Views: 511

stevel05

Expert
Licensed User
Longtime User
The demo has a scaledoutput utility applied to the print job, try removing it and it should print as expected.

Change PJ.PrintPage(ScaleOutput(PJ.GetPrinter,MainForm.RootPane)) to PJ.PrintPage(MainForm.RootPane)
 

Peter Simpson

Expert
Licensed User
Longtime User
Change PJ.PrintPage(ScaleOutput(PJ.GetPrinter,MainForm.RootPane)) to PJ.PrintPage(MainForm.RootPane)

Worked perfect 5/5.
I did try looking in this thread for the answer but I didn't find anything about it (or most probably I missed it).

This library must have taken you a long time to wrap. I'm just messing about with form size to get A4 paper size, then I'll create a project to see how it performs printing about 100 invoices (via PDF so not to waste paper).

Thank you again.

Peter...
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
Your welcome

I don't know if you found it, but you can get the printers reported page size and margins once you have run ShowPageSetupDialog, if it helps.

B4X:
mPJ = PrinterJob_Static.CreatePrinterJob
    mPJ.ShowPageSetupDialog(Null)
    Dim JS As JobSettings = mPJ.GetJobSettings
    Dim PL As PageLayout = JS.GetPageLayout
    Dim Width As Int = PL.GetPrintableWidth
    Dim Height As Int = PL.GetPrintableHeight
    Dim TM as INt = PL.GetTopMargin 
    Dim BM as Int = PL.GetBottomMargin


via PDF so not to waste paper

Yes thanks goodness for PDF printer drivers :)
 

Peter Simpson

Expert
Licensed User
Longtime User
Hello @stevel05,
I was just wondering if it is at all possible to send the document name to the printer? f
For example when printing to PDF files so that the PDF document is automatically saved/named as the document name you chose in the B4J application, also when sending to printers too.

Thank you...
 

stevel05

Expert
Licensed User
Longtime User
Hi Peter, No I haven't found a way to do that, it is not an API option. The Foxit PDF print driver incorporates some management over the filename I guess others might as well. For my own use, if I know what I want the filename to be, I put it on the clipboard before calling the print job, not ideal for users though.
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
I put it on the clipboard before calling the print job

I guess you could use the Robot library to paste it, useful if you are already using the Robot library in the app but it may not be worth if for just that function though.
 

Peter Simpson

Expert
Licensed User
Longtime User
Hi Peter, No I haven't found a way to do that, it is not an API option.
I thought that might have been the case Steve.
I looked through everything that I could find in your library and couldn't find anything about it, so I just thought that I would ask just in case I missed something obvious.

I guess you could use the Robot library
???

Thanks for the rapid response Steve, excellent support as usual.

Peter...
 

Star-Dust

Expert
Licensed User
Longtime User
I have a large panel to print on multiple A4 pages.
It's a long list of accounting movements and it does not usually come in just one A4 page.

Is it possible to divide the print into multiple pages?
Do I have to divide everything into more panels and launch more prints?

Thanks for your help
 

afields

Member
Licensed User
helo!
you do not need to have multiple panels, you even do nto need to hava a panel.
you must have a webview where you are going to put a html file of what you want to write.
In that html, that you must control when to jump tp another page ( if you want to have in all pages the same header ) and also use must probably the webkit to have a new page but note that this is all in the html document and nothing in b4j nor with that library!
if you want i can send to you my case which is a card printing in the front and back (that are quite equal to your problem!
 

Star-Dust

Expert
Licensed User
Longtime User
I know this solution that you propose to me.
But I have to print a set of data that appears in a panel that is contained in a scrollview.
After viewing the data, the user can print them as he sees them.
Putting a webwiew means rewriting my code to publish the data in a webwiew. I would like to avoid it
 

stevel05

Expert
Licensed User
Longtime User
The Java8 API will print what is currently showing the pane, if you can display each page then you can print them too.
 
Top