Problem beim drucken multipler Seiten mit fortlaufendem Text

  • VB.NET

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

    Problem beim drucken multipler Seiten mit fortlaufendem Text

    Hi Leute

    bin seit Tagen dabei eine Lösung für mein Problem zu finden, leider ohne Erfolg.

    Ich versuche eine Rechnung als PDF zu drucken. Die Rechnung ist in mehreren Seiten und aufgebaut, die Rechnungspositionen werden tabellarisch dargestellt.

    Page 1 => Rechnungskopf, kurzer Text, und dann die Rechnungsaufstellung, ggf. Seitenende falls nichts mehr zu drucken da ist und genügend Platz vorhanden
    Page 2 => fortlaufende Rechnungsaufstellung, ggf. Seitenende falls nichts mehr zu drucken da ist und genügend Platz vorhanden

    Die Daten für die Rechnung habe ich in einem typisierten Dataset.

    Beim drucken der entsprechenden Datarow kann es vorkommen, das eine DataColumn sehr langen text hat, der nicht mehr auf die Seite passt und daher einen Seitenwechsel erfolgt. Das klappt auch alles wunderbar.
    Leider wird der text nicht an der Stelle fortgeführt, an der aufgehört wurde. Der Druck läuft dann mit der nächsten zu druckenden DataRow weiter. Hab mir auch noch mal das Tutorial von @RodFromGermany vorgenommen.
    Leider weiß ich nicht, wie ich die For-Schleife unterbrechen und dann auf nächster Seite an der korrekten Stelle weiterdrucken soll. Ich bekomme es hin, das die zunächst zu drukende DataRow kompett auf einer zusammenhängend gedruckt wird. Das bedeutet aber auch, das die jeweilige Seite zur hälfte leer sein kann, wenn der text zu lang wird. Ist vermutlich nicht der eleganteste Code, aber bis auf dieses Prob funktionierts.

    Hier mal mein Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Private Sub PrintDocument1_PrintPage(sender As Object, e As PrintPageEventArgs) Handles PrintDocument1.PrintPage
    2. Dim margin = PrintDocument1.DefaultPageSettings.Margins
    3. Dim g = e.Graphics
    4. Dim brush As New SolidBrush(Color.LightGray)
    5. Dim brush1 As New SolidBrush(Color.Black)
    6. Dim pen1 As New Pen(Brushes.LightGray, 0.5)
    7. Dim pen2 As New Pen(Brushes.DarkGray, 0.5)
    8. Dim pen3 As New Pen(Brushes.White, 0.5)
    9. Dim LineHeight As Single = Me.myfont.GetHeight
    10. margin.Left = 30
    11. margin.Right = 30
    12. margin.Top = 30
    13. margin.Bottom = 30
    14. leftMargin = margin.Left
    15. rightMargin = margin.Right
    16. topMargin = margin.Top
    17. bottomMargin = margin.Bottom
    18. Dim rc = e.Graphics.VisibleClipBounds
    19. rc.Offset(margin.Left + 30, margin.Top + 30) ' obere linke Ecke
    20. rc.Width -= (margin.Left + 20 + margin.Right - 20) ' neue Breite
    21. rc.Height -= (margin.Top + margin.Bottom) ' neue Höhe
    22. Dim zeile = DirectCast(DirectCast(CompanyBindingSource.Current, DataRowView).Row, DtsFirma.CompanyRow)
    23. X = leftMargin
    24. Y = topMargin
    25. Dim strformat As New StringFormat(StringFormatFlags.LineLimit)
    26. Dim charactersfitted As Integer
    27. Dim linesfilled As Integer
    28. If pagenb = 0 Then
    29. Y += 240
    30. g.DrawString(KundeComboBox.Text, myfontbold, Brushes.Black, X + 10, Y + 10)
    31. Y += 30
    32. g.DrawString(StrasseTextBox.Text & vbCrLf & PLZTextBox.Text & " " & StadtTextBox.Text, myfont, Brushes.Black, X + 10, Y)
    33. Y += 50
    34. g.DrawString(Format(AuftragsdatumDateTimePicker.Value.ToShortDateString), myfontbold, Brushes.Black, X + 650, Y)
    35. Y += 50
    36. g.DrawString("Auftragsnummer" & vbTab & vbTab & ":", myfontbold, Brushes.Black, X + 10, Y)
    37. If DtsAufträge.Auftragsübersicht.Rows.Count > 0 Then
    38. g.DrawString(AuftragsnummerTextBox.Text, myfont, Brushes.Black, X + 200, Y)
    39. Else
    40. g.DrawString("", myfont, Brushes.Black, X + 200, Y)
    41. End If
    42. Y += 20
    43. g.DrawString("Bauvorhaben" & vbTab & vbTab & ":", myfontbold, Brushes.Black, X + 10, Y)
    44. g.DrawString(BauvorhabenTextBox.Text, myfont, Brushes.Black, X + 200, Y)
    45. Y += 20
    46. If ZahlungsbedingungenTextBox.Text <> "" Then
    47. g.DrawString("Zahlungsbedingungen" & vbTab & ":", myfontbold, Brushes.Black, X + 10, Y)
    48. g.DrawString(ZahlungsbedingungenTextBox.Text, myfont, Brushes.Black, X + 200, Y)
    49. End If
    50. Y += 50
    51. If AnredeTextBox.Text = "Herr" Then
    52. g.DrawString("Sehr geehrter Herr " & AnsprechpartnerTextBox.Text & "," & vbCrLf & "für Ihren Auftrag bedanken wir uns und berechnen für unsere Leistungen wie folgt:", myfont, Brushes.Black, X + 10, Y)
    53. ElseIf AnredeTextBox.Text = "Frau" Then
    54. g.DrawString("Sehr geehrte Frau " & AnsprechpartnerTextBox.Text & "," & vbCrLf & "für Ihren Auftrag bedanken wir uns und berechnen für unsere Leistungen wie folgt:", myfont, Brushes.Black, X + 10, Y)
    55. ElseIf AnredeTextBox.Text = "" Then
    56. g.DrawString("Sehr geehrte Damen und Herren," & vbCrLf & "für Ihren Auftrag bedanken wir uns und berechnen für unsere Leistungen wie folgt:", myfont, Brushes.Black, X + 10, Y)
    57. End If
    58. Y += 50
    59. g.FillRectangle(brush, X + 10, Y, 40, 30)
    60. g.DrawString("Pos.", myfontbold, Brushes.Black, X + 15, Y + 5)
    61. g.FillRectangle(brush, X + 52, Y, 400, 30)
    62. g.DrawString("Leistung", myfontbold, Brushes.Black, X + 240, Y + 5)
    63. g.FillRectangle(brush, X + 454, Y, 65, 30)
    64. g.DrawString("Menge", myfontbold, Brushes.Black, X + 462, Y + 5)
    65. g.FillRectangle(brush, X + 521, Y, 55, 30)
    66. g.DrawString("Einheit", myfontbold, Brushes.Black, X + 524, Y + 5)
    67. g.FillRectangle(brush, X + 578, Y, 80, 30)
    68. g.DrawString("EP [€]", myfontbold, Brushes.Black, X + 600, Y + 5)
    69. g.FillRectangle(brush, X + 660, Y, 80, 30)
    70. g.DrawString("GP [€]", myfontbold, Brushes.Black, X + 685, Y + 5)
    71. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    72. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    73. Dim an = g.VisibleClipBounds
    74. an.Offset(X + 60, Y + 35)
    75. an.Width = 380
    76. an.Height = Y + (charactersfitted * linesfilled)
    77. Dim S As SizeF
    78. Dim Hoch As Double
    79. Dim B = 380
    80. indextext = 0
    81. S = g.MeasureString(row1.Leistung.Substring(indextext), myfont, an.Size, strformat, charactersfitted, linesfilled)
    82. Hoch = Ausgabenhöhe(S, B)
    83. If Y + (linesfilled * myfont.GetHeight) > 850 Then
    84. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    85. e.HasMorePages = True
    86. pagenb += 1
    87. Exit Sub
    88. Else
    89. If Not row1.IsLeistungNull Then
    90. g.DrawString(row1.Leistung.Substring(indextext), myfont, Brushes.Black, an, strformat)
    91. End If
    92. End If
    93. If Not row1.IsPosNull Then
    94. g.DrawString(CStr(row1.Pos), myfontbold, Brushes.Black, X + 17, Y + 35)
    95. End If
    96. Dim drawrect As New RectangleF(X + 60, Y + 35, B, CInt(Hoch))
    97. g.DrawRectangle(pen3, X + 58, Y + 33, CInt(B + 4), CInt(Hoch + 2))
    98. If Not row1.IsMengeNull Then
    99. g.DrawString(Format(row1.Menge, "N2"), myfont, Brushes.Black, X + 460, Y + 35)
    100. End If
    101. If Not row1.IsEinheitNull Then
    102. g.DrawString(Format(row1.Einheit), myfont, Brushes.Black, X + 530, Y + 35)
    103. End If
    104. If Not row1.IsEinzelpreisNull Then
    105. g.DrawString(Format(row1.Einzelpreis, "C2"), myfont, Brushes.Black, X + 598, Y + 35)
    106. End If
    107. If Not row1.IsGesamtpreisNull Then
    108. g.DrawString(Format(row1.Gesamtpreis, "C2"), myfont, Brushes.Black, X + 663, Y + 35)
    109. End If
    110. If Hoch > 20 Then
    111. Y += 35
    112. g.DrawLine(pen1, X + 51, Y, X + 51, Y + CInt(Hoch + 7))
    113. g.DrawLine(pen1, X + 453, Y, X + 453, Y + CInt(Hoch + 7))
    114. g.DrawLine(pen1, X + 520, Y, X + 520, Y + CInt(Hoch + 7))
    115. g.DrawLine(pen1, X + 577, Y, X + 577, Y + CInt(Hoch + 7))
    116. g.DrawLine(pen1, X + 659, Y, X + 659, Y + CInt(Hoch + 7))
    117. g.DrawLine(pen1, X + 10, Y + CInt(Hoch + 7), X + 739, Y + CInt(Hoch + 7))
    118. Y += CInt(Hoch) - 20
    119. End If
    120. If Hoch < 20 Then
    121. Y += 35
    122. g.DrawLine(pen1, X + 51, Y, X + 51, Y + 25)
    123. g.DrawLine(pen1, X + 453, Y, X + 453, Y + 25)
    124. g.DrawLine(pen1, X + 520, Y, X + 520, Y + 25)
    125. g.DrawLine(pen1, X + 577, Y, X + 577, Y + 25)
    126. g.DrawLine(pen1, X + 659, Y, X + 659, Y + 25)
    127. g.DrawLine(pen1, X + 10, Y + 25, X + 739, Y + 25)
    128. End If
    129. index += 1
    130. indextext += charactersfitted
    131. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    132. If Y >= 850 Then
    133. e.HasMorePages = True
    134. pagenb += 1
    135. Exit Sub
    136. End If
    137. Next
    138. If Y >= 850 Then
    139. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    140. e.HasMorePages = True
    141. pagenb += 1
    142. Exit Sub
    143. Else
    144. Dim rectnetto = New RectangleF(X + 655, Y + 50, 85, Height)
    145. Dim rectmwst = New RectangleF(X + 655, Y + 72, 85, Height)
    146. Dim rectskonto = New RectangleF(X + 655, Y + 92, 85, Height)
    147. Dim rectbrutto = New RectangleF(X + 655, Y + 112, 85, Height)
    148. g.DrawString("Netto" & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    149. g.DrawString(tbNetto.Text, myfont, Brushes.Black, rectnetto, _sfright)
    150. g.DrawLine(pen2, X + 550, Y + 68, X + 740, Y + 68)
    151. Y += 20
    152. g.DrawString("MwSt." & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    153. g.DrawString(tbMwst.Text, myfont, Brushes.Black, rectmwst, _sfright)
    154. g.DrawLine(pen2, X + 550, Y + 68, X + 740, Y + 68)
    155. Y += 20
    156. g.DrawString("Skonto" & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    157. g.DrawString(tbSkontobetrag.Text, myfont, Brushes.Black, rectskonto, _sfright)
    158. Y += 20
    159. g.DrawString("Brutto" & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    160. g.DrawString(tbBrutto.Text, myfont, Brushes.Black, rectbrutto, _sfright)
    161. g.DrawLine(pen2, X + 550, Y + 68, X + 740, Y + 68)
    162. g.DrawLine(pen2, X + 550, Y + 70, X + 740, Y + 70)
    163. e.HasMorePages = False
    164. End If
    165. End If
    166. Y += 80
    167. If pagenb >= 1 Then
    168. X = leftMargin
    169. Y = topMargin
    170. Y += 30
    171. indextext = charactersfitted
    172. If index = FKAuftragsübersichtAuftragsdetailBindingSource.Count Then
    173. Else
    174. g.FillRectangle(brush, X + 10, Y, 40, 30)
    175. g.DrawString("Pos.", myfontbold, Brushes.Black, X + 15, Y + 5)
    176. g.FillRectangle(brush, X + 51, Y, 400, 30)
    177. g.DrawString("Leistung", myfontbold, Brushes.Black, X + 240, Y + 5)
    178. g.FillRectangle(brush, X + 453, Y, 65, 30)
    179. g.DrawString("Menge", myfontbold, Brushes.Black, X + 462, Y + 5)
    180. g.FillRectangle(brush, X + 519, Y, 60, 30)
    181. g.DrawString("Einheit", myfontbold, Brushes.Black, X + 528, Y + 5)
    182. g.FillRectangle(brush, X + 580, Y, 80, 30)
    183. g.DrawString("EP [€]", myfontbold, Brushes.Black, X + 600, Y + 5)
    184. g.FillRectangle(brush, X + 661, Y, 80, 30)
    185. g.DrawString("GP [€]", myfontbold, Brushes.Black, X + 685, Y + 5)
    186. End If
    187. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    188. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    189. Dim S As SizeF
    190. Dim Hoch As Double
    191. Dim B = 380
    192. Dim drawrect As New RectangleF(X + 60, Y + 35, B, CSng(Hoch))
    193. Dim an = g.VisibleClipBounds
    194. an.Offset(X + 60, Y + 35)
    195. S = g.MeasureString(row1.Leistung, myfont, B)
    196. Hoch = Ausgabenhöhe(S, B)
    197. an.Width = 380
    198. an.Height = CInt(Hoch)
    199. If Y >= 850 Then
    200. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    201. e.HasMorePages = True
    202. pagenb += 1
    203. Exit Sub
    204. Else
    205. If Not row1.IsLeistungNull Then
    206. g.DrawString(row1.Leistung.Substring(indextext), myfont, Brushes.Black, an, strformat)
    207. End If
    208. End If
    209. If Not row1.IsPosNull Then
    210. g.DrawString(CStr(row1.Pos), myfontbold, Brushes.Black, X + 17, Y + 35)
    211. End If
    212. g.DrawRectangle(pen3, X + 58, Y + 33, CInt(B + 4), CInt(Hoch + 2))
    213. If Not row1.IsMengeNull Then
    214. g.DrawString(Format(row1.Menge, "N2"), myfont, Brushes.Black, X + 465, Y + 35)
    215. End If
    216. If Not row1.IsEinheitNull Then
    217. g.DrawString(Format(row1.Einheit), myfont, Brushes.Black, X + 535, Y + 35)
    218. End If
    219. If Not row1.IsEinzelpreisNull Then
    220. g.DrawString(Format(row1.Einzelpreis, "C2"), myfont, Brushes.Black, X + 603, Y + 35)
    221. End If
    222. If Not row1.IsGesamtpreisNull Then
    223. g.DrawString(Format(row1.Gesamtpreis, "C2"), myfont, Brushes.Black, X + 668, Y + 35)
    224. End If
    225. index = i + 1
    226. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    227. If Y >= 850 Or indextext < charactersfitted Then
    228. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    229. e.HasMorePages = True
    230. pagenb += 1
    231. Exit Sub
    232. End If
    233. Next
    234. Y += 30
    235. If Y >= 850 Then
    236. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    237. e.HasMorePages = True
    238. pagenb += 1
    239. Exit Sub
    240. Else
    241. Dim rectnetto = New RectangleF(X + 655, Y + 50, 85, Height)
    242. Dim rectmwst = New RectangleF(X + 655, Y + 72, 85, Height)
    243. Dim rectskonto = New RectangleF(X + 655, Y + 92, 85, Height)
    244. Dim rectbrutto = New RectangleF(X + 655, Y + 112, 85, Height)
    245. g.DrawString("Netto" & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    246. g.DrawString(tbNetto.Text, myfont, Brushes.Black, rectnetto, _sfright)
    247. g.DrawLine(pen2, X + 550, Y + 68, X + 740, Y + 68)
    248. Y += 20
    249. g.DrawString("MwSt." & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    250. g.DrawString(tbMwst.Text, myfont, Brushes.Black, rectmwst, _sfright)
    251. g.DrawLine(pen2, X + 550, Y + 68, X + 740, Y + 68)
    252. Y += 20
    253. g.DrawString("Skonto" & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    254. g.DrawString(tbSkontobetrag.Text, myfont, Brushes.Black, rectskonto, _sfright)
    255. Y += 20
    256. g.DrawString("Brutto" & vbTab & "[€]", myfontbold, Brushes.Black, X + 550, Y + 50)
    257. g.DrawString(tbBrutto.Text, myfont, Brushes.Black, rectbrutto, _sfright)
    258. g.DrawLine(pen2, X + 550, Y + 68, X + 740, Y + 68)
    259. g.DrawLine(pen2, X + 550, Y + 70, X + 740, Y + 70)
    260. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    261. e.HasMorePages = False
    262. End If
    263. End If
    264. End Sub



    aufgrund des Codeumfangs Spoiler hinzugefügt ~VaporiZed

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

    Du solltest im PrintPage-EventHandler mit z.B. e.Graphics.MeasureString erstmal rausfinden, wie groß Dein Text ist. Das tust Du schon. Gut. Sobald Du feststellst, dass er zu groß für den Rest der Seite ist, musst Du den String aufsplitten und auf der nächsten Seite weiterführen. Das heißt aber auch, dass Du nicht mit dem Inhalt der DataRow direkt arbeiten kannst, sondern den String/Text ggf. aufteilen müsstest.
    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.
    @VaporiZed, danke das du dir die Zeit nimmst.

    Sowas hatte ich bereits befürchtet, ich weiß allerdings nicht wie. Den String kann ich mit e.graphics.measurestring messen, ist auch im code enthalten. Hatte gehofft, das ich den Text an gleicher stelle auf nächster Seite fortführen kann. @RodFromGermany hatte das in seinem Tutorial behandelt, allerdings war dort die Quelle eine RichTextBox wenn ich nicht falsch liege.

    Die zu druckende Datarow bzw. Zelle kenne ich ja. Greife darauf typisiert zu. Soll ich den Text aus der DataRow

    - zwischenspeichern
    - Länge messen
    - wenn zu lang, den anteiliegen Text auf die aktuelle Seite, Rest auf nächste Seite schreiben?

    Hast du einen Ansatz wie ich das anstellen könnte?

    Danke vorweg.
    @silverbob76GE Erstell ein Demo-Projekt mit zufälligen Daten, die Deinen Effekt auslösen.
    Überzeuge Dich davon, dass dieses Demo-Projekt compiliert und Deinen Effekt reproduziert.
    Zippe das Projekt ohne obj, bin- und .vs-Ordner und hänge es an einen Post an.
    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!
    Letztenendes wird es darauf hinauslaufen, dass Du Dir eine Funktion machst, die Dir zurückgibt, wieviel von einem Text bei einer bestimmten Schrift in ein bestimmtes Rechteck reinpasst. Schau Dir dazu die Überladungen von MeasureString mal an. Es gibt zwar was passendes, allerdings erhältst Du als Ergebnis nur für die Texthöhe einen Wert zwischen tatsächlicher Texthöhe (wenn diese kleiner als die Rechteckshöhe ist) und der Rechteckshöhe selbst. Bei letzterem wird der Text wohl zuviel sein und Du musst den Text aufspalten.
    Ich find das Drucken sehr flexibel, aber aufgrund der Tatsache, dass man überall zu jeden Zeitpunkt des PrintPage-EventHandlers Dinge irgendwo auf dem Blatt platzieren kann auch schwer zu steuern. Als kleinen Punkt hab ich für mich daher mal festgelegt, dass ich in dem EventHandler nur schreibe:

    VB.NET-Quellcode

    1. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    2. If CurrentPageIndex = 0 Then PrintFirstPage(e)
    3. If CurrentPageIndex > 0 Then PrintFurtherPages(e)
    4. If PrintLastPage Then PrintLastPage(e) 'falls es eine Abschlusseite gibt
    5. End Sub

    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.

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

    Hallo Leute

    werde morgen das Demo-Projekt erstellen und hochladen. Wie schon gesagt, klappt das drucken. Aber halt nicht gesplittet. Hab die Seiten zwar aufgeteilt in page 1, page 2, aber daran liegts ja nicht. Wenn ich in der For schleife stecke und die datarow drucke muss ich wenn die seite voll ist, eine neue seite erzeugen und nach der zuletzt gedruckten stelle weiterdrucken. Und da weiss ich halt nicht wie. Hoffe ihr habt nen Ansatz. Werde mich da morgen ran setzen.
    Hi

    hab ein demo projekt erstellt und as projekt gezippt. Habs getestet. Für die app wird eine xml datei benötigt, die auf dem desktop liegen sollte. Hab ich dabei gepackt.
    Hoffe das mir jemand helfen kann.
    Dateien
    • WindowsApp1.zip

      (43,98 kB, 52 mal heruntergeladen, zuletzt: )
    @silverbob76GE Du musst noch ein paar HAusaufgaben erledigen.
    Räume Deinen Code auf, keine Spagetti-Monster-Prozeduren mit redundantem Code:
    Lerne dies:
    Markiere einen in sich geschlossenen Quelltext, Bearbeiten => Umgestalten => Methode extrahieren;
    Generiere Testdaten, die das übliche Muster sprengen.
    Sorge dafür, dass überhaupt alles sichtbar ist, erkenne, dass der Text die Seite verlässt.
    Vergleiche Deine Dateien mit meinen.
    auftragsübersicht.zip
    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, ich erkenn im Resultat jetzt keinen Unterschied. Daten zu generieren, die das Muster sprengen, sind m.E. vorhanden oder ich versteh das Ziel nicht. Anbei Istwert und vermuteter Sollwert (Bildbearbeitung, kein Coderesultat!). Das muss aber der TE präzisieren.
    Bilder
    • Istwert.png

      49,67 kB, 1.271×922, 64 mal angesehen
    • Sollwert.png

      47,19 kB, 1.271×922, 58 mal angesehen
    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.

    VaporiZed schrieb:

    Daten zu generieren, die das Muster sprengen, sind m.E. vorhanden oder ich versteh das Ziel nicht.
    Ich meine so was:
    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!
    Hi Leute

    das was @RodFromGermany im letzten Post im Bild zeigt, hatte ich vorher und kam nicht weiter. Werde ich nachstellen und das Projekt neu hochladen. Bei mir lief der Text bis Seitenende, wurde aber auf der Folgeseite nicht fortgeführt. Auf der neuen Seite wurde mit der nächsten DataRow fortgeführt. Hab dann einen Weg gefunden, die nächste DataRow auf der neuen Seite zu drucken, aber da kann es halt passieren, das eine Seite zur hälfte leer bleibt, was ja nicht so schön ist auf Paper.

    Vielen Dank für den Tip @RodFromGermany, werde den Code aufräumen, gab viele Stolpersteine die ich nicht anders in den Griff bekommen habe und irgendwann nicht mehr sicher war, was zu viel oder überflüssig ist. Bin leider immer noch ein Anfänger, aber versuche immer wieder dran zu arbeiten. Werde mir deinen Code vornehmen und versuchen zu verstehen, wie das funktioniert.

    @VaporiZed, Ziel ist, das ich den Seitenplatz so gut es geht ausnutze und dann erst mit einer neuen Seite anfange. In der oben angehängtn Solution wird geprüft, ob die DataRow zu lang ist. Wenn ja, wird der Druck auf der nächsten Seite fortgeführt. Das ist halt nicht so schön. Danke an euch beiden, das Ihr euch die Zeit dafür nehmt, würde das alleine never schaffen.

    silverbob76GE schrieb:

    wurde aber auf der Folgeseite nicht fortgeführt.
    Ich erwarte von Dir, dass Du mit e.Graphics.MeasureString() erkennst, dass das Papier nicht reicht und dann sofort die nächste Seite bedruckst.
    Wenn das läuft, drucken wir auch halbe Absätze.
    Nur: MeasureString() sollte in Deinem Code vorkommen und ausgewertet werden.
    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!
    Hallo silverbob76GE

    Ich habe Respekt vor deinem Code. Es braucht sehr viel Vorstellungsvermögen so die Druckausgabe Pixel für Pixel zu gestalten. Ich selber würde das mit einem RDLC Report erledigen. Der Grund ist, wenn Du in 2 Jahren irgend etwas abändern willst, wird es wohl sehr aufwändig sein.

    Ich muss zwar zugeben, ich wüsste auch bei RDLC Berichten nicht, ob man den Text unterbrechen kann. Ich gehe davon aus, dass er auf der nächsten Seite vollständig angezeigt wird.

    Mann kann aber PDF's erstellen, ich denke die meisten Kunden wollen heute ja die Rechnungen per Mail - natürlich könntest Du auch via PDF Drucker etwas basteln.

    Falls Du noch nichts mit Berichten gemacht hast, siehe hier: https://www.vb-paradise.de/index.php/Thread/98333-ReportViewer-Tutorial-f%C3%BCr-Anf%C3%A4nger/

    lg Panter

    Hallo @RodFromGermany

    RodFromGermany schrieb:

    Ich erwarte von Dir, dass Du mit e.Graphics.MeasureString() erkennst, dass das Papier nicht reicht und dann sofort die nächste Seite bedruckst.


    Ich habe deinen Code übernommen und auch Code extrahiert, so wie du geschrieben hast. Allerdings hänge ich noch an der Stelle, das der Druck zwar funzt, aber nicht halbe Absätze geschrieben und auf der nächste Seite fortgeführt werden. Ich kann die Datarow abbrechen und auf der nächste Seite fortführe, siehe Bild . Ich kann auch den text durchlaufen lassen, siehe Bild 2.

    Im Code ist e.graphics.measurestring entahlten, und dieser misst ja auch die entsprechende Zeile. Aber egeal was ich mache, entweder wird die komplette Zeile auf der nächsten Seite gedruckt, oder der Druck läuft bis Seitenende, wird aber nicht fortgeführt.
    Wie kann ich messen, das zuvor gedruckte Zeilen + die aktuell zu druckende Zeile nur maximal X Zeichen haben darf. Wenn X überschritten, neue Seite beginnen und Druck fortführen.

    @Panter, habe noch nicht darüber nachgedacht. Hab mich für diese Methode entschieden, erschien mir anfangs logischer. Und hab nun auch zu viel Zeit reingesteckt, jetzt will ich es auch hinbekommen.
    By the way, pixel für pixel, leider. War sehr zeitaufwendig, aber denke das geht bestimmt viel eleganter.
    Bilder
    • Bild 1.jpg

      1,06 MB, 1.856×896, 46 mal angesehen
    • Bild 2.jpg

      767,45 kB, 1.876×794, 48 mal angesehen

    silverbob76GE schrieb:

    wird aber nicht fortgeführt.
    Das mache ich Dir, wenn Du richtig erkennst, dass der Text zu lang ist und Du vorher diese Seite abbrichst.
    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!
    Um ehrlich zu sein, weiß ich nicht weiter. Ich habe:

    Anbei der Code für Pagenb = 0

    VB.NET-Quellcode

    1. If pagenb = 0 Then
    2. Dim rc = e.Graphics.VisibleClipBounds
    3. rc.Offset(margin.Left + 30, margin.Top + 30) ' obere linke Ecke
    4. rc.Width -= (margin.Left + 20 + margin.Right - 20) ' neue Breite
    5. rc.Height -= (margin.Top + margin.Bottom) ' neue Höhe
    6. DrawHeader(g)
    7. DrawRectangle(g, brush)
    8. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    9. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    10. Dim an = g.VisibleClipBounds
    11. an.Offset(X + 60, Y + 35)
    12. an.Width = 380
    13. Dim B = 380
    14. indextext = 0
    15. Dim S As SizeF = g.MeasureString(row1.Leistung.Substring(indextext), myfont, an.Size, strformat, charactersfitted, linesfilled)
    16. Dim Hoch As Double = Ausgabenhöhe(S, B)
    17. an.Height = CInt(Hoch)
    18. Dim textblock As SizeF = e.Graphics.MeasureString(row1.Leistung.Substring(indextext), myfont, an.Size, strformat, charactersfitted, linesfilled)
    19. Dim currentheight = Y + (myfont.GetHeight * linesfilled)
    20. If currentheight + textblock.Height > rc.Height Then
    21. e.HasMorePages = True
    22. pagenb += 1
    23. Return
    24. Else
    25. DrawRow1Info(g, pen3, strformat, row1, an, Hoch, B)
    26. DrawHoch(g, pen1, Hoch)
    27. index += 1
    28. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    29. End If
    30. Next
    31. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    32. e.HasMorePages = False
    33. End If
    @silverbob76GE Poste bitte vollständige Prozeduren.
    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!

    VB.NET-Quellcode

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

    @silverbob76GE Dein Code ist mir etwas zu chaotisch.
    Nichts sagende Variablennamen, fehlende Kommentare.
    Ich hab hier mal ein ganz simples Beispiel gemacht:
    Form mit Button, RichTextBox und PrintDocument
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.IO
    2. ' Form mit Button, RichTextBox und PrintDocument
    3. Public Class Form1
    4. ' Anzahl der bereits gedruckten Zeichen
    5. Private TotalCharsPrinted As Integer
    6. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    7. ' als Text nehme ich einfach die Projekt-Datei
    8. Dim folder As String = ".." & Path.DirectorySeparatorChar
    9. ' "Drucken.exe" => "Drucken.vbproj"
    10. Dim proj As String = String.Concat(Path.GetFileNameWithoutExtension(Application.ExecutablePath), ".vbproj")
    11. ' "..\..\Drucken.vbproj"
    12. proj = String.Concat(folder, folder, proj)
    13. Me.RichTextBox1.Text = File.ReadAllText(proj)
    14. End Sub
    15. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    16. Using dlg = New PrintPreviewDialog()
    17. dlg.WindowState = FormWindowState.Maximized
    18. dlg.Document = Me.PrintDocument1
    19. dlg.PrintPreviewControl.Columns = 2
    20. dlg.ShowDialog()
    21. End Using
    22. End Sub
    23. Private Sub PrintDocument1_BeginPrint(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
    24. ' Start Ausdruck: Noch kein Zeichen gedruckt
    25. Me.TotalCharsPrinted = 0
    26. End Sub
    27. Private Sub PrintDocument1_PrintPage(ByVal sender As Object, ByVal e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    28. Using sf As New StringFormat()
    29. ' nur vollständige Zeilen drucken
    30. sf.FormatFlags = StringFormatFlags.LineLimit Or StringFormatFlags.NoWrap
    31. Dim ft As Font = Me.RichTextBox1.Font
    32. Dim g As Graphics = e.Graphics
    33. ' die noch zu druckenden Zeichen holen
    34. Dim sb As New System.Text.StringBuilder(Me.RichTextBox1.Text.Substring(Me.TotalCharsPrinted))
    35. ' werden von MeasureString() belegt
    36. Dim linesFilled, charsFitted As Integer
    37. ' die Anzahl der druckbaren Zeichen bestimmen
    38. g.MeasureString(sb.ToString(), ft, e.MarginBounds.Size, sf, charsFitted, linesFilled)
    39. ' der eigentliche Druck
    40. g.DrawString(sb.ToString(0, charsFitted), ft, Brushes.Black, e.MarginBounds, sf)
    41. Me.TotalCharsPrinted += charsFitted
    42. e.HasMorePages = Me.RichTextBox1.TextLength > Me.TotalCharsPrinted
    43. End Using
    44. End Sub
    45. End Class
    Gestalte mal Deinen Code so um, dass Du eine einzige Routine hast, in der genau ein TextBaustein gedruckt wird.
    Da kannst Du die TextBausteine von Seite 1 auch mit drucken.
    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, hab den Code nun Kommmentaren versehen.

    wie meinst du das mit "in der genau ein Textbaustein gedruckt wird"?
    Soll ich den Druckinhalt erst mal auf einen String abändern? Die zu druckenden Texte passen in der Regel immer in eine Zeile. Nur bei der Zelle mit "Leistung" ist der Inhalt oftmals länger. Ich habe jetzt mal den kompletten Code geposted, den Druck für Seite 2 habe ich weggelassen. War mir nicht sicher, ob du den sehen wolltest.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System.IO
    2. ' Form mit zwei Button zum drucken und zum speichern, zwei DataGridView, einem DataSet mit zwei DataTable und einer Bindingsource
    3. Public Class Form1
    4. 'Speicherort der XML-Datei, in die der Inhalt der DataTable geschrieben wird
    5. Dim auftragsfile As String = "c:\users\" + Environment.UserName + "\desktop\auftragsübersicht.xml"
    6. 'Schriftart für den Druck der DataTable
    7. Private myfont As Font = New Font("Calibri", 10, FontStyle.Regular)
    8. 'Zähler für die aktuelle Seitenzahl
    9. Private pagenb As Integer
    10. 'Zähler zur Bestimmung der Position in der BindingSource beim durchlaufen mit der For-Schleife
    11. Private index As Integer
    12. 'Startposition des Textes
    13. Private indextext As Integer
    14. 'Y-Koordinate zur Bestimmung der Textposition auf der Druckseite
    15. Private Y As Integer
    16. 'X-Koordinate zur Bestimmung der Textposition auf der Druckseite
    17. Private X As Integer
    18. 'linker Seitenrand
    19. Private leftMargin As Integer
    20. 'rechter Seitenrand
    21. Private rightMargin As Integer
    22. 'oberer Seitenrand
    23. Private topMargin As Integer
    24. 'unterer Seitenrand
    25. Private bottomMargin As Integer
    26. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    27. Reload() 'Methoder zum laden der XMl-Datei
    28. End Sub
    29. Private Sub Reload()
    30. DtsAufträge.Clear()
    31. For Each tb As DataTable In DtsAufträge.Tables
    32. tb.BeginLoadData()
    33. Next
    34. If File.Exists(auftragsfile) Then
    35. DtsAufträge.ReadXml(auftragsfile)
    36. End If
    37. For Each tb As DataTable In DtsAufträge.Tables
    38. tb.EndLoadData()
    39. Next
    40. End Sub
    41. Private Sub btspeichern_Click(sender As Object, e As EventArgs) Handles btspeichern.Click
    42. DtsAufträge.WriteXml(auftragsfile) 'Schreiben der DataTable-Daten in eine XML-Datei mit dem angegeben Speicherpfad
    43. End Sub
    44. Public Function Ausgabenhöhe(ByVal S As SizeF, ByVal B As Double) As Double
    45. 'Funktion zur Bestimmung der Zeilenhöhe, umd die Tabellenzellen zu zeichnen
    46. Dim H As Double
    47. If S.Width > B Then
    48. H = (S.Width / B)
    49. Else
    50. H = S.Height
    51. End If
    52. Return H
    53. End Function
    54. 'Funktion zur Ausrichtung des Texts (links, rechts, mittig)
    55. Private _sfright As New StringFormat With {.Alignment = StringAlignment.Far}
    56. Private Sub btdrucken_Click(sender As Object, e As EventArgs) Handles btdrucken.Click
    57. 'Aufrufen des Druckdialogs
    58. If DtsAufträge.Auftragsübersicht.Rows.Count > 0 Then
    59. Using dlg As New PrintDialog
    60. If dlg.ShowDialog() <> DialogResult.OK Then
    61. MessageBox.Show("Abbruch!", "Auftragsmodul")
    62. Return
    63. End If
    64. 'Druckeinstellungen
    65. PrintDocument1.PrinterSettings = dlg.PrinterSettings
    66. 'Seitenansicht auf Fenstergröße maximiert
    67. PrintPreviewDialog1.WindowState = FormWindowState.Maximized
    68. 'Dokumentname der zu druckenden Datei
    69. PrintPreviewDialog1.Document = Me.PrintDocument1
    70. 'Anzeige der Seitenzahl in der Seitenansicht
    71. PrintPreviewDialog1.PrintPreviewControl.Columns = 2
    72. 'Anzeige des Druckdialogs
    73. PrintPreviewDialog1.ShowDialog()
    74. End Using
    75. End If
    76. End Sub
    77. Private Sub PrintDocument1_BeginPrint(sender As Object, e As Printing.PrintEventArgs) Handles PrintDocument1.BeginPrint
    78. 'Start des Drucks. Seiten und Index für For-Schleife werden auf NUll gesetzt.
    79. Me.pagenb = 0 'Seitenzähler
    80. Me.index = 0 'Positionszähler der BindingSource
    81. Me.indextext = 0 'Position des zu druckenden Texts auf der Seite
    82. FKAuftragsübersichtAuftragsdetailBindingSource.MoveFirst() ' Start des Drucks bei Position 1 (Index = 0) der Bindingsource
    83. End Sub
    84. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    85. 'Druckprozedur
    86. Dim margin = PrintDocument1.DefaultPageSettings.Margins
    87. Dim g = e.Graphics
    88. Dim brush As New SolidBrush(Color.LightGray)
    89. Dim brush1 As New SolidBrush(Color.Black)
    90. Dim pen1 As New Pen(Brushes.LightGray, 0.5)
    91. Dim pen2 As New Pen(Brushes.DarkGray, 0.5)
    92. Dim pen3 As New Pen(Brushes.White, 0.5)
    93. Dim LineHeight As Single = Me.myfont.GetHeight
    94. margin.Left = 30
    95. margin.Right = 30
    96. margin.Top = 30
    97. margin.Bottom = 30
    98. leftMargin = margin.Left
    99. rightMargin = margin.Right
    100. topMargin = margin.Top
    101. bottomMargin = margin.Bottom
    102. 'Druckbereich
    103. Dim rc = e.Graphics.VisibleClipBounds
    104. rc.Offset(margin.Left + 30, margin.Top + 30) ' obere linke Ecke
    105. rc.Width -= (margin.Left + 20 + margin.Right - 20) ' neue Breite
    106. rc.Height -= (margin.Top + margin.Bottom) ' neue Höhe
    107. X = leftMargin
    108. Y = topMargin
    109. Dim strformat As New StringFormat(StringFormatFlags.LineLimit)
    110. Dim charactersfitted As Integer
    111. Dim linesfilled As Integer
    112. DrawHeader(g) ' Kopfzeile auf erster Seite
    113. DrawRectangle(g, brush) ' Tabellenkopfzeile als farbiges Rechteck
    114. 'DataTable enthält Rechnungspositionen. Damit alle DataRows der DataTable gedruckt werden, Iteration mit For-Schleife durch
    115. 'Bindingsource.
    116. For i = index To FKAuftragsübersichtAuftragsdetailBindingSource.Count - 1
    117. Dim row1 = DirectCast(DirectCast(FKAuftragsübersichtAuftragsdetailBindingSource.Current, DataRowView).Row, DtsAufträge.AuftragsdetailRow)
    118. 'Druckbereich der DataRow für die DataColumn 'Leistung', Höhe abhängig von der Zeilenanzahl
    119. Dim an = g.VisibleClipBounds
    120. an.Offset(X + 60, Y + 35)
    121. an.Width = 380
    122. Dim B = 380
    123. ' Startposition des Texts in der zu druckenden Tabellenzeile. Genullt, da die Tabellenzeile neu anfängt.
    124. indextext = 0
    125. 'Prüfung der Länge des Strings in der DataRow
    126. Dim S As SizeF = g.MeasureString(row1.Leistung.Substring(indextext), myfont, an.Size, strformat, charactersfitted, linesfilled)
    127. 'bestimmt die Höhe der zu druckenden Zeile
    128. Dim Hoch As Double = Ausgabenhöhe(S, B)
    129. 'Gibt die Höhe der zu druckenden Tabellenzeile an, damit die Tabellenzeilen gezeichnet werden können.
    130. an.Height = CInt(Hoch)
    131. 'DataRow in Tabellenform gedruckt
    132. DrawRow1Info(g, pen3, strformat, row1, an, Hoch, B)
    133. 'Zeichnung der Tabellenzellen
    134. DrawHoch(g, pen1, Hoch) '
    135. 'Zähler für die Position in der BindingSource
    136. index += 1
    137. FKAuftragsübersichtAuftragsdetailBindingSource.MoveNext()
    138. 'End If
    139. Next
    140. g.DrawString(String.Format(" - Seite {0} -", pagenb + 1), myfont, brush, 380, 1130)
    141. e.HasMorePages = False 'keine weiteren Seiten für Druck vorhanden
    142. 'End If
    143. 'Y += 80
    144. End Sub
    145. Private Sub DrawHeader(g As Graphics)
    146. 'Kopfzeile für den Druck auf Seite 1
    147. Y += 240
    148. g.DrawString("Auftragsnummer" & vbTab & vbTab & ":", myfont, Brushes.Black, X + 10, Y)
    149. Y += 20
    150. g.DrawString("Bauvorhaben" & vbTab & vbTab & ":", myfont, Brushes.Black, X + 10, Y)
    151. Y += 100
    152. End Sub
    153. Private Sub DrawRow1Info(g As Graphics, pen3 As Pen, strformat As StringFormat, row1 As DtsAufträge.AuftragsdetailRow, an As RectangleF, Hoch As Double, B As Integer)
    154. 'Positionszeilen für den Druck auf allen Seiten
    155. If Not row1.IsLeistungNull Then
    156. g.DrawString(row1.Leistung.Substring(indextext), myfont, Brushes.Black, an, strformat)
    157. End If
    158. If Not row1.IsPosNull Then
    159. g.DrawString(CStr(row1.Pos), myfont, Brushes.Black, X + 17, Y + 35)
    160. End If
    161. Dim drawrect As New RectangleF(X + 60, Y + 35, B, CInt(Hoch))
    162. g.DrawRectangle(pen3, X + 58, Y + 33, CInt(B + 4), CInt(Hoch + 2))
    163. If Not row1.IsMengeNull Then
    164. g.DrawString(Format(row1.Menge, "N2"), myfont, Brushes.Black, X + 460, Y + 35)
    165. End If
    166. If Not row1.IsEinheitNull Then
    167. g.DrawString(Format(row1.Einheit), myfont, Brushes.Black, X + 530, Y + 35)
    168. End If
    169. If Not row1.IsEinzelpreisNull Then
    170. g.DrawString(Format(row1.Einzelpreis, "C2"), myfont, Brushes.Black, X + 598, Y + 35)
    171. End If
    172. If Not row1.IsGesamtpreisNull Then
    173. g.DrawString(Format(row1.Gesamtpreis, "C2"), myfont, Brushes.Black, X + 663, Y + 35)
    174. End If
    175. End Sub
    176. Private Sub DrawHoch(g As Graphics, pen1 As Pen, Hoch As Double)
    177. 'Zeichnung der Tabellenzellgrenzen
    178. If Hoch > 20 Then
    179. Y += 35
    180. g.DrawLine(pen1, X + 51, Y, X + 51, Y + CInt(Hoch + 7))
    181. g.DrawLine(pen1, X + 453, Y, X + 453, Y + CInt(Hoch + 7))
    182. g.DrawLine(pen1, X + 520, Y, X + 520, Y + CInt(Hoch + 7))
    183. g.DrawLine(pen1, X + 577, Y, X + 577, Y + CInt(Hoch + 7))
    184. g.DrawLine(pen1, X + 659, Y, X + 659, Y + CInt(Hoch + 7))
    185. g.DrawLine(pen1, X + 10, Y + CInt(Hoch + 7), X + 739, Y + CInt(Hoch + 7))
    186. Y += CInt(Hoch) - 20
    187. End If
    188. If Hoch < 20 Then
    189. Y += 35
    190. g.DrawLine(pen1, X + 51, Y, X + 51, Y + 25)
    191. g.DrawLine(pen1, X + 453, Y, X + 453, Y + 25)
    192. g.DrawLine(pen1, X + 520, Y, X + 520, Y + 25)
    193. g.DrawLine(pen1, X + 577, Y, X + 577, Y + 25)
    194. g.DrawLine(pen1, X + 659, Y, X + 659, Y + 25)
    195. g.DrawLine(pen1, X + 10, Y + 25, X + 739, Y + 25)
    196. End If
    197. End Sub
    198. Private Sub DrawRectangle(g As Graphics, brush As SolidBrush)
    199. 'Inhaöt des Tabellenkopfs
    200. g.FillRectangle(brush, X + 10, Y, 40, 30)
    201. g.DrawString("Pos.", myfont, Brushes.Black, X + 15, Y + 5)
    202. g.FillRectangle(brush, X + 52, Y, 400, 30)
    203. g.DrawString("Leistung", myfont, Brushes.Black, X + 240, Y + 5)
    204. g.FillRectangle(brush, X + 454, Y, 65, 30)
    205. g.DrawString("Menge", myfont, Brushes.Black, X + 462, Y + 5)
    206. g.FillRectangle(brush, X + 521, Y, 55, 30)
    207. g.DrawString("Einheit", myfont, Brushes.Black, X + 524, Y + 5)
    208. g.FillRectangle(brush, X + 578, Y, 80, 30)
    209. g.DrawString("EP [€]", myfont, Brushes.Black, X + 600, Y + 5)
    210. g.FillRectangle(brush, X + 660, Y, 80, 30)
    211. g.DrawString("GP [€]", myfont, Brushes.Black, X + 685, Y + 5)
    212. End Sub
    213. End Class