Button soll Schleife unterbrechen (möglichst ohne Threads)

Anfängerfragen zum Programmieren mit PureBasic.
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 »

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

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:
Bild
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

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

Beitrag 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.
my pb stuff..
Bild..jedenfalls war das mal so.
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 »

Ich kann dir nicht ganz folgen. Wo hast du PostEvent() genutzt? Kannst du den Code zeigen?
Bild
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

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

Beitrag 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
my pb stuff..
Bild..jedenfalls war das mal so.
Benutzeravatar
#NULL
Beiträge: 2235
Registriert: 20.04.2006 09:50

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

Beitrag 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.
my pb stuff..
Bild..jedenfalls war das mal so.
Benutzeravatar
silbersurfer
Beiträge: 174
Registriert: 06.07.2014 12:21

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

Beitrag 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

Intel Quad Core 3,2 Ghz - GTX 1060 - BlitzBasic Plus 1.48 , PureBasic 5.70 LTS / Aktuelles Projekt PureCommander
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

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

Beitrag 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()
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Antworten