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

时间:2013-02-08 15:21:57

标签: java swing printing jtable

由于多种原因,我正在尝试将多个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循环正确迭代,并且调试语句已经显示每个表都被添加到Book中。更改表的顺序无效。将打印模式更改为PrintMode.NORMAL,确实会出现打印其他表格的部分。但是,由于表格宽度经常超过页面宽度(并且仍无法解释PrintMode.FIT_WIDTH无法正常工作的原因),因此我遇到了一个水平的分页问题。

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

最后:如果Book方法没有希望,我怎样才能将多个JTable(即多个printables)的输出合并到一个作业中?我查看了exporting the table as a PDF,但JTable的内置分页非常好,我宁愿不必亲自去做。我的最后一招是放弃并使用iText的内置表函数来构造表的副本。

编辑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 :(你可以跳过这个)我尝试了Durendal的回答。当我打印足够多的页面时,多页打印正在多次打印最后一页(对于可打印的每页打印一次)。这是我在第一次编辑(下面)中讨论过的同样的问题,我不知道为什么会发生这种情况,我的调试声明说它正确地打印了所有页面,但打印了多页打印的最后一页代替每一页。代码附后。洞察力受到赞赏(并通过虚拟饼干偿还)

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

}

1 个答案:

答案 0 :(得分:3)

我最近遇到了同样的问题。 Book类本身就是无用的,因为如果你向它添加Printables,当Book被打印时,它会将bookIndex从Book传递给pagetable索引的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传递给添加到其中的printables的问题(对于Pageables比Printables更容易)。

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

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实例,因为页数取决于页面格式(纸张大小)。