2016-09-26 23 views
5

Rozwiązanie dla języka C#, które można znaleźć w części Edycja pytania. Specjalne podziękowania dla Bruno LowagieC# - itextSharp subtotal na każdej stronie

Próbuję utworzyć fakturę za pośrednictwem iTextSharp w języku C#. Działa bardzo dobrze, ale napotyka problemy, gdy próbuję wydrukować podsumowanie na każdej stronie.

Oto częścią im kodu używanego do tworzenia tabeli w odniesieniu do produktów:

PdfPTable table = new PdfPTable(5); 
     table.WidthPercentage = 100; 
     float[] widths = new float[] { 10f, 30f, 120f, 30f, 30f }; 
     table.SetWidths(widths); 
     table.SkipLastFooter = true; 
     table.SpacingAfter = 10;      

     //Cells to Write Header & Footer 
     AddCell(table, "Pos.", PdfPCell.ALIGN_RIGHT, BORDER_LTB, 0); 
     AddCell(table, "Menge", PdfPCell.ALIGN_RIGHT, BORDER_TB); 
     AddCell(table, "Text", PdfPCell.ALIGN_LEFT, BORDER_TB); 
     AddCell(table, "Einzelpreis ", PdfPCell.ALIGN_RIGHT, BORDER_TB); 
     AddCell(table, "Summe", PdfPCell.ALIGN_RIGHT, BORDER_RTB); 

     AddCell(table, "SUBTOTAL", PdfPCell.ALIGN_LEFT, BORDER_LTB, 7, 4); 
     AddCell(table, "", PdfPCell.ALIGN_LEFT, BORDER_RTB); 

     table.HeaderRows = 2; 
     table.FooterRows = 1; 

     //Cells with positions of invoice 
     for (int i = 0; i < beleg.Einzel.Count; i++) 
     { 
      AddCell(table, beleg.Einzel[i].be_lfd_nr.ToString(), PdfPCell.ALIGN_LEFT, BORDER_LTB); 
      AddCell(table, beleg.Einzel[i].be_art_menge.ToString("N", _gbVars.NFI3D), PdfPCell.ALIGN_RIGHT, BORDER_TB); 
      AddCell(table, (beleg.Einzel[i].be_art_bez.ToString() + "\n" + beleg.Einzel[i].be_pos_text.ToString()).Trim(), PdfPCell.ALIGN_LEFT, BORDER_TB); 
      AddCell(table, beleg.Einzel[i].be_summe_preis.ToString("N", _gbVars.NFI2D), PdfPCell.ALIGN_RIGHT, BORDER_TB); 
      AddCell(table, beleg.Einzel[i].be_summe_netto.ToString("N", _gbVars.NFI2D), PdfPCell.ALIGN_RIGHT, BORDER_RTB); 
     } 

     table.SplitLate = false; 
     document.Add(table); 

Border_RTB i tak dalej są stałe dla moich border-style.

Ten kod generuje czarownicą tabela wygląda następująco:

+------------------------------------------+ 
| Pos | Menge | Text | Einzelpreis | Summe | 
+------------------------------------------+ 
| 1 | 2 | Text |  10.00 | 20.00 | 
+------------------------------------------+ 
| 2 | 1 | Text |  10.00 | 10.00 | 
+------------------------------------------+ 
| 3 | 4 | Text |  10.00 | 40.00 | 
+------------------------------------------+ 
| 4 | 2 | Text |  10.00 | 20.00 | 
+------------------------------------------+ 
|SUBTOTAL       |  | 
+------------------------------------------+ 

tabela może płynąć do następnej strony an i whant napisać podsumę każdej strony w stopce. Wydarzenie "OnEndPage" nie pomaga mi, ponieważ to wydarzenie nie "wie", gdzie w tabeli strona jest zepsuta.

Czy ktoś może mi powiedzieć, w jaki sposób otrzymuję podsumowanie na każdej stronie? Czy istnieje jakieś rozwiązanie, w jaki sposób mogę podsumować coś na stronie i wydrukować je w pliku pdf?

Przepraszam, jeśli mój opis nie jest tak dobry. Problemy z moim angielskim. : -/

EDIT:

Oto rozwiązanie. Specjalne podziękowania dla Bruno. Pokazał mi drogę. W mojej wersji suma częściowa NIE resetuje się na każdej stronie. Sądzę, że to był błąd w moim opisie problemu.

