java - 使用 JavaFX 打印节点

标签 java javafx printing

问题来了:

我目前必须打印一个 a4 横向页面,其中包含我当前 javaFx 场景的“部分”。

我要打印的部分是 BorderPane 的一部分,我需要打印 Left、Center 和 Bottom 节点,因此打印页面应该如下所示:

Second A4 Template Image

打印最重要的是中心部分。它必须尽可能宽/高。基本上,左侧部分最多可以占页面宽度的 10%,底部可以占页面高度的 10-15%。因此,中心项目应拉伸(stretch)以适应 90% 的(可打印)页面宽度和 85% 的(可打印)页面高度。

我实际上尝试了一些没有成功的解决方案......我确实创建了一个打印按钮,其行为如下:

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());

当我尝试这段代码时,打印机收到一个作业,“打印”一页……空白页!上面什么都没有印...

如果我删除“缩放”部分,我会在页面上打印一些内容,但它根本不考虑页面大小...

我也确实尝试过“快照”节点,所以我可以检查它们的属性(宽度、高度),但没有找到任何方法来“连接它们”并打印结果...

// 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());

我将其作为输出(仅供引用):

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

感谢您的帮助/阅读,非常感谢任何帮助。

更新 01:

这是“更新后的代码”:

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);

打印结果只显示在我的 vToPrint 框的左上角,延伸到整个 a4 页面...^^

而且这里输出的width/height和我之前得到的snapshot width/height不一样...

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

这真是令人困惑......

更新 02:

快照和 ImageView 的新尝试:

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();
    }
}

我确实删除了这段代码的比例部分,它实际上给了我以下打印输出:

enter image description here

更新 03:

现在我得出了一个结果,但是打印解析好像失败了。而不是/72 比例(如更新 01 中那样):

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

我确实将它除以 600(就像 resolution.getFeedResolution)...但这可能是错误的,因为我之前已经将它除以 600...:

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

结果在 a4 横向页面上打印了“vToPrint”vbox,但是分辨率真的、真的、真的……很糟糕!整件事都是像素化的。文本可读,但现在打印分辨率有问题...

我还尝试制作要打印的节点的快照,因此我构建了 vToPrint VBox,然后对其进行快照,并将快照保存到 .png 文件中。这很好,分辨率很好。所以现在问题出在打印部分......

最佳答案

这是解决方案,

经过多次研究,问题似乎出在我用来打印的“临时”容器上。即使调用了 applyCss()、layout() 或 autosize(),它也不会真正渲染容器。

我找到的实际解决方案是使用“真正的”容器,并在启动 printJob 之前隐藏我不想打印的项目。

这是我目前使用的代码:

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);

关于java - 使用 JavaFX 打印节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44678747/

相关文章:

c - 位显示的错误功能

C# PrintDocument 和打印机状态

java - 扭曲一系列像素以使图像的某些部分显示为 "jiggle"

java - 通过比较其参数之一获取对象

java - bash 脚本问题启动程序

java - 同时打开两个窗口 - JavaFX

java - 使用注解时的 NullPointerException 行为

java - Proxool最大连接数

java - 在javafx中可变地设置Dialog的ContentText

c - 包含宏的预处理器消息