将多个 JTable 作为一项作业打印 - Book 对象仅打印第一个表

2023-12-03

由于多种原因,我尝试将多个 JTable 的输出合并到一个打印作业中。在费了九牛二虎之力尝试构建 PDF 并梳理 Java API 后,我选择了 Book 类。我的打印代码目前看起来像这样。

try {       
    PrinterJob printer = PrinterJob.getPrinterJob();

    //Set 1/2 " margins and orientation
    PageFormat pf = printer.defaultPage();
    pf.setOrientation(PageFormat.LANDSCAPE);
    Paper paper = new Paper();
    double margin = 36; // half inch
    paper.setImageableArea(margin, margin, paper.getWidth() - margin * 2, paper.getHeight() - margin * 2);
    pf.setPaper(paper);

    Book printJob = new Book();

    // Note for next line: getAllTables() returns an ArrayList of JTables
    for (JTable t : getAllTables() )  
        printJob.append(t.getPrintable(PrintMode.FIT_WIDTH, null, null), pf,2);

    printer.setPageable(printJob);

    System.out.println(printJob.getNumberOfPages());

    if (printer.printDialog())
        printer.print();
    } catch (PrinterException e) {
        e.printStackTrace();
}

主要问题:仅打印“第一个”表的输出。我已确保 for 循环正确迭代,并且调试语句显示每个表都已添加到书中。更改表的顺序没有任何影响。将打印模式更改为PrintMode.NORMAL,确实出现在正在打印的其他表格的部分中。但是,我遇到了一系列水平分页问题,​​因为表格宽度经常超过页面宽度(并且它仍然没有解释为什么PrintMode.FIT_WIDTH不工作)

一个次要问题:如何检测每个可打印文件中的正确页数?我的大多数表格都有两页长,因此目前我每次追加时只添加 2 页。我读到“某处”使用Book.UNKNOWN_NUMBER_OF_PAGES因为页码可以解决这个问题,但这只会导致 API 代码中出现 IndexOutOfBounds 异常。我考虑过自己打电话给 print 直到我得到NO_PAGE_EXISTS,但我需要一个具有正确页面尺寸的 Graphics 对象(而且我不知道如何获得它)。

Lastly:如果 Book 方法毫无希望,那么我还能如何将多个 JTable(即多个可打印文件)的输出合并到一个作业中?我调查了将表格导出为 PDF,但是 JTable 的内置分页功能非常好,我宁愿不用自己做。我的最后一招是放弃并使用 iText 的内置表函数来构造表的副本。

Edit 3:根据我下面的评论,我通过生成可打印文件、确定页数,然后生成新页来完成此工作。我还修改了 Durendal 的包装器,以免我们迭代每个页面的麻烦。包装器中的代码是

    class PrintableWrapper implements Printable
    {
        private Printable delegate;
        private int offset;

        public PrintableWrapper(Printable delegate, int offset) {
            this.offset = offset;
            this.delegate = delegate;
        }

        @Override
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
            return delegate.print(graphics, pageFormat, pageIndex-offset);
        }
    }   

我将 Durendal 的用于确定页数的代码放入其自己的函数中

    public int getNumberOfPages(Printable delegate, PageFormat pageFormat) throws PrinterException 
    {
        Graphics g = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics();
        int numPages = 0;
        while (true) {
            int result = delegate.print(g, pageFormat, numPages);
            if (result == Printable.PAGE_EXISTS) {
                ++numPages;
            } else {
                break;
            }
        }

        return numPages;
    }

创建书籍对象后,我的打印代码如下所示

            int totalPages = 0;
            for (DragNDropTable t : getAllTables() )
            {
                int pages = getNumberOfPages(t.getPrintable(PrintMode.FIT_WIDTH, null, null), pf);
                Printable p = t.getPrintable(PrintMode.FIT_WIDTH, null, null);
                printJob.append(new PrintableWrapper(p,totalPages), pf, pages);
                totalPages += pages;
            }
            printer.setPageable(printJob);

            if (printer.printDialog())
                printer.print();

它就像一个魅力!

编辑2:(你可以跳过这个)我尝试了杜伦达尔的回答。当我打印足够的页面时,多页可打印文件会多次打印最后一页(可打印文件中的每一页打印一次)。这与我在第一次编辑(如下)中讨论的问题相同,我不知道为什么会发生这种情况,我的调试语句说它正确打印了所有页面,但打印了多页可打印的最后一页代替每一页。代码附后。洞察力受到赞赏(并以虚拟cookie作为回报)

