将多个JTable打印为一个作业

将多个JTable打印为一个作业

本文介绍了将多个JTable打印为一个作业 - Book对象仅打印第一个表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 试试{
PrinterJob printer = PrinterJob.getPrinterJob();

//设置1/2边距和方向
PageFormat pf = printer.defaultPage();
pf.setOrientation(PageFormat.LANDSCAPE);
纸= 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();

//下一行的注释:getAllTables()返回一个ArrayList 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();
}

主要问题:只有第一个表的输出为pr inting。我已经确保for循环正确迭代,并且调试语句已经显示每个表都被添加到Book中。更改表的顺序无效。将打印模式更改为 PrintMode.NORMAL ,确实会出现打印其他表的部分。但是,由于表格宽度经常超过页面宽度(我仍然无法解释为什么 PrintMode.FIT_WIDTH 无效),因此我遇到了一个水平的分页问题。 / p>

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



最后:如果Book方法没有希望,我怎样才能将多个JTable的输出(即多个printables)合并为一个工作?我查看了,但JTable内置的分页非常好,我宁愿不必自己动手。我的最后一招是放弃并使用iText的内置表函数来构建表的副本。



编辑3:根据下面的评论,我通过生成可打印,确定页数,然后生成新页面来实现此目的一。我还修改了Durendal的包装器,以免我们在每个页面上迭代。包装器中的代码是

 类PrintableWrapper实现Printable 
{
private Printable delegate;
private int offset;

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

@Override
public int print(图形图形,PageFormat pageFormat,int pageIndex)抛出PrinterException {
return delegate.print(graphics,pageFormat,pageIndex-偏移量);
}
}

我把Durendal的代码用于确定其页数自己的函数

  public int getNumberOfPages(Printable delegate,PageFormat pageFormat)抛出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;
}其他{
休息;
}
}

返回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的回答。当我打印足够多的页面时,多页打印正在多次打印最后一页(对于可打印的每页都打印一次)。这是我在第一次编辑(下面)中讨论的同样的问题,我不知道为什么会发生这种情况,我的调试声明说它正确地打印了所有页面,但打印了多页打印的最后一页代替每一页。代码附后。 Insight非常感谢(并使用虚拟cookie进行了回报)

 尝试{
PrinterJob printer = PrinterJob.getPrinterJob();

//设置1/2边距和方向
PageFormat pf = printer.defaultPage();
pf.setOrientation(PageFormat.LANDSCAPE);
纸= 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();

//下一行的注释:getAllTables()返回一个ArrayList 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;
其他
休息;
}

返回numPages;
}

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



编辑1 :(你可以跳过这个)与Durendal的答案相吻合,我试图制作一个包装器,让我们免去遍历页面的烦恼。不幸的是,它似乎无法在多页打印机上正常工作,在文档中多次打印同一页面。我发布它,只是因为有人可以让它工作,而且使用起来稍微方便一些。

  class PrintableWrapper实现Printable 
{
private Printable delegate;
private int offset;

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

@Override
public int print(图形图形,PageFormat pageFormat,int pageIndex)抛出PrinterException {
return delegate.print(graphics,pageFormat,pageIndex-偏移量);
}


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;
其他
休息;
}

返回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类本身就是无用的,因为如果你向它添加Printables,当Book打印出来时,它会将bookIndex从Book传递给printtable at pageIndex。



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



创建一个简单的Printable Wrapper,它可以记住用于Printable委托的pageIndex和将这些添加到书中:

  class PageWrapper实现Printable {
private Printable delegate;
private int localPageIndex;

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

@Override
public int print(图形图形,PageFormat pageFormat,int pageIndex)抛出PrinterException {
return delegate.print(graphics,pageFormat,localPageIndex) ;
}
}

现在你需要遍历每个Printable的每个页面/ Pageable并向Book添加一个包装器实例(知道pageIndex到其委托中)。这解决了Book将错误的pageIndex传递给添加到其中的printables的问题(Pageables比Printables更容易)。



您可以检测Printable中的Pages数量打印它;)是的,我是认真的:

 图形g =新的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;
}其他{
休息;
}
}

重要的是从实际的PrinterJob获取PageFormat实例你想打印到,因为页数取决于页面格式(纸张大小)。


For a number of reasons, I'm trying to combine the output of multiple JTables into a single print job. After tearing my hair out trying to build PDFs, and combing the Java API, I settled on the Book class. My printing code currently looks like this.

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

Primary Problem: Only the output from the "first" table is printing. I've made sure the for loop iterates correctly, and debugging statements have shown that every table is being added to the Book. Changing order of tables has no effect. Changing the print mode to PrintMode.NORMAL, does appear result in pieces of the other tables being printed. However, I run into a slew horizontal pagination problems, as the table width frequently exceeds page width (and it still doesn't explain why PrintMode.FIT_WIDTH isn't working)

A secondary question: How can I detect the correct number of pages in each printable? Most of my tables are two pages long, so for the moment, I'm just adding 2 pages each time I append. I read "somewhere" that using Book.UNKNOWN_NUMBER_OF_PAGES as the page number will fix this problem, but that only leads to an IndexOutOfBounds exception in the API's code. I've considered calling print myself until I get NO_PAGE_EXISTS, but I'd need a Graphics object with the proper page dimensions (and I have no idea how to get that).

Lastly: If the Book approach is hopeless, how else can I combine the output of multiple JTables (ie. multiple printables) into a single job? I looked into exporting the table as a PDF, but JTable's built-in pagination is so nice, I'd rather not have to do it myself. My last resort is to just give up and use iText's built in table function to construct a copy of the table.

Edit 3: Per my comment below, I got this working by generating a printable, determining the # of pages, and then generating a new one. I also modified Durendal's wrapper to spare us the hassle of iterating over each page. The code from the wrapper is

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

I put Durendal's code for determining number of pages in its own function

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

After I create the book object, my printing code looks like this

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

And it works like a charm!

Edit 2: (you can skip this) I tried Durendal's answer. While I'm printing enough pages, multipage printables are printing the last page multiple times (once for every page in the printable). This is the same problem I discussed in my 1st edit (below), and I have no idea why this is happening, and my debugging statements are saying that it's printing all of the pages correctly, but the last page of a multipage printable is printed in place of each page. Code is attached. Insight is appreciated (and repayed with virtual cookies)

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

I'm using the unmodified PageWrapper that Durendal gave below.

Edit 1: (You can skip this) Dovetailing off of Durendal's answer, I tried to make a wrapper that spares us the chore of iterating over the pages ourselves. Unfortunately, it doesn't seem to work correctly on multipage printables, printing the same page multiple times in the document. I post it, simply because someone may get it to work, and it's slightly more convenient to use.

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

My printing code now looks like this (after I set the page format)

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

}
解决方案

I had the very same Problem recently. The Book class by itself is useless, because if you add Printables to it, when the Book is printed it will pass the pageIndex from the Book to the Printable at pageIndex.

That is in most cases not what you want.

Create a simple Printable Wrapper that can remember a pageIndex to be used for the Printable delegate and add those to the 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);
    }
}

Now you need to iterate trough each page of each Printable/Pageable and add a wrapper instance (that knows the pageIndex into its delegate) to the Book. That solves the problem that Book passes the wrong pageIndex to the printables added to it (its easier for Pageables than Printables).

You can detect the number of Pages in a Printable by printing it ;) Yes, I'm serious:

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

Its important you obtain your PageFormat instance from the actual PrinterJob you want to print to, because the number of pages depends on the page format (paper size).

这篇关于将多个JTable打印为一个作业 - Book对象仅打印第一个表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-22 20:02