2017-06-21 4 views
2

Hier ist das Problem:Printing Knoten mit JavaFX

Ich muss derzeit eine a4, Landschaft Seite drucken „Teile“ meiner aktuellen JavaFX Szene enthält.

Die Teile ich habe, sind Teile eines BorderPane zu drucken, muss ich die Links, Mitte und unten Knoten drucken, so dass die gedruckte Seite sollte wie folgt aussehen:

Second A4 Template Image

Das Wichtigste zu Drucken ist der Mittelteil. Es muss so groß wie möglich sein. Grundsätzlich kann der linke Teil maximal 10% der Seitenbreite und der untere 10-15% der Seitenhöhe einnehmen. Das mittlere Element sollte also so gedehnt werden, dass 90% der (druckbaren) Seitenbreite und 85% der (druckbaren) Seitenhöhe erreicht werden.

Ich habe versucht, tatsächlich einige Lösungen ohne Erfolg ... Ich habe einen Druckknopf erstellen, die wie folgt wirkt:

PrinterJob job = PrinterJob.createPrinterJob(); 

BorderPane bpToPrint = new BorderPane(); 
bpToPrint.setLeft(sourceBorderPane.getLeft()); 
bpToPrint.setCenter(sourceBorderPane.getCenter()); 
bpToPrint.setBottom(sourceBorderPane.getBottom()); 

if(job != null && job.showPrintDialog(root.getScene().getWindow())){ 
    Printer printer = job.getPrinter(); 
    PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, Printer.MarginType.HARDWARE_MINIMUM); 

    double scaleX = pageLayout.getPrintableWidth()/bpToPrint.getWidth(); 
    double scaleY = pageLayout.getPrintableHeight()/bpToPrint.getHeight(); 

    Scale scale = new Scale(scaleX, scaleY); 

    bpToPrint.getTransforms().add(scale); 

    boolean success = job.printPage(pageLayout, bpToPrint); 
    if(success){ 
     job.endJob(); 
    } 
} 

// Since I did "move" the nodes to the "bpToPrint" borderpane 
// I have to put them back to the "source" 

sourceBorderPane.setBottom(bpToPrint.getBottom()); 
sourceBorderPane.setLeft(bpToPrint.getLeft()); 
sourceBorderPane.setCenter(bpToPrint.getCenter()); 

Als ich dieses Stück Code versuchen, erhält der Drucker einen Auftrag, „druckt“ eine Seite ... Eine leere Seite! Nichts, was auf sie gedruckt ...

Wenn ich die „Waage“ Teil zu entfernen, ich habe etwas, das auf der Seite druckt, aber es macht nicht an die Seitengröße auf allen ...

Ich habe auch versuchen, die Knoten zu „Snapshot“, so kann ich ihre Attribute (Breite, Höhe) überprüfen, aber fanden keine Möglichkeit, „sie verketten“ und das Ergebnis drucken ...

// WritableImage myLeft = bPane.getLeft().snapshot(null,null); 
// System.out.println("left item width : "+myLeft.getWidth()+" height : "+myLeft.getHeight()); 
// WritableImage myCenter = bPane.getCenter().snapshot(null,null); 
// System.out.println("center item width : "+myCenter.getWidth()+" height : "+myCenter.getHeight()); 
// WritableImage myBottom = bPane.getBottom().snapshot(null,null); 
// System.out.println("Bottom item width : "+myBottom.getWidth()+" height : "+myBottom.getHeight()); 

ich diese bekommen als Ausgangs (nur zur Information):

left item width : 112.0 height : 892.0 
center item width : 1746.0 height : 892.0 
bottom item width : 1858.0 height : 95.0 

Danke für Hilfe/Lesen, jede Hilfe wirklich geschätzt.

01 Update:

Hier ist der "aktualisierte Code":

PrinterJob job = PrinterJob.createPrinterJob(); 
Node myLeft = root.getLeft(); 
Node myCenter = root.getCenter(); 
Node myBottom = root.getBottom(); 

//I will use a HBox to put the left & center, and a VBox to put hbox + bottom 
VBox vToPrint = new VBox(); 
HBox hToPrint = new HBox(); 

hToPrint.getChildren().addAll(myLeft, myCenter); 
vToPrint.getChildren().addAll(hToPrint,myBottom); 

//Next lines come from the applyCss example    
Group tempRoot = new Group(); 
Scene tempScene = new Scene(tempRoot); 
tempRoot.getChildren().add(vToPrint); 

tempRoot.applyCss(); 
tempRoot.layout();    