Nowe Clases:

public class Totals 
    { 
     public double subtotal = 0; 
     public double total = 0; 
    } 


    public class SubTotalEvent : IPdfPCellEvent 
    { 
     Double price; 
     Totals totals; 
     bool printTotals = false;  //If we just whant to print out the Subtotal, this will be true. 
     bool CellWrittenOnce = false; //Bool to SUM price just once (if row flows to a second page) 

     public SubTotalEvent(Totals totals, double price) { 
      printTotals = false; 
      this.totals = totals; 
      this.price = price; 
     } 

     public SubTotalEvent(Totals totals) { 
      this.totals = totals; 
      printTotals = true; 
     } 

     public void CellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) { 
      if (printTotals) 
      { 
       PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS]; 
       ColumnText.ShowTextAligned(canvas, Element.ALIGN_LEFT, new Phrase(totals.subtotal.ToString()), position.GetLeft(0) + 2, position.GetBottom(0) + 2, 0); 
       return; 
      }  
      if (!CellWrittenOnce) { 
       totals.subtotal += price; 
       totals.total += price; 
      } 
      CellWrittenOnce = true; 
     } 
    } 

Code Aby utworzyć tabelę:

PdfPTable table = new PdfPTable(5); 
     table.WidthPercentage = 100; 
     float[] widths = new float[] { 10f, 30f, 120f, 30f, 30f }; 
     table.SetWidths(widths); 
     table.SkipLastFooter = true; 
     table.SpacingAfter = 10;      

     AddCell(new PdfPCell(new Phrase("item"))); 
     AddCell(new PdfPCell(new Phrase("amount"))); 
     AddCell(new PdfPCell(new Phrase("text"))); 
     AddCell(new PdfPCell(new Phrase("price"))); 
     AddCell(new PdfPCell(new Phrase("sum"))); 

     Totals totals = new Totals(); 
     PdfPCell cel = new PdfPCell(new Phrase("Subtotal")); 
     cel.Colspan = 4; 
     table.AddCell(cel); 
     cel = new PdfPCell(); 
     cel.CellEvent = new SubTotalEvent(totals); 
     table.AddCell(cel); 


     table.HeaderRows = 2; 
     table.FooterRows = 1; 

     for (int i = 0; i < beleg.Einzel.Count; i++) 
     { 
      AddCell(new PdfPCell(new Phrase(i.toString()))); 
      AddCell(new PdfPCell(new Phrase("2"))); 
      AddCell(new PdfPCell(new Phrase("ItemText"))); 
      AddCell(new PdfPCell(new Phrase("10.00"))); 

      cell = new PdfPCell(new Phrase("20.00")); 
      cell.CellEvent = new SubTotalEvent(totals, 20.00); 
      table.AddCell(cell); 
     } 

     table.SplitLate = false; 
     document.Add(table); 
+2

Musisz zaimplementować klasę 'PdfPageEventHelper'. Twoja implementacja byłaby wykonywana za każdym razem, gdy strona zostanie utworzona. Zobacz ten samouczek, jak go zaimplementować http://www.mazsoft.com/blog/post/2008/04/30/Code-sample-for-using-iTextSharp-PDF-library – Darren

+1

Implementuję klasę 'PdfPageEventHelper'. Ale jak mogę dowiedzieć się w "publicznych zastąpić nieważne OnEndPage (pisarz PdfWriter, Dokument doc)", gdzie jestem w tabeli? Tabela jest już napisana w tym miejscu. To wydarzenie jest wywoływane w 'document.Add (table);' –

+0

Niektóre rzeczy nie są dla mnie natychmiast jasne z opisu problemu, więc nie jestem pewien, czy mam jeszcze odpowiedź. Czy następujące założenia są prawidłowe: 1. Dokument faktury składa się z pojedynczej, dużej tabeli, która może obejmować wiele stron. 2. Twoja faktura nie jest formularzem, masz dostęp do wszystkich informacji podczas generowania dokumentu. 3. Chcesz wydrukować sumę częściową składającą się ze wszystkich produktów na bieżącej stronie + sumę sum pośrednich do bieżącej strony w nagłówku/stopce tej strony. –

Odpowiedz

1

