Seite 1 von 2
Button soll Schleife unterbrechen (möglichst ohne Threads)
Verfasst: 11.07.2018 18:31
von Delle
Hallo,
in einem kleinen Tool wird aus dem "Suche starten"-Button nach Betätigung ein "Suche anhalten"-Button und es erfolgen diverse Aktionen:
Code: Alles auswählen
ButtonGadget(#Suche,10,10,100,25,"Suche starten")
Repeat
EventID = WaitWindowEvent()
If EventID=#PB_Event_Gadget And EventGadget()=#Suche
SetGadgetText(#Suche, "Suche anhalten")
; Hier diverse Schleifen die irgendwelches Zeug erledigen...
EndIf
Until WaitWindowEvent() = #PB_Event_CloseWindow
Wie kann ich jetzt dem "Suche anhalten"-Button funktionsfähig machen? Er soll sozusagen die Suche abbrechen und sich selbständig auf "Suche starten" zurückändern.
Geht das ohne Threads?
Danke!
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 19:02
von man-in-black
Hi,
ersteinmal würde ich die Eventschleife von der Aktionsschleife trennen.
Ansonsten werden deine Fensterevents nichtmehr abgearbeitet!
Und damit kommen wir schon auf die Lösung:
Den Aktionsthread einfach mit KillThread() mehr oder weniger freundlich abwürgen.
Edit: ups. Du wolltest ohne Threads. Ich schreib was nachm Essen.
MFG
MIB
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 19:03
von NicTheQuick
Du kannst mit BindGadgetEvent() einen Callback für den Button erstellen und wenn dieser ausgelöst wird, kannst du den Wert einer globalen Variable so ändern, dass deine Schleife abgebrochen wird.
Allerdings ist das noch nicht alles. Damit Events überhaupt erst abgearbeitet werden, muss (Wait)WindowEvent() immer noch regelmäßig ausgeführt werden. In deiner Schleife musst du also regelmäßig weiter die Events abarbeiten. Am besten wäre zum Beispiel eine solche Schleife:
Wenn kein Event kommt, ist WindowEvent() = 0 und somit geht es direkt nach der Schleife weiter. Kamen ein oder mehrere Events an, ist WindowEvent() solange nicht 0 bis alle anstehenden Events abgearbeitet sind. Und wenn der Event zufällig ein Klick auf den Abbruch-Button war, dann wird der Callback aufgerufen, die globale Variable geändert und du kannst die Schleife komplett abbrechen und wieder in die normale Event-Schleife zurückfallen.
Um dem Nutzer Feedback zu geben, dass er nur noch diesen einen Button klicken kann und sonst nichts, solltest du dann auch alle anderen Buttons im Fenster deaktivieren. Ansonsten werden in der Schleife aber sowieso alle Events des Nutzers ignoriert. Aber SplitterGadgets könnte man zum Beispiel immer noch nutzen, es sei denn auch das ist deaktiviert.
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 19:05
von RSBasic
man-in-black hat geschrieben:Den Aktionsthread einfach mit KillThread() mehr oder weniger freundlich abwürgen.
Ich würde lieber eine globale Finish-/Stop-Variable definieren. Im Aktionsthread ist ja wahrscheinlich eine Schleife für das Durchsuchen und wenn die Finish-/Stop-Variable auf 1 ist, dann, wird die Schleife mit Break abgebrochen und der Aktionsthread wird sauber beendet ohne Memory Leaks.
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 19:34
von man-in-black
Ich bin immer für Chaos.
Aber das hängt logischerweise natürlich von dem Schleifeninhalt/Aktionen ab.
Bei deiner Lösung ohne Threads sehe ich aber nach wie vor das Problem mit den Fensterevents. Wie willst du gleichzeitig deinen Button auswerten und Daten abarbeiten?
Das geht mMn nur mit einem zusätzlichen WindowEvent() und BindGadgetEvebt(). (S. Nic)
Das wiederum finde ich jedoch unschön, da du dann keine eindeutige Eventverarbeitung hast...
Was ist denn deine genaue Anwendung des Tools? Wieso keine Threads?
MFG
MIB
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 20:29
von Delle
Also Threads gehen natürlich auch notfalls
Dachte nur das wäre hier mir 2 Zeilen innerhalb der Schleife erledigt oder so...
Das heißt zwischen Repeat:Until kommen die Abfragen nach den Aktionen sowie ein While/Wend... und die eigentlichen "Arbeiten" werden unterhalb in Prozeduren (?) ausgelagert?
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 20:41
von Delle
Ok jz hab ich den Thread vor den Code gepackt und diese Schleife:
Code: Alles auswählen
Repeat
EventID = WaitWindowEvent()
If EventID=#PB_Event_Gadget And EventGadget()=#Suche
If GetGadgetText(#Suche)="Suche starten"
SetGadgetText(#Suche, "Suche anhalten")
thread=CreateThread(@Suche(), 123)
Else
SetGadgetText(#Suche, "Suche starten")
KillThread(thread)
EndIf
EndIf
Until WaitWindowEvent() = #PB_Event_CloseWindow
Nicht sauber, funzt... aber er meckert wegen dem Code hier im Thread rum:
Code: Alles auswählen
While GetGadgetAttribute(1, #PB_Web_Busy):WaitWindowEvent(1):Wend
[20:38:16] [ERROR] WindowEvent() und WaitWindowEvent() können nur vom Haupt-Thread aufgerufen werden.
[20:38:16] Die Programmausführung ist abgeschlossen.
Hab ich mich jetzt total verzettelt!?
WaitWindowEvent(1) hab ich jetzt durch Delay(1) ersetzt.
Irgendwie reagiert der Button mit "Suche starten" aber nicht wirklich auf Anhieb
Auch der Fensterschließen-Button reagiert nicht wirklich sofort...
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 21:47
von man-in-black
Hi,
da beide Threads unabhängig und parallel laufen, brauchst du auch nur in einem
der Threads die Eventstapel abarbeiten. Bei PB ist dies nativ nur im Hauptthread vorgesehen
(s. Fehlermeldung). Ergo brauchst du nur 1x (Wait)WindowEvent in Summe. Im Nebenthread
also nicht...
Dein Nebenthread kann maximal auf Fensterinhalte zugreifen. DAS ist aber mitunter
auch gefährlich, weil zeitgleich 2 Threads (Haupt- u. Nebenthread) auf die gleichen
Speicherbereiche zugreifen könnten. Hier würde ich lieber vom Nebenthread via custom Events
Dateien anfordern/übergeben und mit dem Hauptthread via Mutex in separate Speicherbereiche
ablegen. (Hätte ich mehr als ein Handy in der Hand, würde ich dir was zusammencoden
)
Code: Alles auswählen
global Daten, endThread
Procedure Nebenthread
While endThread = #false
...
Rechne rechne
PostEvent (#custom_holeMirDaten)
...
Debug Daten
Wend
SetGadgetText(#button ... ;wieder auf normal setzen
Endprocedure
Repeat
Event = WaitWindowEvent()
Select Event
...
Case #custom_holeMirDaten
LockMutex... ;vielleicht braucht man die Sicherheit hier auch nicht
Daten = GetGadget...
UnlockMutex
....
...
Case #button ;noch eine Fallunterscheidung, ob start oder stop
endThread = #false
CreateThread (Nebenthread)
SetGadgetText(#button ...
;Statt killThread() - evt. auch mit Mutex sichern:
EndThread = #true
...
Until Event = ...
(Das ist absoluter Pseudocode und vollkommen aus dem Kopf. Fehler sind somit wahrscheinlich!!)
MFG
MIB
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 11.07.2018 23:28
von hjbremer
einfach denken !
dafür gibt es EventWindow() wenn PB Zeugs benutzt wird
bei Fremdzeugs muß dieses einen Abbruchbefehl haben, der in der Schleife abgefragt wird.
Code: Alles auswählen
#main = 1
#suche = 1
#info = 2
Procedure irgendwelchesZeug(start)
exit = 0
For j = start To 10000
;mache irgendwelches Zeug z.B. 10000 Datensätze durchsuchen
SetGadgetText(#info, Str(j))
;Prüfe auf Abbruch
event = WindowEvent()
If event = #WM_KEYDOWN
If EventwParam() = #VK_ESCAPE
exit = -1
Break
EndIf
ElseIf event = #PB_Event_Gadget
If EventGadget() = #suche
exit = j
Break
EndIf
EndIf
Delay(1)
Next
ProcedureReturn exit
EndProcedure
OpenWindow(#main, 0, 0, 300, 300, "PureBasic Window", #PB_Window_ScreenCentered | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
ButtonGadget(#Suche,10,10,150,25,"Suche starten")
TextGadget(#info,10,60,150,25,"", #PB_Text_Center)
start = 1
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_Gadget
If EventGadget() = #Suche
SetGadgetText(#Suche, "Suche anhalten oder Esc")
; Hier diverse Schleifen die irgendwelches Zeug erledigen...
x = irgendwelchesZeug(start)
If x = -1
SetGadgetText(#info, "suche wurde abgebrochen")
SetGadgetText(#Suche, "Suche starten"): start = 1
ElseIf x = 0
SetGadgetText(#info, "suche beendet")
SetGadgetText(#Suche, "Suche starten"): start = 1
Else
SetGadgetText(#info, "suche wurde angehalten bei " + Str(x))
SetGadgetText(#Suche, "weitersuchen"): start = x
EndIf
EndIf
EndSelect
Until Event = #PB_Event_CloseWindow
Re: Button soll Schleife unterbrechen (möglichst ohne Thread
Verfasst: 12.07.2018 06:42
von man-in-black
Hi hjbremer,
das ist genau das Vorgehen, dass Nic und ich angedeutet haben.
Mir gefällt daran nur nicht, dass man quasi 2x die Eventbearbeitung durchführen muss.
Manchmal hat man Buttons, die auch während der Suche funktionieren sollen (Hilfe, ...).
Dein Code wird damit in sich redundant(!). BinGadgetEvent wäre eine Lösung,
aber was ist mit den anderen Events...?
Klar, alles möglich, aber für mich bleiben Threads die sauberste Lösung.
MFG
MIB