Reihenfolge der Abarbeitung

  • VB.NET

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

    Reihenfolge der Abarbeitung

    Ich habe folgendes, wohl einfache Problem, für das ich allerdings noch keine Lösung gefungen habe:

    Ich möchte eine picturebox löschen, bevor ich sie mit neuen Inhalten fülle. Dazu verwende ich folgenden Code:

    sub button1(.....)

    Picturebox1.Image=Nothing 'Löschen der Picturebox
    ....
    Berechnungen
    ...
    Füllen der Picturbox mit den Resultaten.
    ...
    end sub


    Während der Laufzeit geschieht nun folgende seltsame Sache: Die Berechnungen werden durchgeführt, danach die Picturebox mit den Resultaten überschrieben (wobei der alte Inhalt einfach stehen bleibt) und danach wird die Box gelöscht. Scheint also, als fände hier keine sequentielle Befehlsabarbeitung statt. Ist dies ein Bug in VB2010? Ich sehe zumindest keinen Sinn darin. Beheben kann ich das Problem nur durch Einführung einer msgbox Meldung nach dem Löschbefehl, also wenn ich den Code so umschreibe:

    sub button1(.....)



    Picturebox1.Image=Nothing 'Löschen der Picturebox

    msgbox("sinnlose Meldung")

    ....

    Berechnungen

    ...

    Füllen der Picturbox mit den Resultaten.

    ...

    end sub

    Nun wird ordnungsgemäß die Picturebox erst gelöscht und dann, nach der Eingabe von Ok auf die sinnlose Meldung wird korrekt und sequentiell weitergearbeitet.

    Kennt jemand das Problem und weiß, was zu tun ist? Das wäre sehr schön und interessant für mich. Je einfacher die Lösung, desto lieber, ich bin noch Anfänger im Programmieren. :)

    Johannes
    Willkommen im Forum. :thumbup:
    Wie stellst Du Deine Resultate in der PiuctureBox dar?
    Poste mal ein kleines Stück Code, das Dein Problem verdeutlicht.
    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!
    Dies ist das entsprechende Stück Code
    sub ....
    Dim gr1 As Graphics = Graphics.FromHwnd(PictureBox1.Handle)
    Dim gr2 As Graphics = Graphics.FromHwnd(PictureBox1.Handle)
    .
    .
    PictureBox1.Image = Nothing
    PictureBox2.Image = Nothing
    MsgBox("Die Änderungen wurden übernommen")

    Call initgraph(gr1)
    Call phonemdisplay(1, gr1)
    end sub

    Es werden erst picturebox 1 und 2 gelöscht (so sollte es sein) dann wird gerechnet und in der subroutine initgraph(gr1) soll die Picturebox1 mit neuen Daten beschrieben werden. Dies geschieht dort mit gr.drawline(...) Befehlen.

    Mit der eingebauten dummy Messagebox klappt es ja aber die will ich natürlich nicht haben. :(

    Danke fürs Willkommen hier!

    :) Johannes
    Vielleicht solltest Du mal Deine Herangehensweise wie Folgt anpassen:

    VB.NET-Quellcode

    1. Sub MachNeu()
    2. PictureBox1.Invalidate()
    3. PictureBox1.Update()
    4. End Sub
    5. ' hier wird das Biold neu gemalt.
    6. Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    7. Dim g As Graphics = e.Graphics
    8. ' mit g was tun
    9. 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!

    VB.NET-Quellcode

    1. Dim g As Graphics = e.Graphics

    -.-
    Wofür?

    Ansonsten hast Du recht. In der Paint Sub sollte gezeichnet werden.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    Niko Ortner schrieb:

    Wofür?

    RodFromGermany schrieb:

    VB.NET-Quellcode

    1. ' mit g was tun
    :thumbsup:
    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 schrieb:

    Vielleicht solltest Du mal Deine Herangehensweise wie Folgt anpassen:

    VB.NET-Quellcode

    1. Sub MachNeu()
    2. PictureBox1.Invalidate()
    3. PictureBox1.Update()
    4. End Sub
    5. ' hier wird das Biold neu gemalt.
    6. Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    7. Dim g As Graphics = e.Graphics
    8. ' mit g was tun
    9. End Sub

    Hallo Niko und Rod,

    Vielen Dank für den Tipp! Mit picturebox1.update() funktionierte es auf Anhieb. Danke, das hat sehr geholfen.

    Nur noch eine theoretische Frage: Gibt es einen Sinn dafür, dass in VB Befehle nicht immer uns ausnahmslos sequentiell (also Programmzeile nach Programmzeile) abgearbeitet werden? Ich kann keinen entdecken! Liegt vielleicht an meinem Alter, bin ja noch mit FORTRAN77 groß geworden :)
    Wenn Du z.B. Bildverarbeitung machst und dann ein wenig Speed brauchst und einen 8-Core hast, sieh Dir mal
    Parallel.For an.
    Fortran 77 kann ich heute noch (fast) perfekt lesen. :thumbup:
    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!
    @johannes.hagel:
    Die Befehle werden schon sequenziell abgearbeitet.
    Aber nur weil Du das Bild der PictureBox auf Nothing setzt heißt das noch lange nicht, dass die PictureBox auch aktualisiert wird.
    kurzer Crash-Kurs:
    Wenn Du auf ein Steuerelement ("Control") im .Net Framework zeichnen willst, dann musst Du dir merken, was Du zeichnen willst.
    Sobald Du das Control neuzeichnen lassen willst rufst Du Control.Invalidate() auf.
    Das geht auch mehrmals. Dadurch wird der CLR nur mitgeteilt, dass bei der nächsten gelegenheit neu gezeichnet werden soll. (Angenommen Du hättest ein Spiel, dann wird meist Gezieltes Ownerdrawing verwendet. Da wird an Invalidate() ein Rectangle übergeben, das den Bereich angibt, der neu gezeichnet werden soll).
    Wenn es nötig ist, dass sofort gezeichnet wird, dann rufst Du Control.Update() auf.
    Um selbst Sachen auf das Control zu zeichnen verwendest Du das Paint-Event.

    VB.NET-Quellcode

    1. Private Sub BlaPaintDingens(ByVal sender As Object, ByVal e As PaintEventArgs) Handles DeinControl.Paint
    2. End Sub

    Dort zeichnest Du auf e.Graphics alles, was Du dann sehen willst.

    So kannst Du z.B. die Form aus den Bildschirmrand und wieder rein schieben, und das gezeichnete bleibt erhalten.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    johannes.hagel schrieb:

    Gibt es einen Sinn dafür, dass in VB Befehle nicht immer uns ausnahmslos sequentiell (also Programmzeile nach Programmzeile) abgearbeitet werden?

    Alle Befehle WERDEN sequentiell abgearbeitet!
    Wenn EVENTS in's Spiel kommen, dann sieht das zwar anders aus, aber BEFEHLE werden dennoch sequentiell bearbeitet.

    Was passiert bei pb.Image=nothing? Es wird ein Event in die MessageQueue gestellt, dass die Form darauf hinweist, dass ein Teil des Inhalts neu gezeichnet werden muss. Events können aber nur verarbeitet werden, wenn der UI-Thread "nichts zu tun hat". In deinem Fall arbeitet er aber erst noch die anderen Befehle ab. Wenn er damit fertig ist, ist der UI-Thread "idle" und kann die Events in der Queue abarbeiten.

    VB.NET-Quellcode

    1. Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    2. Dim g As Graphics = e.Graphics
    3. g.drawxy
    4. e.drawxy
    5. End Sub


    Warum nicht gleich mit e zeichnen?

    Gelernt... Super!

    Wow, wieder mal etwas gelernt! Vielen Dank Euch für diese Informationen. Ich selbst bin eben mehr ein PC-user, als dass ich über die Hintergründe der genauen Funktionsweisen Bescheid weiß. Was aber durchaus von Vorteil ist, wie ich lese.

    Zumal es auch für einen Lehrer wichtig ist, ständig neu zu lernen, :D

    Schließlich verwende ich VB in erster Linie zur Erstellung eigener Lernsoftware. Bereiche Mathe und Physik.

    johannes.hagel schrieb:

    Zumal es auch für einen Lehrer wichtig ist, ständig neu zu lernen, :D

    Na endlich gibt das mal einer zu. :thumbsup: :thumbsup: :thumbsup:
    Wenn da im Forum solche Aussagen kommen wie "Mein Lehrer will das aber so und so", krempelt es manchem die Zehennägel hoch. ;(
    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!
    Der Beitrag hat mich bei meinem Problem schon sehr weitergebracht, allerdings hänge ich immer noch
    an einem Schritt fest. In meinem Fall soll eine ProgressBar aktualisiert werden. Hier einmal der Quellcode:

    Visual Basic-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
    3. Dim nachricht As String = "ABC " 'Beispielhafter Text der in Töne überführt werden soll
    4. Dim buchstabe As String = String.Empty 'String um die einzelnen Buchstaben auslesen zu können (s.u.)
    5. Dim dauer As Long = 1000 'Tondauer
    6. Dim minfreq As Integer = 400 'unterste Frequenz in Hz
    7. Dim schritt As Integer = 10 'Frequenzabstand zu weiteren Tönen
    8. ladebalken.Minimum = 0 'ProgressBar trägt den Namen "ladebalken"
    9. ladebalken.Maximum = 3
    10. ladebalken.Value = 0
    11. ladebalken.Visible = True
    12. Me.Update() 'An der Stelle hatte ich mein erstes Problem, konnte es aber mit Nikos Erklärung lösen. Statt Me.Update() hätte ich auch ladebalken.Update() verwenden können. Hat auch funktioniert.

    Soweit so gut. Bis hierher funktioniert alles bestens. Jetzt kommen wir zum Problem. Der Beispielhafte Text soll über eine Funktion "Tongenerator()" in Töne überführt werden, doch bevor der Beep()-Befehl über die Funktion gestartet wird, soll der sequentiellen Programmabfolge entsprechend erst der ladebalken um einen Wert erweitert und dann sofort gezeichnet werden. Erst wenn das erfolgt ist, soll die Funktion Tongenerator() aufgerufen werden. Defacto läuft es aber genau umgekehrt, sodass meine progressbar nie die 100% erreicht, bevor sie wieder "invisible" wird.

    Visual Basic-Quellcode

    1. For index As Integer = 0 To 2
    2. ladebalken.Value += 1
    3. Me.Update()
    4. buchstabe = nachricht(0)
    5. nachricht = nachricht.Substring(1)
    6. Select Case buchstabe
    7. Case "A", "a"
    8. Tongenerator("Buchstabe A", 0, dauer, minfreq, schritt)
    9. Case "B", "b"
    10. Tongenerator("Buchstabe B", 1, dauer, minfreq, schritt)
    11. Case "C", "c"
    12. Tongenerator("Buchstabe C", 2, dauer, minfreq, schritt)
    13. End Select
    14. Next
    15. ladebalken.Visible = False
    16. End Sub
    17. Private Sub Tongenerator(ByVal meldung As String, ByVal frequenz As Integer, ByVal dauer As Long, ByVal minfreq As Integer, ByVal schritt As Integer)
    18. Console.Beep((minfreq + (frequenz * schritt)), dauer) 'Auch beim Einsatz einer MessageBox.Show()-Zeile wird zuerst die MessageBox geladen und dann der Ladebalken erneuert.
    19. End Sub
    20. End Class


    Jemand eine Idee, wie ich das lösen kann.
    Ja aber du setzt die PB ja auch direkt auf invisible am Ende der For-SChleife ? Was erwartest du denn ?
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    ThePlexian schrieb:

    Ja aber du setzt die PB ja auch direkt auf invisible am Ende der For-SChleife ? Was erwartest du denn ?


    Nehmen diese letzte Zeile aus dem Code, dann ändert das nicht mein Problem. Der letzte Ton wird immer noch gespielt bevor die Anzeige 100% angibt. Ich möchte es aber in umgekehrter Reihenfolge. Bevor der letzte Ton abgespielt wird, soll die PB auf 100% gesetzt werden.