Proszę spojrzeć na przykład SubTotal.

Najpierw tworzymy klasę śledzić sumy częściowej i całkowitej:

class Totals { 
    double subtotal = 0; 
    double total = 0; 
} 

Potem implementować interfejs PdfPCellEvent, że będziemy używać w kolumnie 5:

class SubTotalEvent implements PdfPCellEvent { 

    Double price; 
    Totals totals; 

    public SubTotalEvent(Totals totals, double price) { 
     this.totals = totals; 
     this.price = price; 
    } 

    public SubTotalEvent(Totals totals) { 
     this.totals = totals; 
     price = null; 
    } 

    @Override 
    public void cellLayout(PdfPCell cell, Rectangle position, PdfContentByte[] canvases) { 
     if (price == null) { 
      PdfContentByte canvas = canvases[PdfPTable.TEXTCANVAS]; 
      ColumnText.showTextAligned(canvas, Element.ALIGN_LEFT, 
        new Phrase(String.valueOf(totals.subtotal)), 
        position.getLeft() + 2, position.getBottom() + 2, 0); 
      totals.subtotal = 0; 
      return; 
     } 
     totals.subtotal += price; 
     totals.total += price; 
    } 

} 

Określiliśmy dwa konstruktory: jeden dla normalnej komórki zawierającej cenę. Jeden dla komórki stopki zawierającej sumę częściową (w tym przypadku nie przekazujemy ceny).

ten sposób możemy użyć tego zdarzenia komórkowy:

public void createPdf(String dest) throws IOException, DocumentException { 

    Totals totals = new Totals(); 

    Document document = new Document(); 
    PdfWriter.getInstance(document, new FileOutputStream(dest)); 
    document.open(); 
    PdfPTable table = new PdfPTable(5); 
    table.setWidths(new int[]{1, 1, 1, 3, 3}); 
    // header 
    table.addCell("Pos"); 
    table.addCell("Menge"); 
    table.addCell("Text"); 
    table.addCell("Einzerpreis"); 
    table.addCell("Summe"); 
    // footer 
    PdfPCell cell = new PdfPCell(new Phrase("Subtotal")); 
    cell.setColspan(4); 
    table.addCell(cell); 
    cell = new PdfPCell(); 
    cell.setCellEvent(new SubTotalEvent(totals)); 
    table.addCell(cell); 
    // definitions 
    table.setHeaderRows(2); 
    table.setFooterRows(1); 
    // table body 
    for(int r = 0; r < 50;){ 
     table.addCell(String.valueOf(++r)); 
     table.addCell("1"); 
     table.addCell("text"); 
     table.addCell("10.0"); 
     cell = new PdfPCell(new Phrase("10.0")); 
     cell.setCellEvent(new SubTotalEvent(totals, 10)); 
     table.addCell(cell); 
    } 
    document.add(table); 
    // extra footer 
    table = new PdfPTable(5); 
    table.setWidths(new int[]{1, 1, 1, 3, 3}); 
    cell = new PdfPCell(new Phrase("Grand total")); 
    cell.setColspan(4); 
    table.addCell(cell); 
    table.addCell(String.valueOf(totals.total)); 
    document.add(table); 
    document.close(); 
} 

Wynik wygląda tak:

enter image description here

na pierwszej stronie, mamy 46 wierszy ciała każdego za przesyłkę z cena 10.W stopce znajduje się suma częściowa 460. Na drugiej stronie mamy 4 rzędy ciał dla każdej pozycji z ceną 10. W stopce znajduje się suma częściowa 40. Dodaliśmy dodatkowy stół, aby naśladować dodatkową stopkę dla sumy wielkiej: 500.

+0

Już prawie jesteśmy! Bardzo ci dziękuję! Pozostał tylko jeden problem: jeśli na przykład wiersz 46 miałby większą wysokość i przepływałby ponad dwie strony, suma częściowa w twoim przykładzie na pierwszej stronie byłaby poprawna. Ale na stronie drugiej byłoby to 50, a nie 40. Ale naprawiłem to za pomocą dodatkowej zmiennej bool. Dla wszystkich czytelników: Powyższy kod z Bruno Lowagie to kod JAVA. Dla języka C# trzeba tłumaczyć. Ale działa bardzo dobrze! Niesamowite. :-) –

Powiązane problemy