Forum: PC-Programmierung Abbruch For-Schleife in Visual Basic2015


von JBourges (Gast)


Lesenswert?

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

von STK500-Besitzer (Gast)


Lesenswert?

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.

von Teo D. (teoderix)


Lesenswert?


Beitrag #6514857 wurde vom Autor gelöscht.
von Thomas W. (thomas100)


Lesenswert?


von JBourges (Gast)


Lesenswert?

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

von niemand (Gast)


Lesenswert?

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

von Schlaumaier (Gast)


Lesenswert?

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. ;)

von JBourges (Gast)


Lesenswert?

Hallo Schlaumeier!
Funktioniert! Muss allerdings den Abbruch-Button zweimal drücken, warum 
auch immer!

Danke!

von Schlaumaier (Gast)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von Wolfgang Höhne (Gast)


Lesenswert?

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

von JBourges (Gast)


Lesenswert?

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

von Wolfgang Höhne (Gast)


Lesenswert?


von STK500-Besitzer (Gast)


Lesenswert?

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.

von Schlaumaier (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Mark B. (markbrandis)


Lesenswert?

Schlaumaier schrieb:
> For i = 1 to ganz_viele

:-)

von Schlaumaier (Gast)


Lesenswert?

@ 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.

von Peter M. (r2d3)


Lesenswert?

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
von Schlaumaier (Gast)


Lesenswert?

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.

von Peter M. (r2d3)


Lesenswert?

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.

von Aussenseiter (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.