Rechteck zeichnen -> Programm stürzt ab

  • VB.NET

Es gibt 29 Antworten in diesem Thema. Der letzte Beitrag () ist von FAtheone.

    Rechteck zeichnen -> Programm stürzt ab

    Da mich meine nächsten paar geplanten Programm-Features wohl zum Nutzen von GDI+ zwingen werden, wollte ich für den Einstieg mal einfach nur Koordinaten aus Textboxen auslesen und aus diesen dann eben ein Reckteck über eine Picturebox zeichnen. Dazu habe ich mich mal in einem Tutorialvon martinustreveri ein bisschen schlau gemacht und folgendes zusammengebastelt.

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click, PictureBox1.Paint
    2. Dim graphic As Graphics = Me.CreateGraphics
    3. Dim pen As New Pen(Color.Red, 1)
    4. Dim rec As New Rectangle(PictureBox1.Location.X + CInt(TextBox2.Text), PictureBox1.Location.Y + CInt(TextBox3.Text), CInt(TextBox4.Text), CInt(TextBox5.Text))
    5. graphic.DrawRectangle(pen, rec)
    6. End Sub


    Allerdings stürtzt das Programm gleich beim starten ab, schließlich ist in den Textboxen auch noch kein Wert. Ohne "Handles PictureBox1.Paint" zeichnet sich nichts wenn man auf den Button klickt, daher dachte ich mir mal, dann wirds sicher daran liegen, dass er ein paint event verlangt, aber das macht das ganze ja nur noch schlimmer :/
    probiers mal damit:

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click, PictureBox1.Paint
    2. Try
    3. Dim graphic As Graphics = Me.CreateGraphics
    4. Dim pen As New Pen(Color.Red, 1)
    5. Dim rec As New Rectangle(PictureBox1.Location.X + CInt(TextBox2.Text), PictureBox1.Location.Y + CInt(TextBox3.Text), CInt(TextBox4.Text), CInt(TextBox5.Text))
    6. graphic.DrawRectangle(pen, rec)
    7. Catch ex As Exception
    8. MsgBox(ex.message)
    9. End Try
    10. End Sub


    dann kriegst du ne genaue Fehlermeldung...
    Ich verwende dafür meistens eine Globale Boolean Variable, die Grafikbefehle im Paint Event dürfen erst ausgeführt werden, wenn alle benötigten Parameter vorhanden sind.
    Also im Paint Event als erstes sowas wie:

    VB.NET-Quellcode

    1. if PainterReady = False Then Exit Sub
    oder etwas ähnliches (Mal ganz einfach dargestellt^^). Wenn dann deine Grafikbefehle gültige Werte bekommen haben, kannst du PainterReady auf True setzen.
    Als Überprüfung ob alle nötigen Eingaben getätigt wurden, wollte ich einfach

    VB.NET-Quellcode

    1. If (TextBox2.TextLength > 0 & TextBox3.TextLength > 0 & TextBox4.TextLength > 0 & TextBox5.TextLength > 0) Then
    Abfrage ob alle Textboxen einen Wert größer 0 haben, aber hat nicht so wirklich geklappt. Aber den Boolean Trick merk ich mir ;)


    Nach EiPotts Methode habe ich es auch versucht(ich habe schon im Designer Werte in die Boxen geschrieben um Fehler zu vermeiden, bis mir die Überprüfung gelingt):

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click, PictureBox1.Paint
    2. PictureBox1.Invalidate()
    3. End Sub
    4. Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    5. Dim graphic As Graphics = PictureBox1.CreateGraphics
    6. Dim pen As New Pen(Color.Red, 1)
    7. Dim rec As New Rectangle(PictureBox1.Location.X + CInt(TextBox2.Text), PictureBox1.Location.Y + CInt(TextBox3.Text), CInt(TextBox4.Text), CInt(TextBox5.Text))
    8. graphic.DrawRectangle(pen, rec)
    9. End Sub

    Das Paint-Event wird ja schon beim Laden der Picturebox gestartet und lässt den Rest der Form nicht korrekt darstellen bis man sie verschiebt. Zusätzlich passt sich das Rechteck immer den Werten in den Boxen an, aber flackert ziemlich stark :/

    Bowserkoopa schrieb:

    Zusätzlich passt sich das Rechteck immer den Werten in den Boxen an, aber flackert ziemlich stark :/
    Das Flackern bekommst du verringert, wenn du in den Eigenschaften der Form DoubleBuffered=True einstellst. Scheint aber auch noch net die optimale Lösung zu sein (zumindest bei meinem DYCP Scroller nicht, aber der schaufelt auch einiges an Werten hin und her).
    Eigentlich ist DoubleBuffered sogar schon auf true gestellt, aber es ruckelt trotzdem noch ziemlich übel + die Form lädt zu Beginn nicht ganz und muss erst verschoben werden damit sie ganz sichtbar wird. Sieht fast so aus, als wäre GDI nicht sehr performant :/ Gibts denn da keine andere Möglichkeit? Schließlich wird ja GDI eigentlich in vielen Programmen verwendet.

    der_Kurt schrieb:

    If (TextBox2.TextLength > 0 AND TextBox3.TextLength > 0 ...

    AND bewirkt eine logische Verknüpfung, '&' ist ein Verkettungsoperator!

    Arg, wie konnte ich das nur übersehen X(
    Ok, ich weiß jetzt zwar nicht wieso, aber es funktioniert komischerweise. Außerdem dachte ich immer, dass das Paint-Event andauernd ausgeführt wird, aber dem scheint nicht so(und genau das verwirrt mich). Jetzt wird das Rechteck nämlich nur noch auf Buttonklick erstellt, nicht wenn ich den Text ändere(dann müsste die Überprüfung ja zutreffen und das Rechteck gezeichnet werden)

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    2. PictureBox1.Invalidate()
    3. End Sub
    4. Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    5. Dim Rechteck As New Rectangle(10, 10, 100, 150)
    6. Dim RoteFarbe As New System.Drawing.Pen(System.Drawing.Color.Red)
    7. If (TextBox2.TextLength > 0) Then
    8. e.Graphics.DrawRectangle(RoteFarbe, Rechteck)
    9. Debug.Print("Paint")
    10. End If
    11. End Sub
    Außerdem dachte ich immer, dass das Paint-Event andauernd ausgeführt wird, aber dem scheint nicht so(und genau das verwirrt mich)

    Deine Türklingel läutet ja auch nicht andauernd, sonder nur dann, wenn jemand draufdrückt ('Ring'-Event :D )
    Das Paint-Event wird dann ausgeführt, wenn etwas über das entsprechende Steuerelement "gezeichnet" wurde, und VB den darunterliegenden Bereich wiederherstellen muß. Sonst nicht. Schon gar nicht andauernd. Da würde dein PC zum Rauchen anfangen.

    Bowserkoopa schrieb:


    Ok, ich weiß jetzt zwar nicht wieso, aber es funktioniert komischerweise. Außerdem dachte ich immer, dass das Paint-Event andauernd ausgeführt wird, aber dem scheint nicht so(und genau das verwirrt mich). Jetzt wird das Rechteck nämlich nur noch auf Buttonklick erstellt, nicht wenn ich den Text ändere(dann müsste die Überprüfung ja zutreffen und das Rechteck gezeichnet werden)

    Du könntest das Steuerelement zum Beispiel per Timer automatisch neuzeichnen lassen.

    VB.NET-Quellcode

    1. PictureBox1.Invalidate()


    Ich würde wohl mit einem Timer arbeiten, der die ganze Zeit automatisch invalidiert und nur mit meiner Boolean das Zeichnen entweder erlauben oder verbieten. Kommt halt drauf an, was du beabsichtigst.

    der_Kurt schrieb:

    Außerdem dachte ich immer, dass das Paint-Event andauernd ausgeführt wird, aber dem scheint nicht so(und genau das verwirrt mich)

    Deine Türklingel läutet ja auch nicht andauernd, sonder nur dann, wenn jemand draufdrückt ('Ring'-Event :D )
    Das Paint-Event wird dann ausgeführt, wenn etwas über das entsprechende Steuerelement "gezeichnet" wurde, und VB den darunterliegenden Bereich wiederherstellen muß. Sonst nicht. Schon gar nicht andauernd. Da würde dein PC zum Rauchen anfangen.

    Klingt logisch^^ Aber das flackern zuvor kam ja daher, das dauernd etwas gezeichnet wurde und das kam dann ja daher, dass das Paint-Event endlos ausgeführt wird. Und wenn die Überprüfung nur ist, dass in Textbox1 Text drinnen ist, und ich tippe zur Laufzeit was rein und springe zur nächsten, hängt sich das Programm auf, weil ja die anderen noch nicht ausgefüllt sind -> Paintevent aktiviert sich. Textboxen zeichnen ja normalerweise nichts ;)

    Option Strict vergess ich meistens bei neuen Forms X( Ich sollte mal bei VB einstellen, dass es das automatisch hinzufügen soll. Namen mache ich meist immer zum Schluss aber werde mich bemühen es in Zukunft schon besser zu Beginn zu machen^^ Die Timer Idee ist eigentlich auch nett, werd ich wohl einbauen
    Sieh dir deinen Code ma genauer an:

    VB.NET-Quellcode

    1. Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.
    2. Dim graphic As Graphics = PictureBox1.CreateGraphics'Zeile rausschmeiißen
    3. Dim pen As New Pen(Color.Red, 1)
    4. Dim rec As New Rectangle(PictureBox1.Location.X + CInt(TextBox2.Text), PictureBox1.Location.Y + CInt(TextBox3.Text), CInt(TextBox4.Text), CInt(TextBox5.Text))
    5. graphic.DrawRectangle(pen, rec)' statt diesem e.graphics.DrawRectangle(...)
    6. End Sub
    Du besorgst dir im Paint der Picturebox ein neues Graphics-Objekt. Damit wird sich deine Anwendung im Kreis drehen. Außerdem solltest du dafür sorgen, dass in deinen Textboxen beim Start sinnvolle Werte stehen. (Leer != sinnvoll)
    Das Doublebuffer arbeitet nur für die Form, nicht für das Paint-Event der Picturebox. Darum lass die PB weg und zeichne direkt auf die Form. Dann im Load mit Setstyle die ganzen Sachen wie Doublebuffer setzen.
    Fiel Fergnügen
    Vatter

    Edit: Timer ist für dein Vorhaben Quatsch. Dafür gibs Events wie z.B. Textchanged-Event. Du mußt natürlich auf sinnvolle Werte abfragen.
    :thumbsup: Seit 26.Mai 2012 Oppa! :thumbsup:

    Vatter schrieb:

    Edit: Timer ist für dein Vorhaben Quatsch. Dafür gibs Events wie z.B. Textchanged-Event. Du mußt natürlich auf sinnvolle Werte abfragen.
    Das mit dem Timer war auch mehr so ein allgemeiner Vorschlag, wenn er automatisch neuzeichnen will. Man kann ja gelegentlich davon ausgehen, dass der andere auch mitdenkt..

    Unwesen schrieb:

    Vatter schrieb:

    Edit: Timer ist für dein Vorhaben Quatsch. Dafür gibs Events wie z.B. Textchanged-Event. Du mußt natürlich auf sinnvolle Werte abfragen.
    Das mit dem Timer war auch mehr so ein allgemeiner Vorschlag, wenn er automatisch neuzeichnen will. Man kann ja gelegentlich davon ausgehen, dass der andere auch mitdenkt..

    Hey :P
    Allerdings wenn man bedenkt, dass ich für alle Textboxen(und es gibt mehrere Überprüfungen da ich ein 3-tab TabControl verwende ;) ) ein TextChanged Event anlegen muss, leidet doch die Übersichtlichkeit daran :/ Also ein Timer würde es dem Verstand beim Folgen des Codes doch etwas einfacher machen ;) Aber Recht hast trotzdem, das TextChanged Event hatte ich anfangs komplett vergessen.

    @Vatter: Wow, sind ja einige Verbesserungsvorschläge die du da gemacht hast, aber sie erscheinen alle doch recht logisch und notwendig. Ich habe mal alle angewandt und es klappt alles wunderbar, thx :)

    Eine einzige Frage: Ich habe vor, dass es möglich ist, mit einer Art "Pinsel" in einer Grafik Bereiche anzuzeichnen und dazu dachte ich, ich lasse einfach solange die Maus gedrückt wird ein gefülltes 5x5 Rechteck an der Mausposition zeichnen, nur verschwinden dauernd die alten Rechtecke die ja gezeichnet wurden. Wie kann ich die alten Grafiken in den Graphics Objekten beibehalten?
    Wie wärs wenn du eine Bitmap erstellst, bezeichnest und dann der Picturebox als BackgroundImage unterschiebst.
    Dann hast du kein Me.Paint-Event, keine Und-Verknüpfung und keine Globale Bool'sche Variable auf die du achten müsstest.


    Hier ein möglicher Code, welcher es dir erlaubt auch unregelmäßige Vierecke zu zeichnen (sonst "DrawRectangle"):

    VB.NET-Quellcode

    1. Private Sub Viereck_Malen()
    2. Dim bmp As Bitmap = New Bitmap(Picturebox1.Width, Picturebox1.Height)
    3. Dim g As Graphics = Graphics.FromImage(bmp)
    4. Dim Punkt1X as Point = Textbox1.text
    5. Dim Punkt1Y as Point = Textbox2.text
    6. Dim Punkt2X as Point = Textbox3.text
    7. Dim Punkt2Y as Point = Textbox4.text
    8. Dim Punkt3X as Point = Textbox5.text
    9. Dim Punkt3Y as Point = Textbox6.text
    10. Dim Punkt4X as Point = Textbox7.text
    11. Dim Punkt4Y as Point = Textbox8.text
    12. g.DrawLine(Pens.Black, Punkt1X ,punkt1Y, Punkt2X ,punkt2Y)
    13. g.DrawLine(Pens.Black, Punkt2X ,punkt2Y, Punkt3X ,punkt3Y)
    14. g.DrawLine(Pens.Black, Punkt3X ,punkt3Y, Punkt4X ,punkt4Y)
    15. g.DrawLine(Pens.Black, Punkt4X ,punkt4Y, Punkt1X ,punkt1Y)
    16. Picturebox1.backgroundimage = bmp
    17. End Sub

    Wenn du willst das beim erneuten Zeichnen das vorherige erhaltenbleibt,schreib die 2. beiden Zeilen in der Sub, außerhalb der Sub.

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

    powachill schrieb:

    der_Kurt schrieb:

    If (TextBox2.TextLength > 0 AND TextBox3.TextLength > 0 ...

    AND bewirkt eine logische Verknüpfung, '&' ist ein Verkettungsoperator!


    Tipp:
    Mach AndAlso und nicht And, da And auch True gibt, wenn 2/3 zutreffend sind.



    TIPP:

    VB.NET-Quellcode

    1. If (True And True And False) Then
    2. MessageBox.Show("Du hast recht!?!?!?!?!")
    3. ElseIf (True And True And True) Then
    4. MessageBox.Show("Du hast unrecht..")
    5. End If


    Führe das aus! :D
    Das ist meine Signatur und sie wird wunderbar sein!