if(job != null && job.showPrintDialog(root.getScene().getWindow())){ 
    Printer printer = job.getPrinter(); 
    PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, Printer.MarginType.HARDWARE_MINIMUM); 

    double width = vToPrint.getWidth(); 
    System.out.println("WIDTH : "+width); 
    //Output : 852.0 

    double height = vToPrint.getHeight(); 
    System.out.println("HEIGHT : "+height); 
    //Output : 803.0 

    PrintResolution resolution = job.getJobSettings().getPrintResolution(); 

    System.out.println("FEEDRESOLUTION : "+resolution.getFeedResolution()); 
    //Output : 600 

    System.out.println("CROSSFEEDRESOLUTION : "+resolution.getCrossFeedResolution()); 
    //Output : 600 


    width /= resolution.getFeedResolution(); 
    System.out.println("NEW WIDTH : "+width); 
    //Output : 1.42 

    height /= resolution.getCrossFeedResolution(); 
    System.out.println("NEW HEIGHT : "+height); 
    //Output : 1.3383333333333334 

    double scaleX = pageLayout.getPrintableWidth()/72/width; 
    System.out.println("SCALE X : "+scaleX); 
    //Output : 8.01056338028169 

    double scaleY = pageLayout.getPrintableHeight()/72/height; 
    System.out.println("SCALE Y : "+scaleY); 
    //Output : 5.935252677755962 

    Scale scale = new Scale(scaleX, scaleY); 

    vToPrint.getTransforms().add(scale); 

    boolean success = job.printPage(pageLayout, vToPrint); 

    if(success){ 
     job.endJob(); 
    } 
} 
root.setLeft(myLeft); 
root.setCenter(myCenter); 
root.setBottom(myBottom); 

Das Ergebnis Druck zeigt nur die linke obere Ecke meines vToPrint Box, eine ganze A4-Seite gespannt .. ^^.

Und die Ausgabe von Breite/Höhe hier ist nicht die gleiche wie die Snapshot-Breite/Höhe früher ich habe ...

left item width : 112.0 height : 892.0 
center item width : 1746.0 height : 892.0 
bottom item width : 1858.0 height : 95.0 

Das ist wirklich verwirrend ...

02 Update:

Neue versuchen, mit Schnappschüssen & imageViews:

PrinterJob job = PrinterJob.createPrinterJob(); 
WritableImage myLeftImg = root.getLeft().snapshot(null, null); 
WritableImage myCenterImg = root.getCenter().snapshot(null, null); 
WritableImage myBottomImg = root.getBottom().snapshot(null, null); 

ImageView myLeftImgView = new ImageView(); 
ImageView myCenterImgView = new ImageView(); 
ImageView myBottomImgView = new ImageView(); 

myLeftImgView.setImage(myLeftImg); 
myCenterImgView.setImage(myCenterImg); 
myBottomImgView.setImage(myBottomImg); 

VBox vToPrint = new VBox(); 
HBox hToPrint = new HBox(); 
hToPrint.getChildren().addAll(myLeftImgView, myCenterImgView); 
vToPrint.getChildren().addAll(hToPrint, myBottomImgView); 

Group myRoot = new Group(); 
Scene myScene = new Scene(myRoot); 
myRoot.getChildren().add(vToPrint);     

myRoot.applyCss(); 
myRoot.layout(); 

if(job != null && job.showPrintDialog(root.getScene().getWindow())){ 
    Printer printer = job.getPrinter(); 
    PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, Printer.MarginType.HARDWARE_MINIMUM); 
    boolean success = job.printPage(pageLayout, vToPrint); 
    if(success){ 
     job.endJob(); 
    } 
} 

Ich habe den Maßstab Teil dieses Stück Code entfernen und es gibt mir tatsächlich die folgende Ausgabe auf Druck:

enter image description here

Update 03:

Jetzt komme ich zu einem Ergebnis, aber die Druckauflösung scheint zu scheitern. Statt/72 die Skala (wie in Update 01):

double scaleX = pageLayout.getPrintableWidth()/72/width; 

Ich habe es teilen mit 600 (wie die resolution.getFeedResolution) ... Aber es wahrscheinlich falsch ist, da ich es schon mit 600 geteilt früher .. .:

width /= resolution.getFeedResolution(); 
// ... 
double scaleX = pageLayout.getPrintableWidth()/width/600; 

die "vToPrint" vbox auf einer A4-Quer Seite das Ergebnis druckt, aber die Auflösung ist wirklich, wirklich, wirklich, ... Bad! Das Ganze ist pixelig. Texte sind lesbar aber es ist etwas falsch mit der Druckauflösung ...

Ich habe auch versucht, einen Snapshot der Knoten zu drucken, also ich meine vToPrint VBox, dann Snapshot erstellen, und speichern Sie den Snapshot in eine .png-Datei. Das ist gut, die Auflösung ist gut. Das Problem ist also im Druck Teil jetzt ...

