5

いくつかの理由から、複数の JTable の出力を 1 つの印刷ジョブに結合しようとしています。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 ページの長さなので、今のところ、追加するたびに 2 ページだけ追加しています。ページ番号として使用するとこの問題が解決することを「どこか」で読みBook.UNKNOWN_NUMBER_OF_PAGESましたが、それは API のコードで IndexOutOfBounds 例外につながるだけです。が得られるまで print を自分で呼び出すことを検討しましNO_PAGE_EXISTSたが、適切なページサイズの Graphics オブジェクトが必要です (それを取得する方法がわかりません)。

最後に: Book アプローチが絶望的である場合、複数の JTables (つまり、複数の印刷可能なもの) の出力を 1 つのジョブに結合するにはどうすればよいでしょうか? テーブルを 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);
        }
    }   

ページ数を決定するためのデュランダルのコードを独自の関数に入れました

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

book オブジェクトを作成すると、印刷コードは次のようになります

            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 の回答を試しました。十分なページを印刷している間に、複数ページの印刷可能ファイルが最後のページを複数回印刷しています (印刷可能ページごとに 1 回)。これは、最初の編集 (以下) で説明したのと同じ問題です。なぜこれが起こっているのかわかりません。デバッグ ステートメントでは、すべてのページが正しく印刷されていると言っていますが、複数ページの印刷可能なページの最後のページが印刷されます。各ページの代わりに。コードが付属しています。洞察は高く評価されます (そして、仮想 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();

}
4

1 に答える 1

3

私は最近まったく同じ問題を抱えていました。Book クラス自体は役に立ちません。Printablesを追加すると、Book が印刷されるときに pageIndex が Book から Printable の pageIndex に渡されるためです。

それはほとんどの場合、あなたが望むものではありません。

Printable デリゲートに使用される pageIndex を記憶できる単純な Printable Wrapper を作成し、それらを 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 の各ページを繰り返し処理し、ラッパー インスタンス (デリゲートへの pageIndex を認識している) を Book に追加する必要があります。これにより、Book が追加された printables に間違った pageIndex を渡すという問題が解決されます (Printables よりも Pageables の方が簡単です)。

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 インスタンスを取得することが重要です。

于 2013-02-08T15:47:57.117 に答える