Hallo zusammen, ich habe in Visual Basic 2015 eine For-Schleife, deren vollständige Abarbeitung ca. 20 min dauert. Nun würde ich diese gern durch ein Ereignis außerhalb der Schleife, wie einen Button, vorzeitig beenden. Solange die Schleife aber aktiv ist, kann ich leider keinen Button betätigen. Wie könnte man dies lösen oder ist eine Do-While-Schleife besser geeignet? Danke
Du musst natürlich Events (oder wie die in Visual BAsic heissen mögen) zulassen. Dann kann dein Button auch ein Flag setzen, das du innerhalb deiner for-Schleife auswertest und bei ggf. die for-Schleife abbricht.
Ereignisgesteuerte Programmierung http://openbook.rheinwerk-verlag.de/einstieg_vb_2010/einstieg_vb_2010_kap_04_003.htm#mj029b31c730b153ce64a27eaf06c05b93
Beitrag #6514857 wurde vom Autor gelöscht.
DoEvents ist dein Freund Schau mal hier: https://www.vbarchiv.net/tipps/tipp_2301-doevents-gezielt-und-nur-wenn-notwendig-einsetzen.html VG Thomas
Danke für den Hinweis "STK500-Besitzer" aber Visual Basic ist an sich schon ereignisgesteuert. Ich brauche so etwas wie einen Interrupt wie z.B. bei den Atmegas, bei denen ich durch eine Unterbrechung eine Variable innerhalb der Schleife setzen kann. Denke mit DoEvents komme ich vielleicht weiter. Kannte ich noch nicht! Danke Thomas
Moin! Dein Fehler ist, die lange laufende Operation auf dem UI-Thread ablaufen zu lassen. Lass sie in einem separaten Thread laufen, dann kannst du auch andere Buttons drücken. Beachte, dass UI-Operationen, wie das Aktualisieren eines TextBox-Textes während der langen Operation, dann über eine spezielle Invoke-Funktion wieder mit dem UI-Thread synchronisiert werden müssen. Das erste Beispiel hilft dir schon weiter: https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/await-operator
dim Abbruch as Boolean = false ' in global-bas deklarien. abbruch = false For i = 1 to ganz_viele i = i+1 my.application.doevents if abbruch = true then exit for next i Sub button_click abbruch = true end sub FERTIG. Tippfehler unterliegen den Copyright. ;)
Hallo Schlaumeier! Funktioniert! Muss allerdings den Abbruch-Button zweimal drücken, warum auch immer! Danke!
JBourges schrieb: > Funktioniert! Muss allerdings den Abbruch-Button zweimal drücken, warum > auch immer! Weil da immer noch eine Zeitschleife drin ist. Die bekommst du nicht wirklich raus, weil das Click selbst erst abgefragt wird wenn der DOEVENT-Befehl kommt. z.b. For i = 1 to ganz_viele for ii = 1 to 10000 x= x + 1 next ii my.application.doevents ' <- wird erst abgefragt und ausgeführt wenn x um 10000 größer ist. next i Einfach gesagt. Überlege dir wo du das positionierst. Weil dein Click-Ereignis wird NICHT übersehen sondern gepuffert. Du kannst es Theoretisch nach jeden Befehl machen aber das geht dann auf die allgemeine Ablaufgeschwindigkeit, und der Befehl verbraucht einiges an Zeit. Nanosekunden sind auch ein Zeiteinheit. !!! ;) Es reicht also i.d.R. 1 Klick. Allerdings ist VB nicht sehr gut darin 2 Dinge gleichzeitig zu tun. Ergo wird so ein Click schon mal übersehen,wenn gerade eine andere Routine läuft. Aber das Problem ist Windows-Like und hat nix mit VB selbst zu tun. Machen andere Programme auch so. Alles das selbe. Programmiersprache ist bei den Thema egal. Windows ist halt kein Multitasking-System sondern ein Zeitschleifen-System. Was bedeutet: Innerhalb einer Zeiteinheit wird jeden Prozess eine bestimmte Anzahl von Zeit zugeordnet. Und innerhalb dieser zugeordneten Zeit darf er was machen ansonsten macht er NIX.
Kleiner Nachtrag : Ich nutze den Befehl so meist. For i = 1 to ganz_viele y = y+1 if y = 20 then my.application.doevents y = 0 label_1.text = str(i) end if next i Das hält die Bildschirmausgabe am laufen und ich kann den Zähler ablesen, was mir je nach Prg. sagt wie weit der ist. Kannst du auch modern machen, in den du ein Ablaufbalken nutzt. Dann muss du in den Falle i als Prozentzahl zu 100 übergeben an den Balken.
Das macht man alles nicht so... Mach es genauso wie in c#... Starte einen task und gib dem ein cacellationtoken mit... In der Schleife fragst du ab ob dieses ausgelöst wurde und wenn ja beendet den task
Ja, danke für die Info. Das Zeitscheiben-Problem in Windows ist mir bekannt. Das zwei- oder mehrmalige Drücken auf den Button ist hinnehmbar. Zeitprobleme habe ich nicht, da ich zum Senden an den Mikrocontroller sowieso eine Wartezeit von 200ms drin habe. Für das Auffrischen und Anzeigen der Laufvariable in der Schleife nehme ich ganz gern den Befehl: Label7.Update() Gruß aus MD
JBourges schrieb: > Danke für den Hinweis "STK500-Besitzer" aber Visual Basic ist an sich > schon ereignisgesteuert Sehr gerne. Visual Basic ansich ist event-gesteuert. Dein Programm aber scheinbar nicht. Aber glücklicherweise haben sich andere um die Lösung bemüht.
JBourges schrieb: > Für das Auffrischen und Anzeigen der Laufvariable in der Schleife nehme > ich ganz gern den Befehl: Label7.Update() > Gruß aus MD JA, aber das bringt nur was wenn die Form am Schirm ist. Wenn du das Prg. minimierst und wieder normalisierst wird NICHT die ganze Form neu gezeichnet solange die Sub läuft. Bei dein .update wird nur das Feld geupdatet. Deshalb löse ich das doevents über die Application aus. Was bedeutet : "Zeichne alles neu". Mir ist das wichtig da viele meiner Prg. Teilweise Stunden laufen, und da will ich halt nicht die Form am Schrim habe, aber mal nach gucken wie weit sie ist. Das führt sogar soweit das ich für eine MSGBOX vorher den Name der Form ändere. Dann steht in meiner Taskleiste "hp:Frage" und ich weiß das irgendwo jemand was von mir will. Ist besonders wichtig wenn ich ein COPY-DATEI Befehl sende der mal eben 4-5 GB über das 100 Mbit Interne-Netzwerk schaufelt.
Schlaumaier schrieb: > Es reicht also i.d.R. 1 Klick. Das ist richtig. Input-Events werden gepuffert. > Allerdings ist VB nicht sehr gut darin 2 Dinge gleichzeitig zu tun. Ergo > wird so ein Click schon mal übersehen,wenn gerade eine andere Routine > läuft. Nein. Dann wäre etwas im Programm falsch. I.d.R. wohl: sinnloses Warten. D.h.: das gepufferte Event kann nicht wirksam werden, weil der Main-Thread es überhaupt nicht abfragt, weil er anderweitig beschäftigt ist (busy-loop) oder sogar auf Anweisung des Programmierers selber erklärt hat, erstmal eine Weile überhaupt nichts tun zu wollen (thread.sleep()). > Aber das Problem ist Windows-Like und hat nix mit VB selbst zu > tun. Es hat tatsächlich nix mit der verwendeten Programmiersprache zu tun, aber auch nix mit Windows. Ist vielmehr im Prinzip für praktisch alle grafischen Oberflächen so. Überall gibt es es ein Messaging-System und praktisch überall wird es aus Performance-Gründen synchronisiert und dann serialisiert in einem GUI-Thread abgearbeitet. Der Sinn dieser Synchonisation und Serialisierung ist einfach: den Code erstens nicht extrem anschwellen zu lassen und zweitens nicht die Möglichkeit für unzählige Deadlock-Situationen quasi vorzuprogrammieren. Wiederum ebenfalls in praktisch allen GUI-Systemen gibt es Möglichkeiten, da irgendwie ein wenig drumherum zu programmieren. Application.DoEvents ist eine davon, bei anderen Spachen/GUI-Systemen gibt es fast immer die entsprechenden Equivalente. Ist aber alles Gülle, einzig (scheinbar) nützlich für faule und dumme Programmierer. Der einzige wirklich richtige Weg ist hingegen immer: langdauernde Aufgaben außerhalb des Haupthread verarbeiten, in einem Extra-Thread. Das wirft auch schon genug Probleme auf, ist aber am Ende immer noch deutlich leichter zu beherrschen als Pfusch-Code, der z.B. mit Application.DoEvents oder vergleichbarem Müll hantiert. Bei .Net gibt es für diesen Zweck übrigens schon den BackgroundWorker als fertige Komponente. Der enthält fast alles, was nötig ist, um eine langdauernde Aufgabe sinnvoll parallel zum MainThread abzuarbeiten. Auch unter Berücksichtung folgender Möglichkeiten/Notwendigkeiten: 1) der parallele Thread muss vorzeitig abgebrochen werden 2) der parallele Thread stößt auf eine nicht behebbare Fehlersitation Was er allerdings leider nicht enthält, ist eine einfache Möglichkeit zur Synchronisation mit dem GUI-Thread. Das muss man "von Hand" machen. Diese scheinbare Schwäche ist einfach dadurch begründet, dass dieser Worker nicht nur dafür gedacht ist, Threads parallel zu einem GUI-Thread abzuarbeiten, sondern generell dazu, konkurrierende Threads abzuarbeiten, die u.U. überhaupt nix mit dem GUI zu schaffen haben. Die müssen natürlich auch synchronisiert werden, aber eben oft nur untereinander. Dazu sind aber andere Mechanismen nötig/sinnvoll als zur Synchronisierung mit dem GUI-Thread.
@ c-hater Ich gebe dir in allen Recht. Schön erklärt. Aber glaubst du ernsthaft das jemand der nicht einmal ein Doevents kennt in der Lage ist mit so Techniken zu arbeiten. Ich persönlich löse das Ereignis nur alle X Runden in einer Schleife aus. Und ich habe noch nie ein Programm ausliefern müssen wo ich so Probleme hatte. Anders ist das auf meinen Rechner. Da sind so Operationen fast an der Tagesordnung aber da es nur auf mein Rechner läuft mache ich mir nicht die Arbeit es "edel" zu machen. Das soll schnell gehen, und die von dir genannten Methoden machen es nicht wirklich schneller nur etwas "edler". Und viele meiner Progamme habe für die Einstellungen nur Variablen die im Prg-Code drin sind. Geht schneller als erst mal 2 Objekte zu malen, platzieren und mit Eigenschaften zu füllen. Und eine Lade-Routine die dann diese Werte permanent speichert. ;) Ich bin halt faul. Ich trenne klar zwischen : Kann ICH benutzen und "Das Programm muss DAU-Sicher sein". DAU-Sicher machen dauert i.d.R. 80% der Entwicklungszeit.
Hallo Schlaumaier, Schlaumaier schrieb: > For i = 1 to ganz_viele > y = y+1 > if y = 20 then > my.application.doevents > y = 0 > label_1.text = str(i) > end if > next i ich hab mir mal Deinen Code weggespeichert, weil er ein schönes kleines Beispiel für häßlichen Code darstellt, mit drei Auffälligkeiten in nur acht Zeilen. 1. Erst einmal benutze ich "i" nicht, das wird zu leicht verwechselt. 2. Die Abfrage auf jeden zwangzigsten Durchlauf kann man eleganter und lesbarer darstellen. 3. Es nützt nichts, ein GUI-Element zu beschreiben, nachdem man den Bildschirm aktualisiert hat - das wird im Zweifelsfall gar nicht sichtbar. Es geht auch lesbarer: for x=1 to anzahl if (x mod 20)=0 then label_1.text = str(x) my.application.doevents end if next x
:
Bearbeitet durch User
Peter M. schrieb: > 1. Erst einmal benutze ich "i" nicht, das wird zu leicht verwechselt. > 2. Die Abfrage auf jeden zwangzigsten Durchlauf kann man eleganter und > lesbarer darstellen. > 3. Es nützt nichts, ein GUI-Element zu beschreiben, nachdem man den > Bildschirm aktualisiert hat - das wird im Zweifelsfall gar nicht > sichtbar. Zu 1. ES ist MEIN Code. Und ich benutze i seit 30 Jahren als Schleifen-Variable oder als Zähl-Variable. Und ich kann meine uralt-Codes vor 30 Jahren noch lesen sofern ich darauf Zugang habe. Ich weiß nicht ob die Cassetten des ZX-81 noch lesebar sind. Davon abgesehen habe ich auf Systemen/Sprachen gelernt wo es kein Mode befehl gibt. Ich weiß nicht einmal ob B4* einen Mod-Befehl unterstützt. Und das ist das Entwicklungssystem was ich für Android und Arduino/Raspberry nutze. Wenn man nämlich nach den kleinsten gemeinsamen Nenner codete, hat man den Vorteil das man sich weniger Unterschiede merken muss. Mich regt schon auf das ich bei b4* nicht die Leertaste sondern Return zum auswählen einer Eigenschaft im Pulldown nehmen muss. zu 2. Ich hasse eleganten Code. Der Code muss nicht elegant sein, weil das ja so modern ist. Ein Code muss LESBAR sein wie ein Roman. Schnell und ohne das ich dabei denken muss. zu 3 Da gebe ich dir völlig recht. So was passiert wenn man auf die Schnelle in einen Forum ein Code runter nagelt. Selbstverständlich muss das DOEVENTS am ende der Abfrage stehen.
Hallo Schlaumaier, Schlaumaier schrieb: > zu 2. Ich hasse eleganten Code. Der Code muss nicht elegant sein, weil > das ja so modern ist. Ein Code muss LESBAR sein wie ein Roman. Schnell > und ohne das ich dabei denken muss. Du darfst das "elegant" gerne durch "lesbar" ersetzen! Deine geschachtelte Schleife halte ich (Du magst das gerne anders sehen) für weniger lesbar als eine einzige Schleife.
Hallo auch, denke das Forum wird immer .... Schon die erste Antwort von "STK500-Besitzer (Gast)" war nichtssagend. Und dann wird gestritten, wer besser (oder sauberer ... eher nicht) programmiert. Die Antwort von Thomas war konkret und weiterführend genug. Es ist doch völlig unerheblich ob Modula besser ist oder zwei Zeilen mehr verständlicher. Nur weiter so ..... Gruß von der Küste Eberhart
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.