2013-02-08 47 views
5

由於多種原因,我試圖將多個JTable的輸出合併爲一個打印作業。在試圖構建PDF文件並梳理Java API之後,我決定了Book類。我的打印代碼目前看起來像這樣。將多個JTable作爲一個作業打印 - 圖書對象只打印第一個表

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對象(並且我不知道如何得到它)。

最後:如果書的做法是沒有希望的,怎麼我還能多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); 
     } 
    } 

我把迪朗達爾的代碼,用於確定其自身的功能

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的回答。在打印足夠多的頁面時,多頁面打印多次打印最後一頁(每頁打印一次)。這是我在第一次編輯(下面)中討論的同樣的問題,我不知道爲什麼會發生這種情況,而且我的調試語句表示它正確地打印所有頁面,但打印多頁可打印的最後一頁是打印代替每一頁。代碼附加。 Insight是

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

我使用未修改PageWrapper是迪朗達爾下面給出讚賞(與虛擬餅乾repayed)。

編輯1:(您可以跳過此)斷相銜接迪朗達爾的回答,我試圖讓,不遺餘力我們遍歷一翻自己的苦差事的包裝。不幸的是,它似乎在多頁面printables上正常工作,在文檔中多次打印同一頁面。我發佈它,只是因爲有人可能會使它工作,並且使用起來稍微方便一些。

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

} 
+0

優秀的問題和答案。我有同樣的問題,並能夠一步一步重新創建解決方案。 @kleopatra非常好的編輯。 – downeyt 2016-02-08 17:16:57

回答

3

最近,我有非常相同的問題。 Book類本身是無用,因爲如果您將Printables添加到它,當打印Book時,它將從Book的pageIndex傳遞給pageIndex處的Printable。

這在大多數情況下不是你想要的。

創建一個簡單的打印包裝,能記住的PageIndex用於可打印委託,並添加那些書:

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

現在需要迭代槽每個可打印/可分頁的每一頁,並添加一個包裝器實例(知道其委託中的pageIndex)到Book中。這解決了Book將錯誤的pageIndex傳遞給添加到其中的printables的問題(對於Pageable而言比Printables更容易)。

您可以通過打印其檢測頁的數量在打印;)是的,我是認真的:

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實例,因爲頁數取決於頁面格式(紙張大小)。

+0

你的意思是,如果我在書中添加兩頁兩頁的打印並打印,當本書到達第三頁和第四頁時,它會要求打印第二頁以打印不存在的頁面?哎呀!這沒有被標記爲錯誤?我不太瞭解你的包裝。重寫的打印功能始終使用localPageIndex進行打印。它是否適用於多頁面printables? – 2013-02-08 15:57:45

+0

確實發生了什麼,它從第二個文檔請求不存在的頁面。您在遍歷Pageable/Printable時創建包裝實例,併爲該文檔傳遞正確的pageIndex。當包裝器稍後被書實例使用時,包裝器會小心地將pageIndex轉換爲文檔中實際存在的頁面。 – Durandal 2013-02-08 16:07:55

+0

是的,我同意,他們至少應該在Book的Javadoc中記錄下這個陷阱...花了我一天的時間來找出答案。 – Durandal 2013-02-08 16:08:45