Button soll Schleife unterbrechen (möglichst ohne Threads)

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Delle
Beiträge: 1118
Registriert: 10.05.2005 22:48

Button soll Schleife unterbrechen (möglichst ohne Threads)

Beitrag 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!
PB 6.02 LTS + Win 11
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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
Zuletzt geändert von man-in-black am 11.07.2018 19:04, insgesamt 1-mal geändert.
(hab alles, kann alles, weiß alles!!^^)

Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8675
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 32 GB DDR4-3200
Ubuntu 22.04.3 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken
Kontaktdaten:

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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:

Code: Alles auswählen

While WindowEvent() : Wend
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.
Bild
Benutzeravatar
RSBasic
Admin
Beiträge: 8022
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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.
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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
(hab alles, kann alles, weiß alles!!^^)

Bild
Benutzeravatar
Delle
Beiträge: 1118
Registriert: 10.05.2005 22:48

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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?
PB 6.02 LTS + Win 11
Benutzeravatar
Delle
Beiträge: 1118
Registriert: 10.05.2005 22:48

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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...
PB 6.02 LTS + Win 11
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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
(hab alles, kann alles, weiß alles!!^^)

Bild
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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  
Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
man-in-black
Beiträge: 362
Registriert: 21.08.2006 17:39

Re: Button soll Schleife unterbrechen (möglichst ohne Thread

Beitrag 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
(hab alles, kann alles, weiß alles!!^^)

Bild
Antworten