+0

Die Node.applyCss Dokumentation sagt auch, bpToPrint machen versuchen die Wurzel eine Szene vor dem Aufruf von applyCss und Layout. – VGR

+0

Ja, du hast Recht. Ich tat dies. Sie können den aktualisierten Code jetzt sehen ... – Julo0sS

+0

@VGR Ich versuche tatsächlich, das gleiche zu tun, aber mit Snapshots und imageViews ... Dies löst das "Größen" -Differenzproblem. Aber die Skala ist völlig falsch. Wenn ich den Skalierungscode lasse, bekomme ich nur die obere linke Ecke auf einer Seite. Wenn ich den Maßstabscode entferne, bekomme ich eine gedruckte Seite mit etwa 1/4 der gewünschten Ausgabe auf einer A4-Seite ... – Julo0sS

Antwort

1

ist die Lösung,

Nach vielen Untersuchungen scheint es, dass das Problem der „temp“ Container kommt ich drucken verwenden. Selbst wenn applyCss(), layout() oder autosize() aufgerufen werden, wird der Container NICHT wirklich gerendert.

Die eigentliche Lösung, die ich gefunden habe, ist, die "echten" Container zu verwenden und einfach die Elemente auszublenden, die ich nicht drucken möchte, bevor ich den printJob starte.

Hier ist der aktuelle Code verwende ich: „Diese Methode ist ein no-op, wenn der Knoten nicht in einer Szene ist“

PrinterJob job = PrinterJob.createPrinterJob(); 

if(job != null && job.showPrintDialog(root.getScene().getWindow())){ 
    Printer printer = job.getPrinter(); 
    PageLayout pageLayout = printer.createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, Printer.MarginType.HARDWARE_MINIMUM); 

    root.getTop().setVisible(false); 
    root.getTop().setManaged(false); 

    double width = root.getWidth(); 
    double height = root.getHeight(); 

    PrintResolution resolution = job.getJobSettings().getPrintResolution(); 

    width /= resolution.getFeedResolution(); 

    height /= resolution.getCrossFeedResolution(); 

    double scaleX = pageLayout.getPrintableWidth()/width/600; 
    double scaleY = pageLayout.getPrintableHeight()/height/600; 

    Scale scale = new Scale(scaleX, scaleY); 

    root.getTransforms().add(scale); 

    boolean success = job.printPage(pageLayout, root); 
    if(success){ 
     job.endJob(); 
    } 
    root.getTransforms().remove(scale); 
} 
root.getTop().setManaged(true); 
root.getTop().setVisible(true); 
2

getPrintableWidth() und getPrintableHeight() ihre Größen Rückkehr in ⁄ Zoll. getWidth() und getHeight() geben die Größe in Pixeln zurück.

äquivalente Einheiten zu teilen, Sie Pixel in Zoll mit der printResolution Eigenschaft JobSettings umwandeln können:

double width = bpToPrint.getWidth(); 
double height = bpToPrint.getHeight(); 

// Convert to inches 
PrintResolution resolution = job.getJobSettings().getPrintResolution(); 
width /= resolution.getFeedResolution(); 
height /= resolution.getCrossFeedResolution(); 

double scaleX = pageLayout.getPrintableWidth()/72/width; 
double scaleY = pageLayout.getPrintableHeight()/72/height; 

bewusst sein, dass ein Knoten des getWidth() und getHeight() Methoden zurückkehren Null, wenn es nicht in ist eine sichtbare Bühne, es sei denn, seine applyCss() und layout() Methoden zuerst genannt werden, wie in the documentation of Node.applyCss() beschrieben:

als ein vollständigeres Beispiel verwendet der folgende Code applyCss() und layout(), um die Breite und Höhe des Buttons zu finden, bevor die Bühne gezeigt wurde. Wenn entweder der Anruf an applyCss() oder der Anruf an layout() auskommentiert ist, werden die Anrufe an getWidth() und getHeight() Null zurückgeben (bis einige Zeit nach dem Stage angezeigt wird). Hier

+1

Jewelsea beschreibt den letzten Teil hier: https://stackoverflow.com/ a/26152904/2991525 – fabian

+0

Danke für Ihre Ratschläge und Hilfe VGR & Fabian, aber die Lösung funktioniert immer noch nicht richtig. Überprüfen Sie meinen aktualisierten Beitrag, um zu sehen, was passiert. – Julo0sS

+0

Es scheint, dass die Auflösung (Zoll, dpi, ...) irgendwo falsch ist. Die VBox wird nun auf der ganzen Seite gedruckt, aber alles ist pixelig ...:/Es ist immer noch sehr verwirrend/mysteriös für mich. Mein Beitrag wurde aktualisiert. – Julo0sS