Problem mit MeasureString

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von EliotM.

    Problem mit MeasureString

    Hallo,
    ich bin dran, ein Kochbuch-Programm, das ich ca. 2002 in VB6 programmiert habe, mit VB.NET 2012 nachzubauen.
    Mein Problem ist, dass ich mit dem MeasureString anscheinend keine richtigen Werte bekomme. Ich nehme den Text aus verschiedenen TextBoxen zum Ausdrucken.
    Die Maße der Rechtecke für den Text stimmen nicht.
    Warum bekomme ich bei (sind 4 Zeilen mit Umbruch) für S Height= ca. 77:

    VB.NET-Quellcode

    1. Dim fnt1 As New Font("Courier New", 12, FontStyle.Regular)
    2. Dim S As SizeF
    3. S = e.Graphics.MeasureString(Txt5, fnt1)

    und bei einem anderen Text mit gleicher Schrift (sind 9 Zeilen zT mit Umbruch) den Wert: S Height= ca. 96,5?
    Aus diesen Werten wird die Höhe ausgerechnet, die x Anzahl Zeilen dann nicht stimmt.

    Vllt. denke ich auch falsch?
    EliotM

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

    @EliotM Willkommen im Forum. :thumbup:
    Wie sollen wir wissen, warum Dein Output falsch ist, wenn wir den Input nicht kennen?
    Was genau steht in Txt5?
    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 Danke für die Willkommensgrüße!
    Warum ist es wichtig, was da drin steht? Da steht einfacher Text in einer TextBox drin, jedes mal ein anderer.
    Natürlich kann ich einen posten. Aber die Zutaten eines Rezepts sind nicht so interessant!? :)
    Oder habe ich Dich falsch verstanden? Die Schrift in den TextBoxen ist identisch mit dem Ausdruck.
    @EliotM Um Dir zu helfen, müssen wir zunächst nachvollziehen, was da los ist.
    Ohne Daten geht das bei mir leider nicht, da meine Glaskugel gerade zur Reparatur ist. ;(
    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
    Ich habe in VB.net noch nicht viel mit Drucken gemacht und arbeite mich gerade ein.
    Hier mal der Code:

    VB.NET-Quellcode

    1. Private Sub RezeptToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles RezeptToolStripMenuItem.Click
    2. ' PrintDocument-Objekt erstellen
    3. Dim pd As New System.Drawing.Printing.PrintDocument
    4. ' Ereignishandler hinzufügen
    5. AddHandler pd.PrintPage, AddressOf Me.Drucken
    6. ' Drucker festlegen
    7. pd.PrinterSettings.PrinterName = "PDFCreator"
    8. 'pd.PrinterSettings.PrinterName = "HP Officejet J4680 series" 'HP Officejet J4680 series
    9. ' Ausdruck starten
    10. pd.Print()
    11. End Sub
    12. Private Sub Drucken(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
    13. Dim X As Double = e.MarginBounds.Left - 25
    14. Dim Y As Double = e.MarginBounds.Top - 80
    15. Dim B As Double = e.MarginBounds.Width + 70
    16. Dim H As Double = e.MarginBounds.Height + 410
    17. Dim Txt0 As String
    18. Dim Txt1 As String
    19. Dim Txt2 As String
    20. Dim Txt3 As String
    21. Dim Txt4 As String
    22. Dim Txt5 As String
    23. Dim Txt6 As String
    24. Dim Txt7 As String
    25. Dim fnt0 As New Font("Courier New", 12, FontStyle.Bold)
    26. Dim fnt1 As New Font("Courier New", 12, FontStyle.Regular)
    27. Dim ZeilH As Integer = 17
    28. ' Höhe des mehrzeiligen Textes
    29. Dim Hoch As Double
    30. Dim U As Integer
    31. 'Dim format1 As New StringFormat(StringFormatFlags.DisplayFormatControl) 'NoClip
    32. With e.Graphics
    33. Dim S As SizeF
    34. ' Druck-Texte
    35. Txt0 = txtKNr.Text & " - " & txtRezeptName.Text & " - " & txtPproPer.Text & " P/P"
    36. Txt1 = cboKochbuch.Text & " " & txtPortionen.Text & " Portionen " & cboKategorie.Text & " " & txtGericht.Text
    37. Txt2 = txtZubZeit.Text & "/" & txtGarZeit.Text & " Min Quelle " & txtQuelle.Text & " " & txtBearbeiter.Text
    38. Txt3 = "Bem.: " & txtBemerkung.Text
    39. Txt4 = "Zutaten"
    40. Txt5 = Me.txtZutaten.Text
    41. Txt6 = "Zubereitung"
    42. Txt7 = Me.txtZubereitung.Text
    43. ' Überschrift und Einzelzeilen ausgeben
    44. .DrawString(Txt0, fnt0, New SolidBrush(Color.Black), CSng((e.PageBounds.Width - e.Graphics.MeasureString(Txt0, fnt0).Width) * 0.5), Y) : Y = Y + 2 * ZeilH 'y=20
    45. .DrawString(Txt1, fnt1, Brushes.Black, X, Y) : Y = Y + ZeilH 'y=54
    46. .DrawString(Txt2, fnt1, Brushes.Black, X, Y) : Y = Y + ZeilH 'y=71
    47. .DrawString(Txt3, fnt1, Brushes.Black, X, Y) : Y = Y + 2 * ZeilH 'y=88
    48. .DrawString(Txt4, fnt0, Brushes.Black, X, Y) : Y = Y + ZeilH 'y=122
    49. ' Größe (Ausmaß) des mehrzeiligen Textes
    50. S = .MeasureString(Txt5, fnt1) ', 12) 'S.W=438, H=77,6
    51. Hoch = Ausgabenhöhe(S, B)
    52. ' Rechteck für die Ausgabe des 1.TextBox-Textes
    53. Dim drawRect As New RectangleF(X, Y, B, Hoch)
    54. ' Text ausgeben
    55. .DrawString(Txt5, fnt1, Brushes.Black, drawRect) : Y = Y + Hoch + ZeilH
    56. .DrawString(Txt6, fnt0, Brushes.Black, X, Y) : Y = Y + ZeilH 'y=233,6
    57. ' Größe (Ausmaß) des mehrzeiligen Textes Zubereitung
    58. S = .MeasureString(Txt7, fnt1) ', 12) 'S.W=1520, H=96,5
    59. Hoch = Ausgabenhöhe(S, B)
    60. ' Rechteck für die Ausgabe des 2.TextBox-Textes
    61. Dim drawRect1 As New RectangleF(X, Y, B, Hoch) 'Y=250,6
    62. ' Text ausgeben
    63. .DrawString(Txt7, fnt1, Brushes.Black, drawRect1) : Y = Y + Hoch '+ ZeilH
    64. .DrawString(Txt4, fnt0, Brushes.Black, X, Y) ': Y = Y + 2 * ZeilH 'y=478 TEST
    65. End With
    66. ' keine weiteren Seiten
    67. e.HasMorePages = False
    68. End Sub
    69. ' Hilfsfunktion
    70. Public Function Ausgabenhöhe(ByVal S As SizeF, ByVal B As Double) As Double
    71. Dim H As Double
    72. If S.Width > B Then
    73. H = (S.Width / B) * S.Height
    74. Else
    75. H = S.Height
    76. End If
    77. Return H
    78. End Function


    Ich hoffe, dass die Form besser rauskommt als ich sie jetzt sehe! Bei mir in VB sieht sie besser aus.
    OK, nach dem Absenden ist es gut!

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

    @EliotM Wenn ich Deinen Code kopiere, kommen 29 Fehler.
    Also:
    Poste genau so viel Code, dass Dein Effekt reproduziert wird und dass der Code bis auf einen Button oder so compiliert.
    Besser wäre es in der Tat, Du hättest die beiden Textbeispiele gepostet, da wäre das klar gewsen.
    Wenn es ums Drucken geht, kannst Du auch hier mal reinschauen: Drucken mehrseitiger Dokumente
    =====================
    Ich denke mal, Du bist diesseits und jenseits des Knicks in Deiner Kennlinie, die Deine Funktion Ausgabenhöhe beschreibt:

    VB.NET-Quellcode

    1. Public Function Ausgabenhöhe(ByVal S As SizeF, ByVal B As Double) As Double
    2. Dim H As Double
    3. If S.Width > B Then
    4. H = (S.Width / B) * S.Height
    5. Else
    6. H = S.Height
    7. End If
    8. Return H
    9. End Function
    10. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    11. Dim B = 15
    12. For d = 10.0F To 20.0F Step 0.5F
    13. Dim s = New SizeF(d, d)
    14. Dim h = Ausgabenhöhe(s, B)
    15. ListBox1.Items.Add(String.Format("{0} - {1:0.00}", d, h))
    16. Next
    17. End Sub
    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“ ()

    Danke für Deine Geduld, aber ich frage nicht oft nach, wie etwas geht. Normalerweise bekomme ich es so hin.
    Oben habe ich den Code noch erweitert. Das ist alles, was ich zum Drucken habe.
    Hier mal der Text von txt5:

    400 g säuerliche Äpfel, 400 g Birnen,
    6 EL Öl, 125 g Zucker, 1 P. Vanillezucker,
    3 Eier, 150 g Mehl, 1/4 l Milch,
    1 EL Zucker zum Bestreuen

    und der von txt7:

    Äpfel und Birnen schälen, kleinschneiden und in eine gefettete Springform 25-28 cm Durchmesser (besser: Pie-Form) geben.
    Zucker, Vanillezucker, das restliche Öl, die Eier und das Mehl zu einem Teig rühren. Milch hinzufügen.
    Den Teig - er hat eine Konsistenz wie Pfannkuchenteig - über das Obst gießen und die Form in den vorgeheizten Ofen (2. Schiene von unten( schieben.
    Bei 200°C ca. 45 Min. backen.
    Gleich mit Zucker bestreuen und evtl. warm servieren.

    Wenn ich 2 oder mehr Rezepte pro Seite drucke, ist es nicht tragbar, dass die Abstände nicht stimmen.
    Ich knoble schon 3 Tage an diesem Prob. Deinen Link werde ich morgen durcharbeiten, wenn ich ihn nicht schon bei meiner Suche gefunden hatte.
    Sorry, habe gerade gesehen: habe Option Strict Off zur Zeit, werde es aber wieder in Option Strict On ändern. das gibt narürlich Fehler!

    Gruß
    EliotM

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

    @EliotM Ich hab eben noch mal den Post editiert, sieh Dir das mal 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!
    @RodFromGermany
    Habe es gesehen, ab ca. 16 läuft die Höhe anders.
    Kann ich das bei mir kompensieren oder wie könnte ich das bei mir korrigieren?
    Bin heute noch dran mein Strict Off noch zu ändern. Hatte es mal kurz abgeschaltet und vergessen auf On zu stellen.
    Melde mich morgen wieder.
    Danke für Dein Engagement!

    Habe gerade (00:49 h) noch Deinen Link von oben angeschaut. Dieses Tut habe ich schon vor 3 Tagen durchgearbeitet. Super Beitrag!
    Ist bereits in meiner Sammlung.

    Habe gerade noch festgestellt, dass es auf die Zeilenumbrüche ankommt. Je Zeilenumbruch ist die S.Heigt um ca. 19,5 höher.
    Also bei 3 Returns im Text 77,60. Wenn dann die Länge mit der Function in Höhe umgewandelt wird, werden die Returns im Text nicht mehr berücksichtigt! Muss mal überlegen, wie ich das überliste! :)
    Das scheint nicht so einfach zu sein! Ich müsste die Länge eines jeden Teilstrings bis und zwischen den Zeilenumbrüchen bestimmen, das ist nicht die eleganteste Art für mich!
    Bin ich eigentlich der erste, der diverse Strings mit Umbrüchen hintereinander drucken will????
    Die ganzen Tuts, die ich bis jetzt durchgearbeitet habe, hatten das nicht.

    Wenn Ihr also wisst, wo ich sowas finden kann oder Ihr wisst, wie es geht, dann bitte ich um Antworten....danke.

    Ich habe gestern Abend noch eine Lösung gefunden: mit "Split(TextBox.Text, vbCrLf)" wird der Text zerlegt. Ich werde den Code noch posten, wenn es eingearbeitet ist. :thumbsup:

    VB.NET-Quellcode

    1. Private Sub RezeptToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles RezeptToolStripMenuItem.Click
    2. Dim pd As New System.Drawing.Printing.PrintDocument
    3. ' Ereignishandler hinzufügen
    4. AddHandler pd.PrintPage, AddressOf Me.Drucken
    5. ' Drucker festlegen
    6. pd.PrinterSettings.PrinterName = "PDFCreator"
    7. 'pd.PrinterSettings.PrinterName = "HP Officejet J4680 series" 'HP Officejet J4680 series
    8. ' Ausdruck starten
    9. pd.Print()
    10. End If
    11. End Sub
    12. Private Sub Drucken(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs)
    13. ' Maße des druckbaren Bereichs
    14. Dim X As Double = e.MarginBounds.Left - 25
    15. Dim Y As Double = e.MarginBounds.Top - 80
    16. Dim B As Double = e.MarginBounds.Width + 70
    17. Dim H As Double = e.MarginBounds.Height + 410
    18. Dim Txt0 As String
    19. Dim Txt1 As String
    20. Dim Txt2 As String
    21. Dim Txt3 As String
    22. Dim Txt4 As String
    23. Dim Txt5 As String
    24. Dim Txt6 As String
    25. Dim Txt7 As String
    26. ' Schriftart für Überschrift und eigentlichen Text festlegen...
    27. Dim fnt0 As New Font("Courier New", 12, FontStyle.Bold)
    28. Dim fnt1 As New Font("Courier New", 12, FontStyle.Regular)
    29. Dim ZeilH As Integer = 17
    30. Dim sLine() As String
    31. ' Höhe des mehrzeiligen Textes
    32. Dim Hoch As Double
    33. '-----------------------------------------------------------
    34. With e.Graphics
    35. Dim S As SizeF
    36. ' Druck-Texte
    37. Txt0 = txtKNr.Text & " - " & txtRezeptName.Text & " - " & txtPproPer.Text & " P/P"
    38. Txt1 = cboKochbuch.Text & " " & txtPortionen.Text & " Portionen " & cboKategorie.Text & " " & txtGericht.Text
    39. Txt2 = txtZubZeit.Text & "/" & txtGarZeit.Text & " Min Quelle " & txtQuelle.Text & " " & txtBearbeiter.Text
    40. Txt3 = "Bem.: " & txtBemerkung.Text
    41. Txt4 = "Zutaten"
    42. Txt5 = Me.txtZutaten.Text
    43. Txt6 = "Zubereitung"
    44. Txt7 = Me.txtZubereitung.Text
    45. ' Überschrift und Einzelzeilen ausgeben
    46. .DrawString(Txt0, fnt0, New SolidBrush(Color.Black), CSng((e.PageBounds.Width - e.Graphics.MeasureString(Txt0, fnt0).Width) * 0.5), CSng(Y)) : Y += 2 * ZeilH
    47. .DrawString(Txt1, fnt1, Brushes.Black, CSng(X), CSng(Y)) : Y += ZeilH
    48. .DrawString(Txt2, fnt1, Brushes.Black, CSng(X), CSng(Y)) : Y += ZeilH
    49. .DrawString(Txt3, fnt1, Brushes.Black, CSng(X), CSng(Y)) : Y += 2 * ZeilH
    50. .DrawString(Txt4, fnt0, Brushes.Black, CSng(X), CSng(Y)) : Y += ZeilH + 3
    51. '-------------------------------------------------------------------------------------------
    52. ' Größe (Ausmaß) des mehrzeiligen Split-Textes Zutaten
    53. B = 485 'noch testen
    54. sLine = Split(txtZutaten.Text, vbCrLf)
    55. For I = 0 To UBound(sLine)
    56. S = .MeasureString(sLine(I), fnt1) ', 12)
    57. Hoch = Ausgabenhöhe(S, B)
    58. ' Rechteck für die Ausgabe des 2.TextBox-Textes
    59. Dim drawRect1 As New RectangleF(CSng(X), CSng(Y), CSng(B), CSng(Hoch))
    60. ' Text ausgeben
    61. .DrawString(sLine(I), fnt1, Brushes.Black, drawRect1) : Y += Hoch
    62. Next I
    63. Y += ZeilH
    64. '-------------------------------------------------------------------------------------------
    65. .DrawString(Txt6, fnt0, Brushes.Black, CSng(X), CSng(Y)) : Y += ZeilH + 3
    66. '-------------------------------------------------------------------------------------------
    67. ' Größe (Ausmaß) des mehrzeiligen Split-Textes Zubereitung
    68. B = 697
    69. sLine = Split(txtZubereitung.Text, vbCrLf)
    70. For I = 0 To UBound(sLine)
    71. S = .MeasureString(sLine(I), fnt1)
    72. Hoch = Ausgabenhöhe(S, B)
    73. ' Rechteck für die Ausgabe des 2.TextBox-Textes
    74. Dim drawRect1 As New RectangleF(CSng(X), CSng(Y), CSng(B), CSng(Hoch))
    75. ' Text ausgeben
    76. .DrawString(sLine(I), fnt1, Brushes.Black, drawRect1) : Y += Hoch + 3
    77. Next I
    78. '----------------------------------------------------------------------------------------------
    79. End With
    80. ' keine weiteren Seiten
    81. 'e.HasMorePages = False
    82. '// Check to see if more pages are to be printed.
    83. e.HasMorePages = (StringTrimming.None > 0) '?????
    84. Me.pageNb += 1
    85. End Sub
    86. ' Hilfsfunktion
    87. Public Function Ausgabenhöhe(ByVal S As SizeF, ByVal B As Double) As Double
    88. Dim H As Double
    89. If S.Width > B Then
    90. H = (S.Width / B)
    91. Multi = Int(S.Width / B)
    92. If H > Multi Then Multi = Multi + 1 'Aufrunden zB: 3.1 auf 4
    93. H = Multi * 19 ' S.Height
    94. Else
    95. H = 17
    96. Multi = 1
    97. End If
    98. Return H
    99. End Function


    So funktioniert es. Die kleinen Korrekturen mag ich zwar nicht, lassen sich aber wahrscheinlich nicht vermeiden.
    Fertig ist es noch nicht. Mehrere Seiten drucken, vor Druck prüfen, ob ganzes Rezept noch drauf geht.....

    Gruß
    EliotM

    Dieser Beitrag wurde bereits 10 mal editiert, zuletzt von „EliotM“ ()