JavaFX PrintAPI错误的PaperSource

我正在使用JavaFx Print-Dialog来定制打印作业。 所有属性都将存储在PrinterJob#JobSettings变量中,但是当我从jobSetting接收纸张来源时,纸张来源始终是默认设置。

我如何获取我设置的纸张来源?

这是一个简短的例子:

public class PrinterPaperSourceTest extends Application {
    public static void main(String[] args) {
        launch( args );
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Printer");
        Button btn = new Button();
        btn.setText("Show Printer Settings ");
        btn.setOnAction( new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                PrinterJob job = PrinterJob.createPrinterJob(Printer.getDefaultPrinter());
                job.showPageSetupDialog(null);
                Alert alert = new Alert(AlertType.INFORMATION);
                PaperSource paperSource = job.getJobSettings().getPaperSource();
                alert.setContentText("PaperSource: " + paperSource.getName());
                alert.show();
            }
        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }
}

我没有答案,但我会试着解释为什么会发生,以及为什么它不容易修复。 这种行为似乎受到Internet打印协议(IPP)规范的影响,并且是由Java Print Service API(JavaFX打印作业委托给其执行)执行IPP的方式引起的。 以下是Oracle技术说明中的一个片段,它解释了手动设置纸张来源的限制(https://docs.oracle.com/javase/8/docs/technotes/guides/jps/spec/attributes.fm5.html):

介质是标识要在其上进行打印的介质的IPP属性。 媒体属性是理解的重要属性,但相对复杂。

Java Print Service API定义抽象类Media的三个子类,以反映IPP规范中的重载媒体属性:MediaSizeName,MediaName和MediaTray。 所有媒体子类都具有媒体类别,每个子类都为其定义不同的标准属性值。 [...]

媒体属性的值始终是一个字符串,但由于该属性被重载,其值将决定属性引用的媒体的类型。 例如,IPP预定义的一组属性值包括值“a4”和“top-tray”。 如果媒体设置为值“a4”,则媒体属性是指纸张的大小,但是如果媒体设置为“顶部纸盘”,则媒体属性是指纸张来源。 [...]

在大多数情况下,应用程序将使用MediaSizeName或MediaTray。 MediaSizeName类按大小枚举媒体。 MediaTray类枚举打印机上的纸盒,通常包括主纸盒和手动进纸盒。 IPP 1.1规范没有规定同时指定介质尺寸和介质托盘,这意味着例如应用程序无法从手动托盘请求尺寸为A4的纸张。 未来版本的IPP规范可能会提供一次请求多种类型的媒体的方法,在这种情况下,JPS API很可能会得到增强以实现此更改。

因此, MediaTray (或纸张来源)不是一个独立参数,如果Media属性已由其他两种方式之一( MediaSizeNameMediaName )定义,则无法设置该参数。 这正是页面设置对话框发生的情况。

J2DPrinterJob类(来自com.sun.prism.j2d.print包)包含对话框代码并更新打印作业设置(我通过调试应用程序发现了这一点)。 以下是此类中更新对话框中纸张来源设置的方法。

private void updatePaperSource() {
    Media m = (Media)printReqAttrSet.get(Media.class);
    if (m instanceof MediaTray) {
        PaperSource s = j2dPrinter.getPaperSource((MediaTray)m);
        if (s != null) {
            settings.setPaperSource(s);
        }
    }
}

我测试了不同的场景,结果相同:在updatePaperSource()开始执行时, Media属性已被定义为MediaSizeName类型。 所以if分支中的语句永远不会执行,这就是为什么纸源不会更新。

我怀疑纸张类型或纸张尺寸优先于纸张来源,并且因为页面设置对话框始终定义纸张类型(没有“自动”选项),所以纸张来源选择过载以避免属性冲突。 这基本上使这个选项无用。

这可能是JDK中的一个错误或有意的设计决策。 无论如何,考虑到它来自Java内部API中的私有方法,我看不出一个简单的方法来解决JavaFX中存在的这个问题。


打印API出现在fx8.0中。 它可以打印节点。 您可以使用javafx.print.PrinterJob类创建打印机作业。 但它只打印适合打印页面的区域,而不打印在屏幕上。 所以你需要通过手动使节点适合页面(缩放,翻译等)。

您可以使用此代码。 希望它能帮助你。

/**
 * Prints the current page displayed within the internal browser, not necessarily the {@link #presentationProperty()}.
 * If no printers are installed on the system, an awareness is displayed.
 */
public final void print() {
    final PrinterJob job = PrinterJob.createPrinterJob();

    if (job != null) {
        if (job.showPrintDialog(null)) {
            if(this.getPresentation().getArchive() != null) {
                final String extension = ".".concat(this.getPresentation().getArchiveExtension());
                final int indexOfExtension = this.getPresentation().getArchive().getName().indexOf(extension);
                final String jobName = this.getPresentation().getArchive().getName().substring(0, indexOfExtension);
                job.getJobSettings().setJobName(jobName);
            }

            job.getJobSettings().setPrintQuality(PrintQuality.HIGH);
            job.getJobSettings().setPageLayout(job.getPrinter().createPageLayout(Paper.A4, PageOrientation.LANDSCAPE, 0, 0, 0, 0));

            this.internalBrowser.getEngine().print(job);
            job.endJob();
        } else {
            job.cancelJob();
        }
    } else {
        DialogHelper.showError("No printer", "There is no printer installed on your system.");
    }
}

资源链接:

  • javafx.print.PrinterJob示例
  • 实例介绍:JavaFX 8打印

  • 经过大量的搜索后,我找到了一种用javafx打印到另一个托盘的方法,这是我查看的第一个地方,所以我想这里是发布我的解决方案的最佳位置,它可能因不同的托盘名称而异我的托盘2它也会打印出所有可用的托盘

    private void printImage(Node node) {
        PrinterJob job = PrinterJob.createPrinterJob();
        if (job != null) {
            JobSettings js = job.getJobSettings();
            PaperSource papersource = js.getPaperSource();
            System.out.println("PaperSource=" + papersource);
            PrinterAttributes pa = printer.getPrinterAttributes();
            Set<PaperSource> s = pa.getSupportedPaperSources();
            System.out.println("# of papersources=" + s.size());
            if (s != null) {
                for (PaperSource newPaperSource : s) {
                    System.out.println("newpapersource= " + newPaperSource);
    
                    //Here is where you would put the tray name that is appropriate
                    //in the contains section
                    if(newPaperSource.toString().contains("Tray 2"))
                        js.setPaperSource(newPaperSource);
                }
            }
            job.getJobSettings().setJobName("Whatever You want");
            ObjectProperty<PaperSource> sources = job.getJobSettings().paperSourceProperty();
            System.out.println(sources.toString());
            boolean success = job.printPage(node);
            if (success) {
                System.out.println("PRINTING FINISHED");
                job.endJob();
                //Stage mainStage = (Stage) root.getScene().getWindow();
                //mainStage.close();
            }
        }
    }
    

    这是我的输出:

    PaperSource=Paper source : Automatic
    # of papersources=6
    newpapersource= Paper source :
    newpapersource= Paper source :  Manual Feed in Tray 1
    newpapersource= Paper source :  Printer auto select
    newpapersource= Paper source :  Tray 1
    newpapersource= Paper source :  Tray 2
    newpapersource= Paper source : Form-Source
    ObjectProperty [bean:  Collation = UNCOLLATED
     Copies = 1
     Sides = ONE_SIDED
     JobName = Whatever
     Page ranges = null
     Print color = COLOR
     Print quality = NORMAL
     Print resolution = Feed res=600dpi. Cross Feed res=600dpi.
     Paper source = Paper source :  Tray 2
     Page layout = Paper=Paper: Letter size=8.5x11.0 INCH Orient=PORTRAIT leftMargin=54.0 rightMargin=54.0 topMargin=54.0 bottomMargin=54.0, name: paperSource, value: Paper source :  Tray 2]
    PRINTING FINISHED
    
    链接地址: http://www.djcxy.com/p/34775.html

    上一篇: JavaFX PrintAPI wrong PaperSource

    下一篇: Can we do VOIP push notification using Twilio iOS SDK?