Problem beim drucken multipler Seiten mit fortlaufendem Text

  • VB.NET

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

    silverbob76GE schrieb:

    Es wird genau ein Textbaustein gedruckt. Aber wie komme ich nun weiter? Kann das alles in eine For-Schleife einbinden, die bindingsoruce durchlaufen.
    Ja, irgendwie schon.
    Aber die For-Schleife darf nicht die ganze bs durchlaufen, sondern immer nur ein Stück - soviel wie auf die Seite noch passt.
    Insgesamt brauchst du einen "KellerAutomaten" (so heisst das glaub), also ein Dingens, was sich seinen Status merkt.
    Dann tut es etwas, ändert den Status - und kann jederzeit unterbrechen und seine Arbeit wieder aufnehmen.
    Weil ein Seitenvorschub ist so eine Unterbrechung.
    Danach muss der "Schreibkopf" umgesetzt werden, die Tabellenheader geschrieben, und dann gehts weiter mit dem RowIndex, an dem unterbrochen wurde.

    Deine Beschreibung des Ausdrucks scheint mir unvollständig. Im Bild sehe ich, dass unter der Tabelle noch was kommt.
    Der "Automat" muss auch das Drucken dieses Teiles unterbrechen können, weil glaub auch dabei kann ein Seitenvorschub auftreten.
    @RodFromGermany, verstehe nicht was du mit

    @silverbob76GE Du hast das mit der BindingSource doch schon gelöst gehabt.
    meinst.
    Mein Problem war ja nie die BindingSoruce, oder ich verstehe gerade was völlig falsch. Anyway.

    Du sagst, in der Prozedur soll ich den verleibenden Platz ausmessen, verstehe ich.
    Mit

    VB.NET-Quellcode

    1. g.MeasureString(sb.ToString(), myfont, S, sf, charactersfitted, linesfilled)
    .

    Das sagt mir, wie viel Platz ich für den Druck meines Strings benötige, richtig?
    Diesen Druckbereich muss ich nun mit dem restlich vorhandenen Druckbereich für die nächste DataRow vergleichen, richtig?

    Mein Druckbereich wäre:

    VB.NET-Quellcode

    1. Dim S as SizeF = New SizeF(380, e.marginbounds-height - Y)


    380 ist die Breite des Druckbereichs, diese ist Fix. Die Höhe des Druckbereichs errechnet sich aus (Blatthöhe - Y-Koordinate). Verständnishalber sagen wir einfach 600.

    Wenn mein zu druckender Text eine Höhe von 700 braucht, erfolgt ein abbruch dort, wo der String das Rechteck (380, 600) gefüllt hat. Ein weiteres Rechteck mit
    (380, 100) muss auf nächster Seite erzeugt werden. Korrekt? Ok, wie kann ich den Druck an der Stelle abbrechen und auf nächster Seite fortführen? Ich weiß es nicht, kein Plan was ich da coden soll.

    Mit e.hasmorepages = indextext < row1.leistung.length wird eine neue Seite erzeugt, aber der Text nicht fortgeführt. Die nächste Seite beginnt mit der neuen DataRow.

    Ich müsste also den zuvor nicht gedruckten Text vor meiner For-Schleife einschieben, richtig? Wie, kein Plan.

    @ErfinderDesRades

    Deine Beschreibung des Ausdrucks scheint mir unvollständig. Im Bild sehe ich, dass unter der Tabelle noch was kommt


    Das ist ein statischer Text, Brieffußzeile, diese wiederholt sich auf jeder Seite. ich will für den Druck meiner Splate "Leistung" einen Druckbereich vorgeben, wenn dieser Druckbereich überschritten wird, soll die nächste Seite anfangen.
    Der Druckbereich hat eine fixe Breite von 380, die Höhe richtet sich nach der Y-Koordinate der DataRow.

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

    silverbob76GE schrieb:

    Das sagt mir, wie viel Platz ich für den Druck meines Strings benötige, richtig?
    Falsch.
    Das sagt Dir, wieviel des Textes in das übergebene Rechteck geschrieben werden kann.
    Verstehe den Code aus Post #19!
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ok, verstehe. Dann müsste ich nun quasi rechnen:

    länge des textes - gedruckter text = noch zu druckender Text auf neuer Seite

    Die länge des gedruckten Texts wird über die Variable TotalCharsPrinted dargestellt.
    Wenn ich nun

    VB.NET-Quellcode

    1. g.DrawString(sb.ToString(indextext, charsFitted), ft, Brushes.Black, e.MarginBounds, sf)

    angebe, dann müsste doch auf der nächsten Seite an der Stelle angefangen werden, wo der Druck vorher aufgehört hat.
    Das wäre ja dann der StartIndex (bei mir als Variable indextext). Diesen setze ich in der For-Schleife aber auf Null, da ich sonst eine Fehlermeldung bekommen.
    StartIndex cannot be larger then length of string.
    Bilder
    • startindex cannot be larger then length of string.png

      124,52 kB, 1.211×816, 49 mal angesehen
    @silverbob76GE Verstehe den Code in Post #19.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    silverbob76GE schrieb:

    Wenn mein zu druckender Text eine Höhe von 700 braucht, erfolgt ein abbruch dort, wo der String das Rechteck (380, 600) gefüllt hat. Ein weiteres Rechteck mit
    (380, 100) muss auf nächster Seite erzeugt werden. Korrekt?
    Nein.
    Dein Fall liegt nämlich anders als die Lösung in post#19.
    Du kannst eine einzelne Tabellen-Zeile doch nicht auf zwei Seiten verteilen.
    Du musst messen: Wieviel Platz braucht diese Tablen-Zelle?
    Und wenns nicht passt muss die ganze Zeile auf die neue Seite.

    Also wenn du dem zustimmst, dann musst du vor allem anders messen: Du musst nicht messen, wieviele Chars meines Zellen-Textes kriege ich in den gegebenen Platz, und den Rest nehme ich rüber.
    Sondern du musst messen: Wieviel Platz braucht mein Zellen-Text, und wenns nicht passt, muss die ganze TableRow rüber.
    Dazu musst du der MeasureString()-Function eine nach unten offene Size als LayoutArea angeben, und der Rückgabewert sagt dir dann wieviel Platz der gesamte ZellenText braucht.
    "nach unten offene Size" gibts nicht wirklich, aber man kann die Höhe sehr gross wählen: Dim layoutArea = new SizeF(380, 32000) - das sollte reichen.
    Wieso das denn? Wenn ich in Word ne Tabelle mache und da eine Tabellenzelle zuviel Text enthält, wird das ja auch nicht alles auf die neue Seite verschoben. Was würde denn passieren, wenn die Row auch nicht alleine auf die Seite passen würde?
    Die Aufteilung des Textes sollte ermöglicht und durchgeführt werden.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Jou.
    Wenn ich will, dass der Textbaustein geteilt wird, wird er halt geteilt.
    Das mit der Texthöhe größer als die Seitenhöhe ist ein gutes Beispiel, und da fällt mir wieder Post #19 ein. ;)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @ErfinderDesRades

    das die komplette gemessen wird und nicht passt, und dann komplett auf neuer seite gedruckt wird, klappt ja schon. Aber dann kanns passieren, das die seite zwei datarow als einzeiler hat und der rest der seite leer ist, weil die dritte rowzeile sehr lang ist. Das will ich ja nicht. Die seite sollte möglichst so voll wie geht gedruckt werden.

    Han noch mal ein Screenshot gemacht. Genau das will ich nicht. Da ist 3/4 der ersten Seite leer.
    Bilder
    • Screenshot2.png

      69,68 kB, 1.341×914, 35 mal angesehen
    • Screenshot3.png

      70,91 kB, 1.354×951, 37 mal angesehen

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

    @RodFromGermany,

    ich arbeite gerade Post 19 durch. jetzt verstehe ich, warum du woltlest das ich erst mal 1 textbaustein drucke. Wenn ich ohne For-Schleife arbeite, also so tue als hätte ich einen Fliesstext, dann wird dieser auch umgebrochen.
    Siehe Screenshot.

    Wenn ich das jetzt richtig einsetze, müsste ich abfragen
    - wann meine DataRow zu lang für den Druck auf einer Seite wird, und dann die Methode für den Druck auf mehreren Seiten wählen.
    - falls nicht, normal drucken.

    Ok, das die Theorie, die du glaub schon zig mal erwähnt hattest. Hab jetzt eine If Abfrage in die Schleife eingebaut. Dabei wird gemessen ob der vorhandene Platz für den Druck auf einer Seite ausreicht oder ob eine zweite bSeite benötigt wird.
    Für die erste Seite funzt das. Wenn ich dann jedoch die Abfrage für die Seiten > 1 einbaue, bekomme ich imer noch die Fehlermeldung "startindex cannot be larger then length of string". Also hab ich iwo noch einen Denkfehler.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    2. 'Seiteränder
    3. Dim margin = PrintDocument1.DefaultPageSettings.Margins
    4. Dim g = e.Graphics
    5. margin.Left = 30
    6. margin.Right = 30
    7. margin.Top = 30
    8. margin.Bottom = 30
    9. leftMargin = margin.Left
    10. rightMargin = margin.Right
    11. topMargin = margin.Top
    12. bottomMargin = margin.Bottom
    13. 'Druckbereich
    14. Dim rc = e.Graphics.VisibleClipBounds
    15. rc.Offset(margin.Left + 30, margin.Top + 30) ' obere linke Ecke
    16. rc.Width -= (margin.Left + 20 + margin.Right - 20) ' neue Breite
    17. rc.Height -= (margin.Top + margin.Bottom) ' neue Höhe
    18. X = leftMargin
    19. Y = topMargin
    20. Dim strformat As New StringFormat(StringFormat.GenericTypographic)
    21. Dim charactersfitted As Integer
    22. Dim linesfilled As Integer
    23. If pagenb = 0 Then
    24. DrawHeader(g)
    25. DrawRectangle(g, brush)
    26. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    27. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    28. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    29. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    30. Dim S As SizeF = New SizeF(380, e.MarginBounds.Height - Y)
    31. Dim B = 380
    32. Dim Hoch As Double = Ausgabenhöhe(S, B)
    33. Using sf As New StringFormat()
    34. ' nur vollständige Zeilen drucken
    35. sf.FormatFlags = StringFormatFlags.LineLimit
    36. ' die noch zu druckenden Zeichen holen
    37. Dim sb As New System.Text.StringBuilder(row1.Leistung.Substring(Me.indextext))
    38. Dim rec As New RectangleF(X + 60, Y + 35, 380, e.MarginBounds.Height - Y)
    39. ' die Anzahl der druckbaren Zeichen bestimmen
    40. g.MeasureString(sb.ToString(), myfont, S, sf, charactersfitted, linesfilled)
    41. If indextext < row1.Leistung.Length Then
    42. g.DrawString(sb.ToString(0, charactersfitted), myfont, Brushes.Black, rec, sf)
    43. DrawHoch(g, pen1, Hoch:=CInt(myfont.GetHeight * linesfilled + 30))
    44. index += 1
    45. e.HasMorePages = True
    46. Me.indextext += charactersfitted
    47. pagenb += 1
    48. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    49. Return
    50. Else
    51. DrawRow1Info(g, pen3, strformat, row1, rec, Hoch, B, charactersfitted)
    52. End If
    53. End Using
    54. Next
    55. End If
    56. If pagenb >= 1 Then
    57. DrawRectangle(g, brush)
    58. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    59. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    60. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    61. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    62. Dim S As SizeF = New SizeF(380, e.MarginBounds.Height - Y)
    63. Dim B = 380
    64. Dim Hoch As Double = Ausgabenhöhe(S, B)
    65. Using sf As New StringFormat()
    66. ' nur vollständige Zeilen drucken
    67. sf.FormatFlags = StringFormatFlags.LineLimit
    68. ' die noch zu druckenden Zeichen holen
    69. Dim sb As New System.Text.StringBuilder(row1.Leistung.Substring(Me.indextext))
    70. Dim rec As New RectangleF(X + 60, Y + 35, 380, e.MarginBounds.Height - Y)
    71. ' die Anzahl der druckbaren Zeichen bestimmen
    72. g.MeasureString(sb.ToString(), myfont, S, sf, charactersfitted, linesfilled)
    73. If indextext < row1.Leistung.Length Then
    74. g.DrawString(sb.ToString(0, charactersfitted), myfont, Brushes.Black, rec, sf)
    75. DrawHoch(g, pen1, Hoch:=CInt(myfont.GetHeight * linesfilled + 30))
    76. e.HasMorePages = True
    77. index += 1
    78. Me.indextext += charactersfitted
    79. pagenb += 1
    80. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    81. Return
    82. Else
    83. indextext = 0
    84. DrawRow1Info(g, pen3, strformat, row1, rec, Hoch, B, charactersfitted)
    85. e.HasMorePages = indextext < row1.Leistung.Length
    86. index += 1
    87. pagenb += 1
    88. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    89. Return
    90. End If
    91. End Using
    92. Next
    93. End If
    94. End Sub


    @silverbob76GE Poste mal so viel Code und kommunizierende Daten, dass ich das genau so nachvollziehen kann.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Hab die Anwendung ohne obj und bin gezippt. Ist nbe xml drin, die au fden desktop muss.

    Der Fehler kommt in der If Anweisung, bei "Dim sb as New System.Text.StringBuilder(row1.leistung.Substring(Me.indextext))"

    VB.NET-Quellcode

    1. If pagenb >= 1 Then
    2. DrawRectangle(g, brush)
    3. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    4. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    5. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    6. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    7. Dim S As SizeF = New SizeF(380, e.MarginBounds.Height - Y)
    8. Dim B = 380
    9. Dim Hoch As Double = Ausgabenhöhe(S, B)
    10. Using sf As New StringFormat()
    11. ' nur vollständige Zeilen drucken
    12. sf.FormatFlags = StringFormatFlags.LineLimit
    13. ' die noch zu druckenden Zeichen holen
    14. Dim sb As New System.Text.StringBuilder(row1.Leistung.Substring(Me.indextext))
    15. Dim rec As New RectangleF(X + 60, Y + 35, 380, e.MarginBounds.Height - Y)
    16. ' die Anzahl der druckbaren Zeichen bestimmen
    17. g.MeasureString(sb.ToString(), myfont, S, sf, charactersfitted, linesfilled)
    18. If indextext < row1.Leistung.Length Then
    19. g.DrawString(sb.ToString(0, charactersfitted), myfont, Brushes.Black, rec, sf)
    20. DrawHoch(g, pen1, Hoch:=CInt(myfont.GetHeight * linesfilled + 30))
    21. e.HasMorePages = True
    22. index += 1
    23. Me.indextext += charactersfitted
    24. pagenb += 1
    25. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    26. Return
    27. Else
    28. indextext = 0
    29. DrawRow1Info(g, pen3, strformat, row1, rec, Hoch, B, charactersfitted)
    30. e.HasMorePages = indextext < row1.Leistung.Length
    31. index += 1
    32. pagenb += 1
    33. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    34. Return
    35. End If
    36. End Using
    37. Next
    38. End If

    Dateien
    • WindowsApp1.zip

      (45,23 kB, 44 mal heruntergeladen, zuletzt: )

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

    @silverbob76GE Wir wollten doch eine in sich geschlossene Routine schreiben, die einen kompletten Textbaustein druckt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany,

    das hab ich auch gemacht und einen screenshot in Post 50 geposted. Der Textbaustein klappt mit dem Code aus Post 19 wunderbar.
    Hab mir gedacht, das ich dann das in eine For-Schleife einbinden muss, in der abgefragt wird wie viel Platz da ist.
    Erst nach dieser Prüfung soll entschieden werden, welcher Druckvorgang ausgelöst wird. Hab den screenshot noch mal angehängt. Fortlaufender Druck über 2 Seiten.
    Bilder
    • Screenshot3.png

      70,91 kB, 1.354×951, 43 mal angesehen
    @silverbob76GE Da Di offensichtlich Dein Problem vollständig gelöst hast, bedarfst Du ja meiner Hilfe nicht mehr.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    das wäre schön, sowiet bin ich leider nicht. Wie ich vorher schon geschrieben habe, bekomme ich immer ne Fehlermeldung "startindex cannot be larger then length of string". Der einzelne Textbaustein klappt. Ich hatte daher ja auch die Solution gezippt und angehängt, damit man das besser nachvollziehen kann.Wei0 nicht was ich falsch mache.
    naja, mit bs.MoveNext betrittst du eine neue Row - die wohl einen kürzeren Leistung-Text hat.
    indexText scheinst du aber nicht zurückzusetzen, daher ist dieser index zu gross - das sagt jdfs. der Fehler.

    Deine Anwendung bringt nicht sooo viel, weil sind ja keine Daten da zum Drucken - insbesondere keine, die den Fehler reproduzieren.

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

    @ErfinderDesRades

    mit bs.movenext muss ich eine neue DataRow betreten, sonst werden die nächsten DataRow ja ncht gedruckt.

    Wenn ich indeText zurücksetze, wird der restliche Text von Seite 1 nicht zu Ende gedruckt, der Druck geht dann mit der neuen DataRow los.
    Wenn ich den nicht zrücksetze, kommt die Fehlermeldung => "startindex cannot be larger then length of string".
    Drehe mich iwie im Kreis.

    @RodFromGermany

    @silverbob76GE Wir wollten doch eine in sich geschlossene Routine schreiben, die einen kompletten Textbaustein druckt.


    Das habe ich auch hinbekommen, dank deines Code in Pos 19 klappts. Allerdings ist das auch nur ein Textbaustein, also eine DataRow.
    Ich brauche aber eine For-Schleife, damit ich die restlichen DataRow durchlaufen kann. Sobald ich die einbinde, bekomme ich beim drucken des restlichen Texts von Seite 1 auf Seite 2 Probleme, wie oben beschrieben.
    "StartIndex cannot be larger then length of string". Das hat was mit der Variable indexText zu tun.



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