Seite 2 von 2

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

Verfasst: 12.07.2018 09:44
von hjbremer
BindGadgetEvent() ist auch nur eine 2. bzw. zusätzliche Eventverarbeitung.
Außerdem braucht man eine globale Variable, denn irgendwie muß die Schleife abgebrochen werden.

Dies betrifft auch Threads. Wie gesagt man braucht eine Abbruchbedingung.

Einen Thread einfach beenden ohne die Schleife zu beenden, kann Probleme machen.
z.B. das ListIconGadget zu sortieren mit Api Befehlen in einem Thread.

Außerdem ist diese Vorgehensweise mit WindowEvent() und einem Delay z.B. beim WebGadget
und der Busy-Abfrage doch bewährt. Es funktioniert ohne Probleme. Man braucht dafür keinen Thread finde ich.

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

Verfasst: 12.07.2018 10:42
von NicTheQuick
hjbremer: (Wait)WindowEvent() an zwei Stellen zu nutzen finde ich nicht so schön. Um Events an verschiedenen Stellen im Programm abarbeiten zu können, gibt es BindEvent() und BindGadgetEvent(). Abgesehen davon funktioniert #WM_KEYDOWN nur unter Windows. Das Delay(1) ist da auch fehl am Platz. Ein Delay(1) ruft man nur auf, wenn WindowEvent() = 0 ist, denn dann gab es auch wirklich kein Event. Gab es ein Event, sollte man so schnell wie möglich das nächste abholen anstatt auch dann zu warten. Dabei ist es egal, ob es ein Delay(1) oder Delay(100) oder sogar Delay(0) ist. In jedem Fall gibt das Betriebssystem die Arbeit an den nächsten Prozess weiter. Und bis dann der eigene Prozess wieder dran ist, kann es mehr als 0 oder 1 Millisekunde dauern. In der Zeit könnten schon wieder neue Events angekommen sein.
Der Pseudocode von man-in-black gefällt mir da wesentlich besser. Aber natürlich funktioniert dein Code in den meisten Fällen trotzdem gut. Es geht aber schöner. :wink:

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

Verfasst: 12.07.2018 11:11
von #NULL
Ich habe es gerade ohne Thread, nur mit PostEvent() versucht, wobei die Suche immer einen Einzelschritt weiter arbeitet wenn ein Such-Event auftritt sodass zwischendurch die anderen Events verarbeitet werden können. Problem dabei ist das PostEvent / CustomEvents scheinbar eine andere Priorität haben, sodass beispielsweise das Disablen eines Buttons vor PostEvent nicht sichtbar wird bis alle Custom Events abgearbeitet sind und keine neuen mehr auftreten, dann ist die Suche ja aber schon wieder vorbei. Weiß nicht wieso sich CustomEvents nicht hinten anstellen.

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

Verfasst: 12.07.2018 11:19
von NicTheQuick
Ich kann dir nicht ganz folgen. Wo hast du PostEvent() genutzt? Kannst du den Code zeigen?

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

Verfasst: 12.07.2018 11:25
von #NULL
Ja, kann ich gleich nochmal zurückschrauben.
Hier erstmal meine Variante ohne PostEvent, einfach mit einem eigenen Flag:

Code: Alles auswählen

EnableExplicit

Define win, progress, bSearch, bCancel
Define quit
Define searching = #False
Define search = 0

Procedure startSearch()
  Shared searching, search, bSearch, bCancel, progress
  If Not searching
    searching = #True
    search = 0
    DisableGadget(bSearch, 1)
    DisableGadget(bCancel, 0)
    SetGadgetState(progress, 0)
  EndIf
EndProcedure

Procedure stopSearch()
  Shared searching, search, bSearch, bCancel, progress
  If searching
    searching = #False
    search = 0
    DisableGadget(bCancel, 1)
    DisableGadget(bSearch, 0)
    SetGadgetState(progress, 0)
  EndIf
EndProcedure

Procedure search()
  Shared searching, search, bSearch, bCancel, progress
  
  If searching
    search + 1
    Debug "searching " + search + " .."
    SetGadgetState(progress, 100.0 * search / 20)
    Delay(100)
    If search >= 20
      Debug "finished"
      stopSearch()
    EndIf
  Else
    Debug "cancel"
  EndIf
  
  If Not searching
    search = 0
    DisableGadget(bCancel, 1)
    DisableGadget(bSearch, 0)
  EndIf
EndProcedure

