pdf File Writer Rahmen für bestimmte Zellen einer Tabelle

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 40 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    DerSmurf schrieb:

    Wie kürze ich meinen Text also auf diese Länge?
    Gib DrawString den zur Verfügung stehenden Platz mit:
    docs.microsoft.com/de-de/dotne…?view=dotnet-plat-ext-6.0
    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!
    Oh Sorry. das habe ich übersehen.
    Aber sag mal, wäre meine Lösung unsauber?

    VB.NET-Quellcode

    1. If Colcounter = 3 Then
    2. If Text.Length > 36 Then
    3. Text = Text.Substring(0, (Text.Length - (Text.Length - 36)))
    4. End If


    Ich denke das ganze hat zwei Vorteile.
    1. Wenn ich die Zeichen begrenze, wird mein String nicht mitten in einem Buchstaben abgeschnitten
    2. Deine Version benötigt mehr Code

    Kann ich meine String schneide Methode lassen, oder ist das unsauber?

    edit:
    Die Alternative sähe wohl so aus, (auch wenn die Höhe nicht stimmt. Die Breite ist zwar OK. Aber der Text wird nicht abgeschnitten, sondern Zweizeilig dargestellt:

    VB.NET-Quellcode

    1. Dim Text = cols(i)
    2. Dim cellwidth As Single
    3. Dim wrtingRect As RectangleF
    4. If Colcounter = 3 Then
    5. 'If Text.Length > 36 Then
    6. ' Text = Text.Substring(0, (Text.Length - (Text.Length - 36)))
    7. 'End If
    8. cellwidth = 270
    9. wrtingRect = New RectangleF(x, y + Row_Position, x + cellwidth, 0)
    10. e.Graphics.DrawString(Text, TableFont, System.Drawing.Brushes.Black, wrtingRect, TextFormat)
    11. Else
    12. e.Graphics.DrawString(Text, TableFont, System.Drawing.Brushes.Black, x, y + Row_Position, TextFormat)
    13. End If

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

    DerSmurf schrieb:

    wäre meine Lösung unsauber?
    Ja.
    Du hast gewiss Proportionaltext, d.h., dass ein i schmaler ist als ein m.
    Du musst also mit .MeasureString() arbeiten.
    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!
    Ist es dann nicht eine Option zu testen wie viele "m" in eine Zeile passen und sich danach zu richten?

    Edit:
    und kannst du mir sagen, warum mein Text zweilig dargestellt wird?
    Mit meinem Rechteck mit Höhe 0, hätte ich erwartet, dass der Text garnicht angezeigt wird.


    VB.NET-Quellcode

    1. [s]wrtingRect = New RectangleF(x, y + Row_Position, x + cellwidth, 0)
    2. e.Graphics.DrawString(Text, TableFont, System.Drawing.Brushes.Black, wrtingRect, TextFormat)[/s]


    habs rausgefunden, die 0 am Ende der Rechteckgröße scheint wohl nicht zu funktionieren, wie ich vermutet habe.
    So wäre mein Code dann richtig.

    VB.NET-Quellcode

    1. cellwidth = 270
    2. wrtingRect = New RectangleF(x, y + Row_Position, cellwidth, 20)
    3. e.Graphics.DrawString(Text, TableFont, System.Drawing.Brushes.Black, wrtingRect, TextFormat)

    Ich werde mal mit ein paar Artikeln testen, wie unschön das Abschneiden aussieht. Also ob es überhaupt stört.
    Denn der Vorteil ist natürlich, dass ich den wirklich zu verfügung stehenden Platz verwende und keinen Platz verschwende, weil ich ja davon ausgehe, dass ich lauter "m" im Wort habe.

    Könntest du mir dann noch bei der Mehrseitigkeit helfen?
    ch finde keine Lösung, wie ich das Beispiel in deinem Tutorial auf meine Anwendung hier passend bekomme, denn ich habe ja keinen String, wo ich nur die Zeichen zählen muss.Außerdem hätte ich gerne den Teil ab "Netto - Betrag" (unter der ersten Linie) immer zusammenhängend.Wenn also der Seitenumbruch z-B. eine Zeile unter "7" Mwst auf" entstünde, würde ich diesen gerne schon vorher durchführen, sodass die nächste Seite mit "Netto - Betrag" beginntWäre es da eine Option zu schauen, wie tief die Tabelle runter kann, bis es nicht mehr auf eine Seite passt und dann manuell einen Seitenumbruch einzufügen?

    VB.NET-Quellcode

    1. if y + Row_Position = 450 then ' wenn 450 die Grenze auf der y Achse ist
    2. '"neue Seite einfügen"
    3. End if

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „DerSmurf“ ()

    @DerSmurf Dies hier setzt den Druck auf einer neue Seite fort:

    VB.NET-Quellcode

    1. if y + Row_Position = 450 then ' wenn 450 die Grenze auf der y Achse ist
    2. '"neue Seite einfügen"
    3. e.HasMorePages = True
    4. Return
    5. End if
    Allerdings muss der Rest des Codes darauf abgestimmt sein, damit der Textfluss stimmt.
    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!
    Vorgweg: Ich habe mich für das Abschneiden des Textes entschieden:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. If Colcounter = 3 Then
    2. cellwidth = 270
    3. wrtingRect = New RectangleF(x, y + Row_Position, cellwidth, 20)
    4. e.Graphics.DrawString(Text, TableFont, System.Drawing.Brushes.Black, wrtingRect, TextFormat)
    5. Else
    6. e.Graphics.DrawString(Text, TableFont, System.Drawing.Brushes.Black, x, y + Row_Position, TextFormat)
    7. End If

    und werde es für die weiteren Spalten, wo ich evtl. Überlänge habe ebenso durchführen. Das abschneiden nach Zeichenlänge ist, wie du ja bereits sagtest, einfach Mist, wegen der - doch sehr - unterschiedlichen Buchstabenlänge.

    Ich habe eine kleine neue Demo gebastelt um die Seitenumbrüche zu testen.
    Dazu habe ich mir folgende Aufgabe gestellt:
    Nur auf Seite 1 soll ein Text in Schriftgröße 22 stehen, darunter die Zahlen 1 bis 400 jeweils einzeln pro Zeile.
    Dabei sollen sich die Zahlen sauber auf mehrere Blätter verteilen.
    Damit das ganze meiner Hauptanwendung näher kommt, gibt es wieder eine Sub, die eine List of Integer befüllt und dann damit die eigentliche DruckSub startet.

    @RodFromGermany Bitte beurteile meine Lösung - denn diese würde ich ziemlich genauso in meine Hauptanwendung einbauen können.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. [/spoiler][spoiler] Private Pagenumber As Integer = 1
    3. Private arrayCount As Integer = 0
    4. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    5. Pagenumber = 1
    6. Using dlg As New PrintPreviewDialog
    7. Me.PrintDocument1.DocumentName = "Test" ' Arbeitstitel
    8. dlg.Document = Me.PrintDocument2
    9. dlg.ShowDialog()
    10. End Using
    11. End Sub
    12. Private Sub PrintDocument2_BeginPrint(sender As System.Object, e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument2.BeginPrint
    13. Pagenumber = 1
    14. End Sub
    15. Private Sub PrintDocument2_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument2.PrintPage
    16. Seitenumbruchtest(sender, e)
    17. End Sub
    18. Private Sub Seitenumbruchtest(sender As Object, e As Printing.PrintPageEventArgs)
    19. Dim NumberList As New List(Of Integer)
    20. For i = 1 To 400
    21. NumberList.Add(i)
    22. Next
    23. CreatePages(sender, e, NumberList)
    24. End Sub
    25. Private Sub CreatePages(sender As Object, e As Printing.PrintPageEventArgs, Numberlist As List(Of Integer))
    26. Dim TextFont As Font = New Font("times new roman", 12)
    27. Dim HeaderFont As Font = New Font("times new roman", 22)
    28. Dim y As Integer = 20
    29. Dim yFurSeitenumbruch As Integer
    30. If Pagenumber = 1 Then
    31. e.Graphics.DrawString("Dies ist ein Überflüssiger Fülltext", HeaderFont, Brushes.Black, New Point(30, y))
    32. y += 30
    33. e.Graphics.DrawString("er soll nur auf Seite 1 erscheinen", HeaderFont, Brushes.Black, New Point(30, y))
    34. y += 30
    35. e.Graphics.DrawString("und steht als Beispiel", HeaderFont, Brushes.Black, New Point(30, y))
    36. y += 30
    37. e.Graphics.DrawString("für den Text über den Artikeln in meiner Rechnung", HeaderFont, Brushes.Black, New Point(30, y))
    38. y += 60
    39. End If
    40. For i = arrayCount To Numberlist.Count - 1
    41. e.Graphics.DrawString(Numberlist(i).ToString, TextFont, Brushes.Black, New Point(30, y))
    42. y += 20
    43. If Pagenumber = 1 Then
    44. yFurSeitenumbruch = 1150
    45. Else
    46. yFurSeitenumbruch = 1160
    47. End If
    48. If y >= yFurSeitenumbruch Then
    49. e.HasMorePages = True
    50. Pagenumber += 1
    51. arrayCount = i + 1
    52. Return
    53. End If
    54. Next
    55. End Sub[/spoiler][spoiler]
    56. End Class


    Da ich nicht weiß, ob du sowas lieber im Forum, oder in der Solution machst, habe ich die Solution mal angehängt.
    Dateien
    • PPDTedt.zip

      (14,41 kB, 6 mal heruntergeladen, zuletzt: )
    @DerSmurf Wenn Du mehrere Seiten druckst, pack die Fonts aus der Prozedur in die Klasse, ebenso alle IDisposables,
    die kannst Du dann bei Programmbeendigung aufräumen.
    Ich hab mal ein paar Prozeduen zusammengefasst und das BeginPrint getunt.
    Der Code von PrintDocument1_PrintPage() hehört eigentlich nach PrintDocument1_BeginPrint, wo Du Deine Datenklasse befüllst und für den Druck vorbereitest.
    Trenne die Ausgabe von Headern, Zwischenüberschriften und Daten, das alles passiert in separaten Prozeduren dieser Datenklasse.
    Wenn jede dieser Prozeduren weiß, wie hoch ihr eigener Ausdruck wird, kannst Du prüfen, ob der Inhalt noch auf die aktuelle Seite passt.
    Wenn nicht, fügst Du einen Seitenumbruch ein.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim TextFont1 As Font = New Font("times new roman", 12)
    3. Dim HeaderFont1 As Font = New Font("times new roman", 18)
    4. Dim TableFont1 As Font = New Font("times new roman", 12)
    5. Private TextFont2 As Font = New Font("times new roman", 12)
    6. Private HeaderFont2 As Font = New Font("times new roman", 22)
    7. Private _InvoiceType As String = "Warenausgang"
    8. Private PageNumber As Integer = 1 ' Doc 1 und 2, Startindex im Array
    9. Private ArrayCount As Integer = 0 ' Doc 2
    10. Private NumberList As List(Of Integer)
    11. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    12. Using dlg As New PrintPreviewDialog
    13. Me.PrintDocument1.DocumentName = "Test" ' Arbeitstitel
    14. dlg.WindowState = FormWindowState.Maximized
    15. dlg.Document = Me.PrintDocument1
    16. dlg.ShowDialog()
    17. End Using
    18. End Sub
    19. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    20. Using dlg As New PrintPreviewDialog
    21. Me.PrintDocument1.DocumentName = "Test" ' Arbeitstitel
    22. dlg.Document = Me.PrintDocument2
    23. dlg.ShowDialog()
    24. End Using
    25. End Sub
    26. ''' <summary>
    27. ''' CreateInvoice
    28. ''' </summary>
    29. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    30. Dim CompanyFirstInfo As New List(Of String)
    31. Dim CompanySecondInfo As New List(Of String)
    32. Dim CustomerFirstInfo As New List(Of String)
    33. Dim CustomerSecondInfo As New List(Of String)
    34. Dim Invoicetype As String = ""
    35. Dim Invoicetext As String = ""
    36. Dim Invoicedate As New List(Of String)
    37. Dim ArticleList As New List(Of String)
    38. Dim Net7 As Double
    39. Dim Net19 As Double
    40. Dim NetTotal As Double
    41. Dim Tax7 As Double
    42. Dim Tax19 As Double
    43. Dim BrutTotal As Double
    44. Invoicedate.Add("Datum: " & System.DateTime.Now.ToString("dd.MM.yyyy"))
    45. Net7 = 7.0
    46. Net19 = 19
    47. NetTotal = Net7 + Net19
    48. Tax7 = 0.07
    49. Tax19 = 0.19
    50. BrutTotal = Net7 + Net19 + Tax7 + Tax19
    51. Select Case _InvoiceType
    52. Case = "Warenausgang"
    53. CompanyFirstInfo.Add("Firmenname1")
    54. CompanyFirstInfo.Add("Firmenname2")
    55. CompanyFirstInfo.Add("Firmenstraße")
    56. CompanyFirstInfo.Add("Firmenort")
    57. CompanySecondInfo.Add("Firmentelefon")
    58. CompanySecondInfo.Add("Firmenmail")
    59. CompanySecondInfo.Add("Firmensteuernr")
    60. CustomerFirstInfo.Add("KundenFirma")
    61. CustomerFirstInfo.Add("Kundenname")
    62. CustomerFirstInfo.Add("Kundenstr.")
    63. CustomerFirstInfo.Add("Kundenort")
    64. CustomerSecondInfo.Add("KundenTelefon")
    65. Invoicedate.Add("Rechnungdatum entspricht Leistungsdatum")
    66. Invoicetype = "Rechnung"
    67. Invoicetext = "Wir danken für Ihren Einkauf und berechnen wie folgt:"
    68. ArticleList = GetArticle()
    69. 'Case = "Wareneingang"
    70. ' If Not CheckCustomerData() Then Return
    71. ' CompanyFirstInfo = GetCustomerFirstData()
    72. ' CompanySecondInfo = GetCustomerSecondData()
    73. ' CustomerFirstInfo = GetCompanyFirstData()
    74. ' CustomerSecondInfo = GetCompanySecondData()
    75. ' Invoicedate.Add("Rechnungdatum entspricht Leistungsdatum")
    76. ' Invoicetype = "Rechnung"
    77. ' Invoicetext = ""
    78. ' ArticleList = GetArticle(False)
    79. 'Case = "Artikelrückgabe"
    80. ' If Not CheckCustomerData() Then Return
    81. ' CompanyFirstInfo = GetCompanyFirstData()
    82. ' CompanySecondInfo = GetCompanySecondData()
    83. ' CustomerFirstInfo = GetCustomerFirstData()
    84. ' CustomerSecondInfo = GetCustomerSecondData()
    85. ' Invoicedate.Add("Rechnungdatum entspricht Leistungsdatum")
    86. ' Invoicetype = "Artikelrückgabe"
    87. ' Invoicetext = ""
    88. ' ArticleList = GetArticle(False)
    89. 'Case = "Angebot"
    90. ' CompanyFirstInfo = GetCompanyFirstData()
    91. ' CompanySecondInfo = GetCompanySecondData()
    92. ' CustomerFirstInfo = GetCustomerFirstData()
    93. ' CustomerSecondInfo = GetCustomerSecondData()
    94. ' Invoicedate.Add("")
    95. ' Invoicetype = "Angebot"
    96. ' Invoicetext = "Gerne unterbreiten wir Ihnen hiermit folgendes Angebot." &
    97. ' Environment.NewLine & "Die angebotenen Preise sind freibleibend."
    98. ' ArticleList = GetArticle(_NetInvoicing)
    99. End Select
    100. DrawPdf(e, CompanyFirstInfo, CompanySecondInfo, CustomerFirstInfo, CustomerSecondInfo, Invoicedate, Invoicetype, Invoicetext, ArticleList,
    101. Net7, Net19, NetTotal, Tax7, Tax19, BrutTotal)
    102. End Sub
    103. Private Sub DrawPdf(e As Printing.PrintPageEventArgs, Biller1 As List(Of String), Biller2 As List(Of String), Recipient1 As List(Of String),
    104. recipient2 As List(Of String), Invoicedate As List(Of String), Invoicetype As String, Invoicetext As String, ArticleList As List(Of String),
    105. Net7 As Double, Net19 As Double, NetTotal As Double, Tax7 As Double, tax19 As Double, Bruttotal As Double)
    106. Dim xlinks As Integer = 70
    107. Dim xrechts As Integer = 480
    108. Dim y As Integer = 30
    109. Dim yStart As Integer = y
    110. Dim textrechts As New StringFormat
    111. textrechts.Alignment = StringAlignment.Far
    112. Dim TextLinks As New StringFormat
    113. TextLinks.Alignment = StringAlignment.Near
    114. Dim TextMitte As New StringFormat
    115. TextMitte.Alignment = StringAlignment.Center
    116. Dim TextFormat As New StringFormat
    117. 'Ausstelleradresse der Rechnung - linke Seite
    118. For Each item In Biller1
    119. e.Graphics.DrawString(item, TextFont1, Brushes.Black, New Point(xlinks, y))
    120. y += 20
    121. Next
    122. y = yStart
    123. 'Ausstelleradresse der Rechnung - rechte Seite
    124. For Each item In Biller2
    125. e.Graphics.DrawString(item, TextFont1, Brushes.Black, New Point(xrechts, y))
    126. y += 20
    127. Next
    128. y += 70
    129. yStart = y
    130. 'Empfänger der Rechnung - linke Seite
    131. For Each item In Recipient1
    132. e.Graphics.DrawString(item, TextFont1, Brushes.Black, New Point(xlinks, y))
    133. y += 20
    134. Next
    135. Dim yTemp = y + 50
    136. y = yStart
    137. 'Empfänger der Rechnung - rechte Seite
    138. For Each item In recipient2
    139. e.Graphics.DrawString(item, TextFont1, Brushes.Black, New Point(xrechts, y))
    140. y += 20
    141. Next
    142. y = yTemp
    143. 'Rechnungsart
    144. e.Graphics.DrawString(Invoicetype, HeaderFont1, Brushes.Black, New Point(xlinks, y))
    145. 'Rechnungsdatum
    146. For Each item In Invoicedate
    147. e.Graphics.DrawString(item, TextFont1, Brushes.Black, New Point(xrechts, y))
    148. y += 20
    149. Next
    150. y += 30
    151. 'Rechnungstext
    152. e.Graphics.DrawString(Invoicetext, TextFont1, Brushes.Black, New Point(xlinks, y))
    153. y += 50
    154. 'Artikeltabelle
    155. Dim Row_Position As Single = 0
    156. Dim RowHeight As Single = CType(e.Graphics.MeasureString("W", TableFont1).Height * 1.25, Single)
    157. Dim Colcounter As Integer = 1
    158. Dim RowCounter As Integer = 1
    159. Dim x As Integer
    160. For Each article In ArticleList
    161. Dim cols() As String = Split(article, "~"c)
    162. For i = 0 To cols.Length - 1
    163. If RowCounter = 1 Then
    164. Select Case Colcounter
    165. Case = 1 : x = xlinks
    166. Case = 2 : x = xlinks + 80
    167. Case = 3 : x = xlinks + 150
    168. Case = 4 : x = xlinks + 410
    169. Case = 5 : x = xlinks + 480
    170. Case = 6 : x = xlinks + 580
    171. Case Else : x = xlinks + 100
    172. End Select
    173. TextFormat = TextLinks
    174. Else
    175. Select Case Colcounter
    176. Case = 1
    177. TextFormat = textrechts
    178. x = xlinks + 40
    179. Case = 2
    180. TextFormat = textrechts
    181. x = xlinks + 129
    182. Case = 3
    183. TextFormat = TextLinks
    184. x = xlinks + 150
    185. Case = 4
    186. TextFormat = TextLinks
    187. x = xlinks + 432
    188. Case = 5
    189. TextFormat = textrechts
    190. x = xlinks + 559
    191. Case = 6
    192. TextFormat = textrechts
    193. x = xlinks + 668
    194. Case Else
    195. TextFormat = TextLinks
    196. x = xlinks + 100
    197. End Select
    198. End If
    199. Dim Text = cols(i)
    200. Dim cellwidth As Single
    201. Dim wrtingRect As RectangleF
    202. If Colcounter = 3 Then
    203. cellwidth = 270
    204. wrtingRect = New RectangleF(x, y + Row_Position, cellwidth, 20)
    205. e.Graphics.DrawString(Text, TableFont1, System.Drawing.Brushes.Black, wrtingRect, TextFormat)
    206. Else
    207. e.Graphics.DrawString(Text, TableFont1, System.Drawing.Brushes.Black, x, y + Row_Position, TextFormat)
    208. End If
    209. Colcounter += 1
    210. Next
    211. Row_Position += RowHeight
    212. Colcounter = 1
    213. RowCounter += 1
    214. Next
    215. y += CInt(Row_Position)
    216. e.Graphics.DrawRectangle(Pens.Black, xlinks, y, 670, 1)
    217. y += 10
    218. Dim x1 = xlinks + 150
    219. Dim x2 = xlinks + 310
    220. 'Netto Text
    221. e.Graphics.DrawString("Netto - Betrag", TextFont1, Brushes.Black, New Point(x1, y))
    222. e.Graphics.DrawString(NetTotal.ToString("#,##0.00 €"), TextFont1, Brushes.Black, New Point(xlinks + 670, y), textrechts)
    223. y += 20
    224. e.Graphics.DrawString("7% Mwst auf", TextFont1, Brushes.Black, New Point(x2, y))
    225. e.Graphics.DrawString(Net7.ToString("#,##0.00 €"), TextFont1, Brushes.Black, New Point(xlinks + 560, y), textrechts)
    226. e.Graphics.DrawString(Tax7.ToString("#,##0.00 €"), TextFont1, Brushes.Black, New Point(xlinks + 670, y), textrechts)
    227. y += 20
    228. e.Graphics.DrawString("19% Mwst auf", TextFont1, Brushes.Black, New Point(x2, y))
    229. e.Graphics.DrawString(Net19.ToString("#,##0.00 €"), TextFont1, Brushes.Black, New Point(xlinks + 560, y), textrechts)
    230. e.Graphics.DrawString(tax19.ToString("#,##0.00 €"), TextFont1, Brushes.Black, New Point(xlinks + 670, y), textrechts)
    231. y += 25
    232. e.Graphics.DrawRectangle(Pens.Black, xlinks, y, 670, 1)
    233. y += 10
    234. e.Graphics.DrawString("Endsumme", TextFont1, Brushes.Black, New Point(x1, y))
    235. e.Graphics.DrawString(Bruttotal.ToString("#,##0.00 €"), TextFont1, Brushes.Black, New Point(xlinks + 670, y), textrechts)
    236. End Sub
    237. Private Function GetArticle() As List(Of String)
    238. Dim ArticleList As New List(Of String)
    239. Dim Article As String
    240. ArticleList.Add("Menge~Art.Nr.~Bezeichnung~Mwst.~Einzelpreis~Gesamtpreis")
    241. For i = 1 To 5
    242. Dim amount = i * 4 * 100
    243. Dim Einzelpreis As Double = i * 2.5
    244. Dim Gesamtpreis = amount * Einzelpreis
    245. Dim ArtNr As Integer = CInt(i * 1111.458) * i * 100
    246. If i = 3 Then Einzelpreis = 1528.0
    247. If i = 1 Then
    248. Article = "1~Art.Nr.~" & "Rinti Kennerfleisch 800g Wildschwein mmmmmmmmmmmmmmmm~" & "19" & "~" & "Einzelpreis~" & "Gesamtpreis"
    249. Else
    250. Article = amount & "~" & ArtNr.ToString & "~" & "Artikelname " & i & "~" & "19" & "~" & Einzelpreis.ToString("#,##0.00 €") & "~" & Gesamtpreis.ToString("#,##0.00 €")
    251. End If
    252. ArticleList.Add(Article)
    253. Next
    254. Return ArticleList
    255. End Function
    256. Private Sub PrintDocument2_BeginPrint(sender As System.Object, e As System.Drawing.Printing.PrintEventArgs) Handles PrintDocument2.BeginPrint
    257. PageNumber = 1 ' Startindex initialisieren
    258. ArrayCount = 0
    259. NumberList = New List(Of Integer)
    260. For i = 1 To 400
    261. NumberList.Add(i)
    262. Next
    263. End Sub
    264. ''' <summary>
    265. ''' Seitenumbruchtest, CreatePages
    266. ''' </summary>
    267. Private Sub PrintDocument2_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument2.PrintPage
    268. Dim y As Integer = 20
    269. Dim yFurSeitenumbruch As Integer = 1150
    270. If PageNumber = 1 Then
    271. e.Graphics.DrawString("Dies ist ein Überflüssiger Fülltext", HeaderFont2, Brushes.Black, New Point(30, y))
    272. y += 30
    273. e.Graphics.DrawString("er soll nur auf Seite 1 erscheinen", HeaderFont2, Brushes.Black, New Point(30, y))
    274. y += 30
    275. e.Graphics.DrawString("und steht als Beispiel", HeaderFont2, Brushes.Black, New Point(30, y))
    276. y += 30
    277. e.Graphics.DrawString("für den Text über den Artikeln in meiner Rechnung", HeaderFont2, Brushes.Black, New Point(30, y))
    278. y += 60
    279. Else
    280. e.Graphics.DrawString($"Seite {PageNumber}", HeaderFont2, Brushes.Black, New Point(30, y))
    281. y += 60
    282. End If
    283. For i = ArrayCount To NumberList.Count - 1
    284. e.Graphics.DrawString(NumberList(i).ToString, TextFont2, Brushes.Black, New Point(30, y))
    285. y += 20
    286. If y >= yFurSeitenumbruch Then
    287. e.HasMorePages = True
    288. PageNumber += 1
    289. ArrayCount = i + 1
    290. Return
    291. End If
    292. Next
    293. End Sub
    294. End Class
    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!
    Ich danke dir! Deine Änderungen - bzw. deren Zweck - habe ich soweit verstanden.
    Das ganze bastel ich nun in meine Hauptanwendung um.

    Ich bin mir aber noch nicht 100%ig sicher, wie ich das ganze dann final umsetze.
    Entweder mit zwei Buttons - einmal Druckvorschau anzeigen und einmal direkt drucken,
    oder ein Panel was sich rausschiebt, auf dem dann die Druckdatei angezeigt wird (PrintpreviewControl, sowie alle Settings hierzu. Also welcher Drucker, Anzahl der Drucks, usw.

    Ich denke die zweite Variante ist optisch am schönsten, aber da kann ich ja rumprobieren.

    Edit:
    Du schmeißt alle PrintFonts und die IDispoables in die Klasse, damit ich hinterher aufräumen kann. Tust es aber nicht? (oder hab ich was übersehen)
    Dafür würde ich noch den EndPrint Handler abonnieren. Oder gehört das woanders rein?

    Edit2: Ich habe den Code nun funktionierend in meinem Hauptprogramm. Aber das hier:

    RodFromGermany schrieb:

    Der Code von PrintDocument1_PrintPage() hehört eigentlich nach PrintDocument1_BeginPrint, wo Du Deine Datenklasse befüllst und für den Druck vorbereitest.

    stellt mich vor eine Herausforderung. Denn ich übergebe das e As Printing.PrintPageEventArgs ja an meine Sub Createinvoice und von da weiter an DrawPdf.
    Im BeginPrintEvent habe ich ja e As PrintEventArgs - kann es also nicht übergeben und damit in Drawpdf nicht e.hasmorepages auf True setzen.
    Außerdem habe ich festgestellt, dass das PrintPage Event beim Drucken jeder Seite feuert.
    Also für jede neue Seite in meinem Ausdruck läuft die Sub CreateInvoice, welche ja alle Daten holt, immer wieder.
    Ich vermute also, dass mein gesamtes Konstrukt aus Subs murks ist. (auch wenn das Ergebnis anstandslos ist).
    Könntest du mir einmal aufschreiben, wie ich es richtig mache?
    Also in welcher Reihenfolge ich was mache, bzw. welche Subs ablaufen lasse? Und sollte ich alle Daten die CreateInvoice sammelt in die Klasse schreiben - damit ich sie nicht an die DruckSub übergeben muss?

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

    DerSmurf schrieb:

    (oder hab ich was übersehen)
    Hier ist von 2 (zwei) Klassen die Rede:
    Fonts und IDisposable aus der Prozedur in die bereits vorhandene Klasse, hier Form1.
    Daten in eine separate neu zu erstellende Klasse, die es noch nicht gibt.
    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!
    Ah, ok.
    Und in meine zweite Klasse kommen dann auch die Subs zum sammeln von Daten, das Erstellen des Headers meiner Druckseite (also Firmennamen, usw.) und das Erstellen meiner Tabelle.
    Dazu rufe ich dann im BeginPrint Event die Datensammelsub auf.
    Im Page Print Event, kommt dann die eigentliche Druck Sub, - aufgeteilt in eine Sub für Header und eine Sub für die Artikeltabelle.
    So?

    DerSmurf schrieb:

    So?
    Ja, sollte funktionieren.
    Mach Dir zuerst ein kleines Test-Programm, um das Datenhandling zu verstehen.
    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. Das habe ich dann soweit umgesetzt (außer meine Druckensub ist immernoch eine einzige Sub).
    Schrittweise sieht das soweit auch gut aus, es werden nicht bei jeder Seite die Daten neu geladen.

    VB.NET-Quellcode

    1. Private Sub PrintDocument1_BeginPrint(sender As Object, e As PrintEventArgs) Handles PrintDocument1.BeginPrint
    2. Pagenumber = 1
    3. arraycount = 0
    4. CreateInvoice()
    5. End Sub
    6. Private Sub PrintDocument1_PrintPage(sender As Object, e As Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage
    7. 'hier kommt nun der Text auf die Seite
    8. End Sub
    9. Private Sub PrintDocument1_EndPrint(sender As Object, e As PrintEventArgs) Handles PrintDocument1.EndPrint
    10. 'hier wird bereinigt
    11. End Sub


    Nun möchte ich noch den PrintPreviewDialog durch ein PrintPreviewControl erstetzen. Da ich das PrintPreviewDialog optisch grauenvoll finde.
    Das funktioniert auch alles. Ich habe einen PrintPreviewDialog auf die Form gezogen und verwende folgenen Code:

    VB.NET-Quellcode

    1. Private Sub PrintPreview()
    2. 'PrintDocument1.PrinterSettings.PrinterName = "Microsoft Print to PDF"
    3. Dim DefaultPrinter As New PrintDocument
    4. PrintDocument1.PrinterSettings.PrinterName = DefaultPrinter.PrinterSettings.PrinterName
    5. PrintPreviewDialog1.Document = PrintDocument1
    6. PrintPreviewControl1.Document = PrintPreviewDialog1.Document
    7. PrintPreviewControl1.AutoZoom = True
    8. End Sub
    9. Private Sub BTNPrintPreview_Click(sender As Object, e As EventArgs) Handles BTNPrintPreview.Click
    10. PrintPreview()
    11. End Sub
    12. Private Sub BTNPrint_Click(sender As Object, e As EventArgs) Handles BTNPrint.Click
    13. PrintPreview()
    14. 'Dim DefaultPrinter As New PrintDocument
    15. 'PrintDocument1.PrinterSettings.PrinterName = DefaultPrinter.PrinterSettings.PrinterName
    16. PrintDocument1.Print()
    17. End Sub


    In der Vorschau sehe ich problemlos zwei Seiten im PrintpreviewControl. Wenn ich das ganze aber drucke mit der BTNPrint_Click Sub, landet nur die letzte Seite auf Papier, bzw. in der pdf.
    Leider kann ich das ganze nicht schrittweise durchlaufen lassen, dann streikt mein VS an der Stelle an der ich den pdf Namen eingeben muss, und hängt sich auf.

    Hast du eine Idee, was ich hier falsche mache, oder soll ich dir das nochmal in die Demo Anwendung einbauen?

    Edit: Ich habe dafür meine Demo Solution nochmal umgebaut.
    Hier sieht man jetzt schön, dass bei einem Klick auf "drucken" der Drucker gestartet wird (bzw. das Eingabefenster für Dateiname bei pdf Drucker) erscheint und dann erst die Seiten hochgezählt werden.
    Dateien
    • PPDTedt.zip

      (24,28 kB, 1 mal heruntergeladen, zuletzt: )

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

    DerSmurf schrieb:

    es werden nicht bei jeder Seite die Daten neu geladen.
    Die Daten müssen bei BeginPrint vollständig vorliegen.
    ====

    VB.NET-Quellcode

    1. Private Sub PrintPreview()
    2. PrintPreviewDialog1.Document = PrintDocument1
    3. PrintPreviewControl1.Document = PrintPreviewDialog1.Document
    4. PrintPreviewControl1.Rows = 2
    5. PrintPreviewControl1.Columns = 4
    6. End Sub
    Die Verwendung des PrintPreviewControls ist suboptimal, da Dir die Button-Leiste fehlt.
    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!

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

    RodFromGermany schrieb:

    Die Daten müssen bei BeginPrint vollständig vorliegen.

    bedeutet das, dass ich meine Sub aus dem PrintPage Handler in BeginPrint verschieben muss?
    Kann ja nicht sein. Ich verstehe gerade nicht ,wie ich am Ende der BeginPrint Sub vollständige Daten haben soll.
    Immerhin wird doch danach erst die eigentliche Druck Sub (PrintPage) aufgerufen? Oo

    RodFromGermany schrieb:

    Die Verwendung des PrintPreviewControls ist suboptimal, da Dir die Button-Leiste fehlt.

    Da hast du recht. Aber der PrintPreviewDialog bringt mir ja keinen wirklichen Vorteil.
    Es wird ein Druck erstellt (den ich mir in den seltensten Fällen überhaupt angucken möchte), und nach Klick auf drucken kommts auf Papier.
    So war es ja vorher auch mit meiner pdf.

    DerSmurf schrieb:

    verschieben muss?
    Nicht müsen, aber der Print-Handler wird für jede Seite einzeln aufgerufen, also bei Deinem Beispiel 8 Mal.
    Da wäre es suboptimal, wenn Du die Daten 8 Mal berechnest.
    Wenn Du weißt, dass nur eine Seitze gedruckt wird, könnte es im Print-Event bleiben.
    Allerdings weiß ich, dass es selten bei dieser einen Seite bleibt.
    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!
    IDa wir uns hier ja nur im Kreis drehen, habe ich nun etwas im Netz gefunden und für mich abgewandelt: Link

    VB.NET-Quellcode

    1. Private Sub BTNPrint_Click(sender As Object, e As EventArgs) Handles BTNPrint.Click
    2. ' Zuerst die Definition des Dokuments
    3. Dim lPD As New System.Drawing.Printing.PrintDocument()
    4. lPD.DocumentName = "Name des Dokuments"
    5. GetInvoiceData() 'Läd alle Daten
    6. ' Die Funktion PDPrintPage wird jedesmal aufgerufen, bevor das
    7. ' Dokument eine neue Seite drucken will.
    8. AddHandler lPD.PrintPage, AddressOf PDPrintPage
    9. AddHandler lPD.EndPrint, AddressOf PDDEndPrint
    10. ' Seitenzahl in eigener Variable initialisieren
    11. Pagenumber = 1
    12. arraycount = 0
    13. lPD.Print()
    14. End Sub
    15. Private Sub PDPrintPage(ByVal sender As System.Object,
    16. ByVal e As System.Drawing.Printing.PrintPageEventArgs)
    17. 'Hier werden die Seiten erstellt
    18. End Sub
    19. GetInvoiceData()
    20. PrintPreviewDialog1.Document = lPD
    21. PrintPreviewControl1.Document = lPD
    22. ' Seitenzähler auf Anfangswert!
    23. Pagenumber = 1
    24. arraycount = 0
    25. ' Das Dokument mit seinem Handler verbinden
    26. AddHandler lPD.PrintPage, AddressOf PDPrintPage
    27. AddHandler lPD.EndPrint, AddressOf PDDENdPrint
    28. lPD = Nothing
    29. End Sub
    30. Private Sub PDDENdPrint(sender As Object, e As PrintEventArgs) Handles PrintDocument1.EndPrint
    31. 'hier wird aufgeräumt
    32. End Sub


    Nun ist zwar mein begin Print Handler verschwunden, aber das ganze funktioniert.
    Und wenn ich dich jetzt richtig verstanden habe, müsste der ja eh weg.
    Nun weiß ich nicht, ob ich meine erstellten Handler im Code lassen soll, oder sie wieder per Designer erzeuge, aber das ist ja wahrscheinlich egal.

    RodFromGermany schrieb:

    Allerdings weiß ich, dass es selten bei dieser einen Seite bleibt.

    Dai ich weiß wie viele Artikel ich gewöhnlicherweise per Hand auf einen Rechnungsblock schreibe, darf ich behaupten, dass ich das an dieser Stelle besser weiß als du.
    Es wird zu 95% immer eine Seite sein. Aber trotzdem soll ja auch mehrseitigkeit funktionieren.
    @DerSmurf Was soll der Tinnef mit AddHandler? Sollte da nicht wenigstens bei PDPrintPage ein RemoveHandler stehen?
    Ansonsten ist dieser Code für die Tonne. Sorry.
    Und:
    Schön, dass 95% Deiner Ausdrucke auf eine Seite passen, bei mir kein einziger. ;)
    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!
    Ich habe die Handler, sowie die Deklaration des PrintDocuments innerhalb der Subs entfernt, und nutze das PrintDocument1, welches ich auf die Form gezogen habe.
    Also ist es jetzt letztlich der gleiche Code wie vorher, nur dass es kein BeginPrint mehr gibt (und das ich mehrere Seiten drucken kann)

    RodFromGermany schrieb:

    Schön, dass 95% Deiner Ausdrucke auf eine Seite passen, bei mir kein einziger.

    Bei mir ist es nur eine Ergänzung zum Kassenbon.
    Quasi damit ich keine Rechnungen mehr von Hand schreiben muss - daher nur als Ergänzung und nicht Buchführungsrelevant.
    Es passen in ca. 15 Artikel auf eine Seite - mehr habe ich erst einmal von Hand geschrieben.

    DerSmurf schrieb:

    Es passen in ca. 15 Artikel auf eine Seite
    OK.
    Wo liegt das Problem?
    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!
    Das Problem ist hier:

    RodFromGermany schrieb:

    Ansonsten ist dieser Code für die Tonne. Sorry.


    Ist er immernoch für die Tonne, wenn die Handlererstellung, und die PrintDocument Erstellungen aus dem Code verschwinden, und ich stattdessen das PrintDocument1 aus dem Designer verwende?
    Code kommt heute Abend, mein Laptop Akku ist alle.