Drawstring zündet nicht

  • VB.NET

Es gibt 27 Antworten in diesem Thema. Der letzte Beitrag () ist von -Franky-.

    Drawstring zündet nicht

    Hallo,

    ich habe vor langer Zeit einige Programme in VB6 zur Berechnung von Daten erstellt. Ich habe den Print-Befehl verwendet um die Berechneten Werte auf einem separaten Formular auszugeben. Ich möchte diese Programme nun alle in Visual Studio konvertieren und habe mit dem "Drawstring" Schwierigkeiten.
    Um ein generelles Gefühl zu bekommen habe ich einfach 2 Formulare erstellt. Beim ersten gebe ich ein Text in einer Textbox ein, lasse es verschwinden und rufe das Ausgebeformular auf. In VB6 habe ich den Form_Activate Event beim Öffnen des zweiten Fensters benutzt um dann die Daten aus dem Input des ersten Fensters zu berechnen an entsprechender Stelle auf dem neuen Fenster auszugeben. Sieht bei mir so aus:

    VB.NET-Quellcode

    1. Private Sub Form2_Activated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Activated
    2. Dim Grafik As Graphics = Me.CreateGraphics
    3. Dim Fo As New Font("Courier New", 20, FontStyle.Bold, GraphicsUnit.Point)
    4. Grafik.Clear(Color.Yellow)
    5. Grafik.DrawString(PrText, Fo, Brushes.Black, XPos + 500, YPos + 90)
    6. End Sub


    Das Formular bleibt aber leer, es wird nicht mal gelb obwohl ich sehen kann, daß die Zeilen abgehandelt werden. Das selbe hinter einem Button_Click klappt aber.

    VB.NET-Quellcode

    1. Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    2. Dim Grafik As Graphics = Me.CreateGraphics
    3. Dim Fo As New Font("Courier New", 20, FontStyle.Bold, GraphicsUnit.Point)
    4. Grafik.Clear(Color.Yellow)
    5. Grafik.DrawString(PrText, Fo, Brushes.Black, XPos + 500, YPos + 90)
    6. End Sub


    Wie schaffe ich es, daß das Formular erzeugt wird ohne das ich einen Button brauche?

    Wäre für jegliche Hilfe dankbar
    Teste das mal:

    VB.NET-Quellcode

    1. Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    2. Draw(e.Graphics)
    3. End Sub
    4. Private Sub Draw(g As Graphics)
    5. Dim txt As String = "Hallo"
    6. Using f As New Font("Arial", 16)
    7. g.Clear(Color.Yellow)
    8. g.DrawString(txt, f, Brushes.Black, 500, 50)
    9. End Using
    10. End Sub
    Willkommen im Forum.
    Der Code läuft. Aber zu einem anderen Zeitpunkt als Du denkst. Und anders als Du denkst. Minimiere mal das Form und dann wiederherstellen. Tada! Und dann das Form teilweise aus dem Bildschirm schieben und dann wieder zurück: Zonk!
    Nimm das Form-Paint-Event.
    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.
    Hallo ErfinderDesRades,
    da ich im Moment das Rad neu erfinde, ich habe außer VB6 nichts gemacht, kann ich damit wenig anfangen. Ich wollte form2.graphics.... verwenden und bekam eine Meldung ich soll me.garaphics... verwenden. Könntest Du das etwas erläutern?
    Kein form2.graphics, kein me.garaphics, kein CreateGraphics, sondern e.Graphics. Dabei ist e das, was dem EventHandler vom System übergeben wird.

    VB.NET-Quellcode

    1. Private Sub Form2_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    e ist also der 2. Parameter des Paint-EventHandlers. Wird Dir quasi automatisch generiert.
    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.
    @JLH Allerdings genügt das noch nicht.
    Das Paint-Event muss das ganze Control "aus dem Gedächtnis hereaus" zeichnen. Dazu sind Variablen und Flags erforderlich bzw. sinnvoll.
    Außerdem muss das Darstellen selbst angetriggert werden, sonst wird nur dann gemalt, wenn die Form minimiert und wieder hergestellt wird.
    Teste folgenden Code in einem neuen Projekt: Form und Button, drücke permanent auf den Button:

    VB.NET-Quellcode

    1. Public Class Form2
    2. Private Index As Integer = 0
    3. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    4. Me.Index += 1
    5. If Me.Index = 5 Then
    6. Me.Index = 0
    7. End If
    8. Me.Invalidate()
    9. End Sub
    10. Private Sub Form2_Paint(sender As Object, e As PaintEventArgs) Handles MyBase.Paint
    11. If Me.Index > 0 Then e.Graphics.DrawLine(Pens.Red, 10, 10, 150, 10)
    12. If Me.Index > 1 Then e.Graphics.DrawLine(Pens.Red, 10, 10, 10, 150)
    13. If Me.Index > 2 Then e.Graphics.DrawLine(Pens.Red, 10, 150, 150, 150)
    14. If Me.Index > 3 Then e.Graphics.DrawLine(Pens.Red, 150, 10, 150, 150)
    15. End Sub
    16. 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!
    Danke aber leider bin ich jetzt wieder so schlau wie am Anfang. Im Lehrprogramm klappt das wunderbar, nicht aber im echten. Ich denke ich hatte das bereits anfangs so und bin dann so weit umhergeirrt bis ich mein Code mit dem Form_Print-Event heute Mittag zum laufen gebracht habe... aber das soll ich ja unterlassen. Ich kann den Code nicht posten aber im wesentlichen läuft folgendes ab:

    Nach Eingabe aller Parameter wird Eingabe Form1 geschlossen, alles berechnet und Form2 aufgerufen.

    VB.NET-Quellcode

    1. Sub Form2_Activated
    2. Sub1
    3. End Sub
    4. Sub1 (Generiert das Layout wie wo was wann gedruckt werden soll)
    5. PosX=0
    6. PosY=0
    7. Var1=Parameter1
    8. String=" Irgwendwas "
    9. Sub2
    10. me.validate() (Erste Zeile wurde generiert und soll jetzt auf Bildschirm erscheinen)
    11. ... zweite Zeile
    12. ... dritte Zeile
    13. ... usw
    14. End Sub
    15. Sub2
    16. baut aus Var1, String und sonstiges eine Zeile in Variable "Ausgabe" zusammen und legt den Font "Fo" fest.
    17. End Sub
    18. Private Sub frmAusgabe_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
    19. e.Graphics.DrawString(Ausgabe, Fo, Brushes.Black, XPos, YPos)
    20. End Sub


    Er läuft über me.validate() aber nichts passiert. Wenn dann alle Zeilen durch sind erscheint nur die letzte Zeile.

    Mit

    VB.NET-Quellcode

    1. Dim Grafik As Graphics = Me.CreateGraphics
    2. Grafik.DrawString(Ausgabe, Fo, Brushes.Black, XPos, YPos)
    wo oben me.validate() steht
    klappt es.

    Warum ist das nicht praktikabel? Oder besser, warum zündet jetzt nicht der me.validate()? Ich habe auch Sub1 komplett in Form-Paint-Event gepackt, da flackert es aber mächtig und erkennen kann man nichts.

    Code-Tags eingefügt. ~Thunderbolt

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

    Das Problem scheint im Detail zu stecken.
    Wie sollen wir da helfen, wenn wir nur so ungefähren Pseudo-Code zu Gesicht bekommen?


    JLH schrieb:

    Warum ist das [me.CreateGraphics] nicht praktikabel?
    Wenn das Form verschoben wird, verkleinert/vergrössert, oder wenn Fenster darüber hin und hergeschoben werden, kommt es zu Darstellungsfehlern.
    Ausserdem stellt das ein Memory-Leak dar, wodurch u.U. immer mehr System-Resourcen belegt werden bis sich das System verlangsamt.

    Poste mal deinen Code und nicht irgend nen pille palle pseudo Code. So kann man dir ja gar nicht richtig Helfen...

    JLH schrieb:

    Er läuft über me.validate() aber nichts passiert.
    Sollte das nicht Me.Invalidate() lauten? Weil dadurch wird das Paint Event ausgelöst, in dem man wiederum Zeichnen kann.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Hier mal was ich im Sinn machen möchte. Es soll 3x den selben Text an unterschiedlicher Stelle ausgeben. Es kommt aber nichts.
    Natürlich mit "invalidate()", hatte mich verschrieben.

    VB.NET-Quellcode

    1. ​Public Class Form1
    2. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    3. PrText = TextBox1.Text
    4. Me.Hide()
    5. Form2.Show()
    6. End Sub
    7. End Class


    VB.NET-Quellcode

    1. Public Class Form2
    2. Dim Ausgeben As Integer = 0 'Keine Ausgabe
    3. Private Sub Form2_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles MyBase.Paint
    4. Select Case Ausgeben
    5. Case 1 'Ausgeben
    6. e.Graphics.DrawString(PrText, Fo, Brushes.Blue, XPos, YPos)
    7. End Select
    8. End Sub
    9. Private Sub Form2_Activated(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Me.Activated
    10. Ausgabe()
    11. End Sub
    12. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    13. Ausgabe()
    14. End Sub
    15. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    16. End
    17. End Sub
    18. Sub Ausgabe()
    19. Ausgeben = 1 'Ausgabe ein
    20. YPos = 0
    21. Me.Invalidate()
    22. YPos = 100
    23. Me.Invalidate()
    24. YPos = 500
    25. Me.Invalidate()
    26. Ausgeben = 0 'Ausgabe aus
    27. End Sub
    28. End Class


    VB.NET-Quellcode

    1. ​Module Module1
    2. Public PrText As String
    3. Public Fo As New Font("Courier New", 10, FontStyle.Bold, GraphicsUnit.Point)
    4. Public XPos As Integer
    5. Public YPos As Integer
    6. End Module

    JLH schrieb:

    Er läuft über me.validate() aber nichts passiert.
    Klar, denn innerhalb einer Routine wird Paint nicht mehrmals bei mehrmaligem Aufruf von Invalidate aufgerufen, sondern erst nach Beenden der invalidisierenden Prozedur.

    JLH schrieb:

    Danke aber leider bin ich jetzt wieder so schlau wie am Anfang.
    Verstehe meinen Code.
    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!
    Danke Rod,
    Klar, denn innerhalb einer Routine wird Paint nicht mehrmals bei mehrmaligem Aufruf von Invalidate aufgerufen, sondern erst nach Beenden der invalidisierenden Prozedur.

    Das habe ich mir gedacht, da nur die letzte Zeile gedruckt wird. Deshalb habe ich ja auch nur den Pille Palle Code gepostet da man auch mit dem meine gedachte Struktur erkennen hätte können.

    ​Verstehe meinen Code.

    Den versteh ich ja. Selbst wenn Dein Vorschlag eine Lösung wäre kann ich nicht für jede auszugebende Zeile den User auf einen Button klicken lassen. Ich suche eine Lösung wie ich den „Print-Befehl„ aus VB6 umsetzen kann. Wie in folgendem Pille Palle Code Beispiel:

    Visual Basic-Quellcode

    1. S​ub Ausgabe
    2. Xpos=0
    3. Ypos=0
    4. Print Ausgabe$;
    5. Xpos=275
    6. Ypos=0
    7. Print Ausgabe$;
    8. Usw....
    9. End Sub


    Die Zeilen die hier fehlen dienen nur der Aufbereitung der String$-Variable und Berechnung der Xpos und Ypos. Wie kann ich wo im VB6 Code Print steht ein Event innerhalb der Sub auslösen der dann Druckt? Stehe leider immer noch am Anfang.

    JLH schrieb:

    Den versteh ich ja.
    Offsichtlich nicht.
    Ist auch sehr schwer. Weil man muss wissen, dass Invalidate() die Paint-Methode verzögert aufruft.
    Es ist daher sinnlos dreimal hintereinander die Ausgabe-Variable umzusetzen, Invalidate() aufzurufen, und am Ende Ausgabe wieder auf 0.
    Aufgrund besagter Verzögerung wird das Paint 1/100s später aufgerufen, und nur einmal - obwohl du 3mal Invalidate() postuliertestest.
    Und dann ist Ausgabe ja wieder auf 0, und Paint wird dann tun, was es dann tun soll: nichts.

    Also wenn du 3 Strings Painten willst, rufe Invalidate einmal, und painte dann 3 Strings.
    Wie RFG gezeigt hat.
    Du kannst dir auch mein Tut zum Thema angucken, das geht sehr sehr viel tiefer in die Thematik ein.
    Aber es erklärt auch die Basics.
    OwnerDrawing

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    2. End
    3. End Sub
    Das ist keine adäquate Programmbeendigungsmethode, sondern Holzhammer.
    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.
    OK, so langsam versteh ich gar nichts mehr. Ich möchte daher nochmal mein Problem neu formulieren.

    In VB6 habe ich ein Formular erzeugt indem ich Textbausteine generiere und sofort nach dem Generieren den String mit Print an PosX und PosY ausgebe. Den Befehl Print gibt es aber so nicht mehr in .Net.
    VB6 Code:

    String generieren
    x,y
    Print
    String generieren
    x,y
    Print

    Das habe ich nun in

    String generieren
    x,y
    me.invalidate()
    String generieren
    x,y
    me.invalidate()

    umgewandelt weil irgendwo steht, daß invalidate() das Print-Event auslöst. In meinem obigen Beispiel hatte ich erwartet, das der Code, der Einfachheit halber, den selben String 3x hintereinander auf unterschiedlicher Position Druckt. Es steht leider nirgends, daß das innerhalb einer Sub erst geht wenn die Sub fertig ist, noch wie lange man warten muß bis man es wieder verwenden darf. Womit kann ich den VB6 Print Befehl ersetzen? Es handelt sich um ca. 60 Bausteine die in X Kombinationen zusammengesetzt werden. Ich kann doch nicht für jede einen Button erstellen :(

    ein wirklicher Mehr-Aufwand ist es nicht unbedingt
    Naja, wenn ich das mit dem Print-Befehl in VB6 vergleiche......