win = OpenWindow(#PB_Any, 100, 100, 420, 130,"window", #PB_Window_ScreenCentered)
AddKeyboardShortcut(win, #PB_Shortcut_Escape, 99)
progress = ProgressBarGadget(#PB_Any, 10, 10, 400, 30,  0, 100)
bSearch = ButtonGadget(#PB_Any, 10, 50, 400, 30, "suchen")
bCancel = ButtonGadget(#PB_Any, 10, 90, 400, 30, "abbrechen")
DisableGadget(bCancel, 1)

Repeat
  While WaitWindowEvent(2)
    If EventWindow() = win
      If Event() = #PB_Event_Menu And EventMenu() = 99
        quit = #True
      ElseIf Event() = #PB_Event_CloseWindow
        quit = #True
      ElseIf Event() = #PB_Event_Gadget
        If EventGadget() = bSearch
          startSearch()
        ElseIf EventGadget() = bCancel
          stopSearch()
        EndIf
      EndIf
    EndIf
  Wend
  If searching
    search()
  EndIf
Until quit

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

Verfasst: 12.07.2018 11:37
von #NULL
Folgender Code sucht zwar nicht, aber der Such-Button wird disabled. Wenn ich aber das auskommentierte ;PostEvent(#eventSearch) aktiviere dann generiert die Suche immer wieder Search-Events und das disabled wird nicht sichtbar obwohl es vor dem erstem PostEvent stattfand.

Code: Alles auswählen

EnableExplicit

Enumeration #PB_Event_FirstCustomValue
  #eventSearch
EndEnumeration

Define win, progress, bSearch, bCancel
Define quit

Define searching = #False
Define search = 0

Procedure search()
  Shared searching, search
  Shared bSearch, bCancel
  
  If searching
    search + 1
    Debug "searching " + search + " .."
    Delay(100)
    If search >= 20
      Debug "finished"
      searching = #False
    Else
      PostEvent(#eventSearch)
    EndIf
  Else
    Debug "cancel"
  EndIf
  
  If Not searching
    search = 0
    DisableGadget(bCancel, 1)
    DisableGadget(bSearch, 0)
  EndIf
EndProcedure

win = OpenWindow(#PB_Any, 100, 100, 420, 130,"window", #PB_Window_ScreenCentered)
AddKeyboardShortcut(win, #PB_Shortcut_Escape, 99)
progress = ProgressBarGadget(#PB_Any, 10, 10, 400, 30,  0, 100)
bSearch = ButtonGadget(#PB_Any, 10, 50, 400, 30, "suchen")
bCancel = ButtonGadget(#PB_Any, 10, 90, 400, 30, "abbrechen")
DisableGadget(bCancel, 1)

Repeat
  WaitWindowEvent()
  If EventWindow() = win
    If Event() = #PB_Event_Menu And EventMenu() = 99
      quit = #True
    ElseIf Event() = #PB_Event_CloseWindow
      quit = #True
    ElseIf Event() = #PB_Event_Gadget
      If EventGadget() = bSearch
        DisableGadget(bSearch, 1)
        DisableGadget(bCancel, 0)
        searching = #True
        Debug "post"
        ;PostEvent(#eventSearch)
      ElseIf EventGadget() = bCancel
        DisableGadget(bCancel, 1)
        DisableGadget(bSearch, 0)
        searching = #False
        PostEvent(#eventSearch)
      EndIf
    EndIf
  ElseIf Event() = #eventSearch
    Debug "seach event"
    search()
  EndIf
Until quit
<edit>
Mit gtk2 sieht man sogar wie der Such-Button hängenbleibt.

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

Verfasst: 12.07.2018 11:46
von silbersurfer
Ich finde es mit Threads doch schöner gerade wenn es um Suchen geht bei Verzeichnis durchsuchen geht ja auch immer viel Zeit ins Land
hier mal mein Ansatz dazu

Code: Alles auswählen

EnableExplicit

Structure thread
	Thread.i
	stop.i
	such.s
EndStructure

Define Startsuche,EventID,Quit,a, Mein.Thread
Dim suchfeld.s(1000000)
#Window=1
#suche=3

For a=0 To 1000000
	suchfeld(a)="Text"+Str(a)
Next 	

Procedure Suchen(*this.Thread)
	Shared suchfeld()
	Protected a
	Repeat
		If a>1000000 : a=0 : EndIf 
		If *this\such =suchfeld(a)
			Debug "es wurde was gefunden ! "
		EndIf 
		If *this\stop=1
			Break
		EndIf 
		a=a+1
	ForEver	
EndProcedure

Procedure SucheStarten(suchen.s,*this.Thread)
	With *this
		\Thread=CreateThread(@Suchen(),*this)
		\such=suchen
		\stop=0
	EndWith	
EndProcedure	

If OpenWindow(#Window, 0, 0, 400, 200, "Test Window",#PB_Window_ScreenCentered | #PB_Window_SystemMenu)
	ButtonGadget(#Suche,10,10,100,25,"Suche starten")
EndIf 
Repeat
	EventID = WaitWindowEvent()
	Select EventID
		Case  #PB_Event_CloseWindow
			Quit=1
		Case #PB_Event_Gadget
			Select EventGadget()
				Case #suche
					If Startsuche=0
						SetGadgetText(#Suche, "Suche anhalten")
						Startsuche=1
						SucheStarten("Text999999",Mein.Thread)
						; Hier diverse Schleifen die irgendwelches Zeug erledigen... 
					ElseIf Startsuche=1
						SetGadgetText(#Suche, "Suche Starten")
						Startsuche=0  : Mein\stop=1	
					EndIf 						
			EndSelect
	EndSelect		
Until Quit=1


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

Verfasst: 13.07.2018 23:55
von mk-soft
Benötigt Modul 'ThreadToGUI'

Code: Alles auswählen

;-TOP

; Example ThreadToGUI

IncludeFile "Modul_ThreadToGUI.pb"

Enumeration #PB_Event_FirstCustomValue
  #My_Event_ThreadToGUI
EndEnumeration

Structure udtThreadData
  ThreadId.i
  Cancel.i
  ; Data
EndStructure

Procedure thFillList(*data.udtThreadData)
  Protected text.s, count
  
  UseModule ThreadToGUI
  
  DoSetGadgetText(1, "Stop Fill")
  DoStatusBarText(0, 0, "Thread 1 running...")
  For count = 1 To 120
    text = FormatDate("%HH:%II:%SS - Number ", Date()) + Str(count)
    DoAddGadgetItem(0, -1, text)
    Delay(1000)
    If *data\Cancel
      Break
    EndIf
  Next
  DoStatusBarText(0, 0, "Thread 1 finished.")
  DoSetGadgetText(1, "Start Fill")
  
  *data\Cancel = 0
  
  UnuseModule ThreadToGUI
  
EndProcedure

Procedure thFlash(*data.udtThreadData)
  Protected count, col
  
  UseModule ThreadToGUI
  
  DoSetGadgetText(2, "Stop Flash")
  
  For count = 0 To 40
    For col = 0 To 3
      DoStatusBarProgress(0, 1, count * 20 + col * 5)
      Select col
        Case 0 : DoSetGadgetColor(3, #PB_Gadget_BackColor, RGB(255,0,0))
        Case 1 : DoSetGadgetColor(3, #PB_Gadget_BackColor, RGB(255,255,0))
        Case 2 : DoSetGadgetColor(3, #PB_Gadget_BackColor, RGB(0,255,0))
        Case 3 : DoSetGadgetColor(3, #PB_Gadget_BackColor, RGB(255,255,255))
      EndSelect
      Delay(1000)
      If *Data\Cancel
        Break 2
      EndIf
    Next
  Next
  DoStatusBarProgress(0, 1, 100)
  
  DoSetGadgetText(2, "Start Flash")
  
  *data\Cancel = 0
  
  UnuseModule ThreadToGUI
  
EndProcedure

Procedure Main()
  Protected event, thread1.udtThreadData, thread2.udtThreadData
  
  If OpenWindow(0, #PB_Ignore, #PB_Ignore, 800, 560, "Thread To GUI Example", #PB_Window_SystemMenu)
    CreateStatusBar(0, WindowID(0))
    AddStatusBarField(200)
    StatusBarText(0, 0, "Thread 1")
    AddStatusBarField(200)
    AddStatusBarField(#PB_Ignore)
    
    ListViewGadget(0, 0, 0, 800, 500)
    ButtonGadget(1, 10, 510, 120, 24, "Start Fill")
    ButtonGadget(2, 140, 510, 120, 24, "Start Flash")
    StringGadget(3, 710, 510, 80, 24, "State", #PB_String_ReadOnly)
    
    ThreadToGUI::BindEventGUI(#My_Event_ThreadToGUI)
    
    Repeat
      event = WaitWindowEvent(10)
      Select event
        Case #PB_Event_CloseWindow
          
          If IsThread(thread1\ThreadId) Or IsThread(thread2\ThreadId) 
            MessageRequester("Info", "Threads running...")
          Else
            Break
          EndIf
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case 1
              If Not IsThread(thread1\ThreadId)
                thread1\ThreadId = CreateThread(@thFillList(), thread1)
              Else
                thread1\Cancel = 1
              EndIf
              
            Case 2
              If Not IsThread(thread2\ThreadId)
                thread2\ThreadId = CreateThread(@thFlash(), thread2)
              Else
                thread2\Cancel = 1
              EndIf
              
          EndSelect
          
      EndSelect
      
    ForEver
    
  EndIf
  
EndProcedure : Main()