try {       
    PrinterJob printer = PrinterJob.getPrinterJob();

    //Set 1/2 " margins and orientation
    PageFormat pf = printer.defaultPage();
    pf.setOrientation(PageFormat.LANDSCAPE);
    Paper paper = new Paper();
    double margin = 36; // half inch
    paper.setImageableArea(margin, margin, paper.getWidth() - margin * 2, paper.getHeight() - margin * 2);
    pf.setPaper(paper);

    Book printJob = new Book();

    // Note for next line: getAllTables() returns an ArrayList of JTables
    for (JTable t : getAllTables() )  
    {
        Printable p = t.getPrintable(PrintMode.FIT_WIDTH, null, null);
        int pages = getNumberOfPages(p, pf);

        for (int i=0; i < pages; i++)
            printJob.append(new PageWrapper(p,i), pf);
    }

    printer.setPageable(printJob);

    System.out.println(printJob.getNumberOfPages());

    if (printer.printDialog())
        printer.print();
    } catch (PrinterException e) {
        e.printStackTrace();
}

public int getNumberOfPages(PageFormat pageFormat) throws PrinterException 
{
    Graphics g = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics();
    int numPages = 0;
    while (true) {
        int result = delegate.print(g, pageFormat, numPages);
        if (result == Printable.PAGE_EXISTS) 
            ++numPages;
        else
            break;
    }

    return numPages;
}

我正在使用 Durendal 下面提供的未经修改的 PageWrapper。

编辑1:(您可以跳过此部分)为了与 Durendal 的答案相吻合,我尝试制作一个包装器,让我们免去自己迭代页面的苦差事。不幸的是,它似乎无法在多页可打印文件上正常工作,在文档中多次打印同一页面。我发布它,只是因为有人可能会让它工作,而且使用起来稍微方便一些。

class PrintableWrapper implements Printable
    {
        private Printable delegate;
        private int offset;

        public PrintableWrapper(Printable delegate, int offset) {
            this.offset = offset;
            this.delegate = delegate;
        }

        @Override
        public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
            return delegate.print(graphics, pageFormat, pageIndex-offset);
        }


        public int getNumberOfPages(PageFormat pageFormat) throws PrinterException 
        {
            Graphics g = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics();
            int numPages = 0;
            while (true) {
                int result = delegate.print(g, pageFormat, numPages);
                if (result == Printable.PAGE_EXISTS) 
                    ++numPages;
                else
                    break;
            }

            return numPages;
        }
    }

我的打印代码现在看起来像这样(设置页面格式后)

Book printJob = new Book();
int totalPages = 0;

for (DragNDropTable t : getAllTables() )
{
    Printable p = t.getPrintable(PrintMode.FIT_WIDTH, null, null);
    PrintableWrapper pw = new PrintableWrapper(p, totalPages);
    totalPages += pw.getNumberOfPages(pf);
    printJob.append(pw, pf,pw.getNumberOfPages(pf));
}

printer.setPageable(printJob);

if (printer.printDialog())
{
    printer.print();

}

我最近遇到了同样的问题。 Book 类本身是useless,因为如果向其中添加 Printable,当打印 Book 时,它会将 Book 的 pageIndex 传递到 pageIndex 处的 Printable。

在大多数情况下,这不是您想要的。

创建一个简单的 Printable Wrapper,它可以记住用于 Printable 委托的 pageIndex 并将其添加到 Book 中:

class PageWrapper implements Printable {
    private Printable delegate;
    private int localPageIndex;

    public PageWrapper(Printable delegate, int pageIndex) {
        this.localPageIndex = pageIndex;
        this.delegate = delegate;
    }

    @Override
    public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
        return delegate.print(graphics, pageFormat, localPageIndex);
    }
}

现在,您需要遍历每个 Printable/Pageable 的每个页面,并向 Book 添加一个包装器实例(知道其委托中的 pageIndex)。这解决了 Book 将错误的 pageIndex 传递给添加到其中的可打印文件的问题(对于可打印文件来说,它比可打印文件更容易)。

您可以通过打印来检测可打印文件中的页数;)是的,我是认真的:

Graphics g = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics();
int numPages = 0;
while (true) {
    int result = printable.print(g, pageFormat, numPages);
    if (result == Printable.PAGE_EXISTS) {
        ++numPages;
    } else {
        break;
    }
}

从要打印到的实际 PrinterJob 获取 PageFormat 实例非常重要,因为页数取决于页面格式(纸张尺寸)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将多个 JTable 作为一项作业打印 - Book 对象仅打印第一个表 的相关文章

随机推荐