Problem beim drucken multipler Seiten mit fortlaufendem Text

  • VB.NET

Es gibt 65 Antworten in diesem Thema. Der letzte Beitrag () ist von silverbob76GE.

    Werde heute noch ne demo app hochladen.
    aber vielleicht kurz was zum stringbuilder:

    muss ich eventuell auf seite 2 den zaehler indextext so lassen, aber dafür charactersfitted auf die komplette textlänge setzen? Das probier ich noch aus, bin noch unterwegs.

    Hab die Datei mal angehängt. Der Ansatz von oben hat nix gebracht. Hoffe das jemand ne Antwort hat.
    Dateien
    • WindowsApp1.zip

      (47,11 kB, 45 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „silverbob76GE“ ()

    habs jetzt auf der ersten version aufgebaut.
    Wichtig ist eben, dass man aufräumt, richtig benennt, und vor allem denselben Code nicht mehrmals hinschreibt.
    sonst blickt man nicht mehr durch.

    Insbesondere undurchsichtig sind auch If-Abschnitte oder Schleifen, die über mehr als eine Bildschirmseite gehen.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    2. Dim g = e.Graphics
    3. Dim margin = PrintDocument1.DefaultPageSettings.Margins
    4. Dim X = margin.Left
    5. Dim Y = margin.Top
    6. Dim drawText As Action(Of String, Integer, Integer) = Sub(s, dx, dy) g.DrawString(s, myfont, Brushes.Black, X + dx, Y + dy)
    7. If _pageNr = 0 Then
    8. drawText("Auftragsnummer" & vbTab & vbTab & ":", 10, 240)
    9. drawText("Bauvorhaben" & vbTab & vbTab & ":", 10, 260)
    10. Y += 360
    11. Else
    12. Y += 80
    13. End If
    14. DrawColumnHeaders(g, X, Y)
    15. e.HasMorePages = True
    16. Try
    17. For i = _printRow To bsFkAuftragsdetail.Count - 1
    18. Dim row = DirectCast(DirectCast(bsFkAuftragsdetail(i), DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    19. If _printedLeistungChars = 0 Then
    20. 'neu angefangene row: auch die anderen Werte eintragen
    21. If Not row.IsPosNull Then drawText(CStr(row.Pos), 17, 35)
    22. If Not row.IsMengeNull Then drawText(Format(row.Menge, "N2"), 465, 35)
    23. If Not row.IsEinheitNull Then drawText(Format(row.Einheit), 535, 35)
    24. If Not row.IsEinzelpreisNull Then drawText(Format(row.Einzelpreis, "C2"), 603, 35)
    25. If Not row.IsGesamtpreisNull Then drawText(Format(row.Gesamtpreis, "C2"), 668, 35)
    26. End If
    27. 'ab hier vorwiegend Aufwand wg der Leistung-Spalte
    28. Dim sUnprinted = If(row.IsLeistungNull, "", row.Leistung.Substring(_printedLeistungChars))
    29. Dim layoutRect = g.VisibleClipBounds
    30. layoutRect.Offset(X + 60, Y + 35)
    31. layoutRect.Width = 380
    32. layoutRect.Height -= Y
    33. Dim charactersfitted, linesfilled As Integer
    34. Dim sz = g.MeasureString(sUnprinted, myfont, layoutRect.Size, _strformat, charactersfitted, linesfilled)
    35. Dim sPrint = sUnprinted.Substring(0, charactersfitted)
    36. g.DrawString(sPrint, myfont, Brushes.Black, layoutRect, _strformat)
    37. _printedLeistungChars += charactersfitted
    38. Dim hoehe = Ausgabenhöhe(sz, _breiteLeistungCol)
    39. Y += 35
    40. DrawGridlines(g, X, Y, hoehe)
    41. If charactersfitted < sUnprinted.Length Then Return ' wenn hier rausspringt wird auf nächster Seite mit selber Row weitergemacht
    42. _printRow += 1
    43. _printedLeistungChars = 0
    44. If hoehe > 20 Then Y += CInt(hoehe) - 20
    45. If Y >= 850 Then Return ' wenn hier rausspringt wird auf nächster Seite mit nächster Row
    46. Next
    47. e.HasMorePages = False
    48. Finally
    49. _pageNr += 1
    50. g.DrawString(String.Format(" - Seite {0} -", _pageNr), myfont, Brushes.LightGray, 380, 1130)
    51. End Try
    52. End Sub
    53. Private Sub DrawColumnHeaders(g As Graphics, x As Integer, y As Integer)
    54. Dim drawText As Action(Of String, Integer) = Sub(s, dx) g.DrawString(s, myfont, Brushes.Black, x + dx, y + 5)
    55. g.FillRectangle(Brushes.LightGray, x + 10, y, 40, 30)
    56. drawText("Pos.", 15)
    57. g.FillRectangle(Brushes.LightGray, x + 52, y, 400, 30)
    58. drawText("Leistung", 240)
    59. g.FillRectangle(Brushes.LightGray, x + 454, y, 65, 30)
    60. drawText("Menge", 462)
    61. g.FillRectangle(Brushes.LightGray, x + 521, y, 55, 30)
    62. drawText("Einheit", 524)
    63. g.FillRectangle(Brushes.LightGray, x + 578, y, 80, 30)
    64. drawText("EP [€]", 600)
    65. g.FillRectangle(Brushes.LightGray, x + 660, y, 80, 30)
    66. drawText("GP [€]", 685)
    67. End Sub
    68. Private Sub DrawGridlines(g As Graphics, x As Integer, y As Integer, hoehe As Single)
    69. g.DrawRectangle(_pnWhite, x + 58, y - 2, _breiteLeistungCol + 4, CInt(hoehe + 2))
    70. Dim dy = If(hoehe > 20, CInt(hoehe + 7), 25)
    71. g.DrawLine(_pnGray, x + 51, y, x + 51, y + dy)
    72. g.DrawLine(_pnGray, x + 453, y, x + 453, y + dy)
    73. g.DrawLine(_pnGray, x + 520, y, x + 520, y + dy)
    74. g.DrawLine(_pnGray, x + 582, y, x + 582, y + dy)
    75. g.DrawLine(_pnGray, x + 664, y, x + 664, y + dy)
    76. g.DrawLine(_pnGray, x + 10, y + dy, x + 739, y + dy)
    77. End Sub

    Dateien

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    noch bischen aufgeräumter:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    2. Dim g = e.Graphics
    3. Dim margin = PrintDocument1.DefaultPageSettings.Margins
    4. Dim X = margin.Left
    5. Dim Y = margin.Top
    6. Dim drawText As Action(Of String, Integer) = Sub(s, dx) g.DrawString(s, myfont, Brushes.Black, X + dx, Y)
    7. If _pageNr = 0 Then
    8. Y += 240 : drawText("Auftragsnummer" & vbTab & vbTab & ":", 10)
    9. Y += 20 : drawText("Bauvorhaben" & vbTab & vbTab & ":", 10)
    10. End If
    11. Y += 80
    12. DrawColumnHeaders(g, Y)
    13. e.HasMorePages = True
    14. Try
    15. For i = _printRow To bsFkAuftragsdetail.Count - 1
    16. Y += 35
    17. Dim row = DirectCast(DirectCast(bsFkAuftragsdetail(i), DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    18. If _printedLeistungChars = 0 Then
    19. 'neu angefangene row: auch die anderen Werte eintragen
    20. If Not row.IsPosNull Then drawText(CStr(row.Pos), 17)
    21. If Not row.IsMengeNull Then drawText(Format(row.Menge, "N2"), 465)
    22. If Not row.IsEinheitNull Then drawText(Format(row.Einheit), 535)
    23. If Not row.IsEinzelpreisNull Then drawText(Format(row.Einzelpreis, "C2"), 603)
    24. If Not row.IsGesamtpreisNull Then drawText(Format(row.Gesamtpreis, "C2"), 668)
    25. End If
    26. Dim sUnprinted = If(row.IsLeistungNull, "", row.Leistung.Substring(_printedLeistungChars))
    27. Dim layoutRect = g.VisibleClipBounds
    28. layoutRect.Offset(X + 60, Y)
    29. layoutRect.Width = 380
    30. layoutRect.Height -= Y
    31. Dim charactersfitted, linesfilled As Integer
    32. Dim sz = g.MeasureString(sUnprinted, myfont, layoutRect.Size, _strformat, charactersfitted, linesfilled)
    33. Dim sPrint = sUnprinted.Substring(0, charactersfitted)
    34. g.DrawString(sPrint, myfont, Brushes.Black, layoutRect, _strformat)
    35. _printedLeistungChars += charactersfitted
    36. Dim hoehe = sz.Height
    37. DrawGridlines(g, Y, hoehe)
    38. If charactersfitted < sUnprinted.Length Then Return ' wenn hier rausspringt wird auf nächster Seite mit selber Row weitergemacht
    39. _printRow += 1
    40. _printedLeistungChars = 0
    41. If hoehe > 20 Then Y += CInt(hoehe) - 20
    42. If Y >= 850 Then Return ' wenn hier rausspringt nächste Seite mit nächster Row
    43. Next
    44. e.HasMorePages = False
    45. Finally
    46. _pageNr += 1
    47. g.DrawString(String.Format(" - Seite {0} -", _pageNr), myfont, Brushes.LightGray, 380, 1130)
    48. End Try
    49. End Sub
    50. Private Sub DrawColumnHeaders(g As Graphics, y As Integer)
    51. Dim X = PrintDocument1.DefaultPageSettings.Margins.Left
    52. g.FillRectangle(Brushes.LightGray, X + 10, y, 40, 30)
    53. g.FillRectangle(Brushes.LightGray, X + 52, y, 400, 30)
    54. g.FillRectangle(Brushes.LightGray, X + 454, y, 65, 30)
    55. g.FillRectangle(Brushes.LightGray, X + 521, y, 55, 30)
    56. g.FillRectangle(Brushes.LightGray, X + 578, y, 80, 30)
    57. g.FillRectangle(Brushes.LightGray, X + 660, y, 80, 30)
    58. Dim drawText As Action(Of String, Integer) = Sub(s, dx) g.DrawString(s, myfont, Brushes.Black, X + dx, y + 5)
    59. drawText("Pos.", 15)
    60. drawText("Leistung", 240)
    61. drawText("Menge", 462)
    62. drawText("Einheit", 524)
    63. drawText("EP [€]", 600)
    64. drawText("GP [€]", 685)
    65. End Sub
    66. Private Sub DrawGridlines(g As Graphics, y As Integer, hoehe As Single)
    67. Dim X = PrintDocument1.DefaultPageSettings.Margins.Left
    68. g.DrawRectangle(_pnWhite, X + 58, y - 2, _breiteLeistungCol + 4, CInt(hoehe + 2))
    69. Dim dy = If(hoehe > 20, CInt(hoehe + 7), 25)
    70. g.DrawLine(_pnGray, X + 51, y, X + 51, y + dy)
    71. g.DrawLine(_pnGray, X + 453, y, X + 453, y + dy)
    72. g.DrawLine(_pnGray, X + 520, y, X + 520, y + dy)
    73. g.DrawLine(_pnGray, X + 582, y, X + 582, y + dy)
    74. g.DrawLine(_pnGray, X + 664, y, X + 664, y + dy)
    75. g.DrawLine(_pnGray, X + 10, y + dy, X + 739, y + dy)
    76. End Sub
    @ErfinderDesRades

    hab die Solution runtergeladen und ausprobiert. Der Seitenwechsel mit fortlaufendem Text klappt.

    VB.NET-Quellcode

    1. layoutRect.Height = e.MarginBounds.Height - Y


    Extremes Danke für die Lösung.

    Danke an alle, die an diesem Thread mitgewirkt haben.
    Fein.
    Ich verwende übrigens auch anonyme Methoden (#6, #60), um den Code kompakt und leserlicher hinzukriegen.
    Kann dir nur empfehlen, dich damit auseinanderzusetzen.

    es sind noch viele weitere Verbesserungen möglich - die wichtigste: Schmeiss den Microsoft.Visualbasic-Import raus.
    Raus damit aus der Datei und raus damit aus den General-Importen.
    Dann umstellen auf OOP-.Net-Programmierung.
    Siehe auch Visual Studio – Empfohlene Einstellungen

    Nächste Aufgabe wäre, von all den vielen "magischen Zahlen" wegzukommen - ist sehr schlechter Stil.
    Im Grunde brauchts nur für jede Spalte eine Breiten-Festlegung - alle anderen Werte müssten sich anhand des Fonts daraus ableiten lassen.
    Dann könnteste die Beschriftungen und die Spaltenbreiten auch mal ändern, oder gar den Font selbst - ohne mit Adlerauge alle Pixels nachjustieren zu müssen.
    @ErfinderDesRades

    werd die Tips versuchen umzusetzen. Der code den ich geschrieben habe ist vom letzten Jahr, bastle schon ziemlich lange dran, immer wieder mal. Und jedes mal wirds ein wenig besser. Bin mit vielem im meiner app noch nicht zu frieden, aber grösstenteils funktioniert sie. Jetzt mit dem drucken bin ich einen grossen schritt weiter.