foreach Schleife abbrechen

Anfängerfragen zum Programmieren mit PureBasic.
schleicher
Beiträge: 214
Registriert: 30.03.2014 19:57
Computerausstattung: Purebasic 5.70
Wohnort: 18314 Löbnitz

foreach Schleife abbrechen

Beitrag von schleicher »

Ich weiß wohl, das man mit break eine Foreach Schleife abbrechen kann, aber wie funktioniert das im Window mit einem Button ?
Wie in meinem Beispielcode zu sehen habe ich es mit einer Variable(abbrechen=1) versucht, aber diese Variable scheint während die Foreach-Schleife läuft, nicht geändert zu werden. (Das kopieren von Ordnern geht natürlich auch mit CopyDirectory(, der Code ist nur ein Beispiel)
Ich habe in dem Beispiel ein Delay eingesetzt, damit das Ganze nicht so schnell abläuft. Ist in meinem eigentlichen Code nicht drin.

Code: Alles auswählen

EnableExplicit

Structure copyfiles
  Datei.s
  Pfad.s
  Komplettpfad.s
  Size.l
EndStructure
Global NewList copyfiles.copyfiles()



Enumeration FormWindow
  #Window_testcopy
EndEnumeration

Enumeration FormGadget
  #ProgressBar_copy
  #String_Copyinfo
  #Button_Abbrechen
  #String_Ursprung
  #Button_Ursprung
  #String_Ziel
  #Button_Ziel
  #Button_copy
EndEnumeration

Declare CopyFolder()


Global abbrechen, Ordner_Ursprung.s, Ordner_Ziel.s, gesamtkbyte.l, anzahl

OpenWindow(#Window_testcopy, 0, 0, 450, 240, "Test Ordner kopieren", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ProgressBarGadget(#ProgressBar_copy, 20, 100, 400, 25, 0, 0)
StringGadget(#String_Copyinfo, 20, 140, 400, 25, "")
ButtonGadget(#Button_Abbrechen, 300, 190, 120, 25, "Abbrechen")
StringGadget(#String_Ursprung, 20, 20, 170, 25, "zu kopierender Ordner")
ButtonGadget(#Button_Ursprung, 190, 20, 30, 25, "..")
StringGadget(#String_Ziel, 240, 20, 150, 25, "Zielordner")
ButtonGadget(#Button_Ziel, 390, 20, 30, 25, "..")
ButtonGadget(#Button_copy, 20, 190, 130, 25, "Kopiere")


Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
      
    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
          
        Case #Button_Ursprung
          gesamtkbyte=0
          anzahl=0
          Ordner_Ursprung=PathRequester("Bitte Ordner zum kopieren wählen", "c:\")
          SetGadgetText(#String_Ursprung, Ordner_Ursprung)
          
          If ExamineDirectory(0, Ordner_Ursprung, "*.*")
            While NextDirectoryEntry(0)
              If DirectoryEntryType(0) = #PB_DirectoryEntry_File
                AddElement(copyfiles())
                copyfiles()\Komplettpfad=Ordner_Ursprung+DirectoryEntryName(0)
                copyfiles()\Datei=DirectoryEntryName(0)
                copyfiles()\Pfad=Ordner_Ursprung
                copyfiles()\Size=DirectoryEntrySize(0)/1024
                gesamtkbyte+copyfiles()\Size
                anzahl+1
              EndIf
            Wend
            FinishDirectory(0)
          EndIf
          
        Case #Button_Ziel
          Ordner_Ziel=PathRequester("Bitte Zielordner wählen", "c:\")
          SetGadgetText(#String_Ziel, Ordner_Ziel)
        Case #Button_copy
          abbrechen=0
          CopyFolder()
        Case #Button_Abbrechen
          abbrechen=1
          
      EndSelect
  EndSelect
  
ForEver



Procedure CopyFolder()
  Define Ordnername_Ursprung.s, anzahl_backslash, File.s, size_copy.l, x
  size_copy=0
  
  If Ordner_Ursprung
    anzahl_backslash=CountString(Ordner_Ursprung, "\")
    Ordnername_Ursprung=StringField(Ordner_Ursprung, anzahl_backslash, "\")
    Debug "Ordnername = "+Ordnername_Ursprung
  EndIf
  
  SetGadgetAttribute(#ProgressBar_copy, #PB_ProgressBar_Maximum, gesamtkbyte) 
  
  If Ordner_Ziel And Ordner_Ursprung
    If FileSize(Ordner_Ziel+Ordnername_Ursprung)-1
      CreateDirectory(Ordner_Ziel+Ordnername_Ursprung)
    EndIf
    x=1
    ForEach copyfiles()
      Delay(1000)
      While WindowEvent() :Wend
      File=copyfiles()\Komplettpfad
      size_copy+copyfiles()\Size 
      If File
        If abbrechen=0
          If CopyFile(File, Ordner_Ziel+Ordnername_Ursprung+copyfiles()\Datei)<>0
            SetGadgetState(#ProgressBar_copy, size_copy)
            SetGadgetText(#String_Copyinfo, "Kopiere : "+x+"/"+anzahl+" "+File)
            If x=anzahl
              SetGadgetState(#ProgressBar_copy, 0)
              SetGadgetText(#String_Copyinfo, "Fertig")
              EndIf
          EndIf
        Else
          Break
        EndIf
      EndIf
      x+1
    Next
  Else
    MessageRequester("Error", "Bitte Ursprungs und Zielordner wählen !")
  EndIf
EndProcedure
Purebasic 5.51
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: foreach Schleife abbrechen

Beitrag von STARGÅTE »

In dem moment wo du CopyFolder() aufrufst, läuft der Code ja nur noch im unteren Prozedurblock.
Dein ganzer Window-Event-Block wird dabei nicht mehr abgearbeitet, erst wenn CopyFolder() fertig ist.

Es gibt nun zwei möglichkeiten:
  • Du erstellt aus CopyFolder() einen Thread der parallel gestartet wird, dann wird dein Event-Block weiter bearbeitet und abbrechen kann verändert und überprüft werden. (Erfordert Thread-Safe zusammen mit absicherung von Variablen/Listen die in beiden Codeteilen benutzt werden)
  • Du erstellt auch in der ForEach-Schleife unten ein Window-Event Block, der dann separat den Abbrechen-Button abfragt und dann dort auf abbrechen = 1 stellst.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
schleicher
Beiträge: 214
Registriert: 30.03.2014 19:57
Computerausstattung: Purebasic 5.70
Wohnort: 18314 Löbnitz

Re: foreach Schleife abbrechen

Beitrag von schleicher »

STARGÅTE hat geschrieben: Du erstellt auch in der ForEach-Schleife unten ein Window-Event Block, der dann separat den Abbrechen-Button abfragt und dann dort auf abbrechen = 1 stellst.
Danke für den Tip. Probiere das gleich mal aus.
Funktioniert ! Ist aber bestimmt noch besser zu schreiben oder ?

Code: Alles auswählen

EnableExplicit

Structure copyfiles
  Datei.s
  Pfad.s
  Komplettpfad.s
  Size.l
EndStructure
Global NewList copyfiles.copyfiles()



Enumeration FormWindow
  #Window_testcopy
EndEnumeration

Enumeration FormGadget
  #ProgressBar_copy
  #String_Copyinfo
  #Button_Abbrechen
  #String_Ursprung
  #Button_Ursprung
  #String_Ziel
  #Button_Ziel
  #Button_copy
EndEnumeration

Declare CopyFolder()


Global abbrechen, Ordner_Ursprung.s, Ordner_Ziel.s, gesamtkbyte.l, anzahl

OpenWindow(#Window_testcopy, 0, 0, 450, 240, "Test Ordner kopieren", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ProgressBarGadget(#ProgressBar_copy, 20, 100, 400, 25, 0, 0)
StringGadget(#String_Copyinfo, 20, 140, 400, 25, "")
ButtonGadget(#Button_Abbrechen, 300, 190, 120, 25, "Abbrechen")
StringGadget(#String_Ursprung, 20, 20, 170, 25, "zu kopierender Ordner")
ButtonGadget(#Button_Ursprung, 190, 20, 30, 25, "..")
StringGadget(#String_Ziel, 240, 20, 150, 25, "Zielordner")
ButtonGadget(#Button_Ziel, 390, 20, 30, 25, "..")
ButtonGadget(#Button_copy, 20, 190, 130, 25, "Kopiere")


Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      End
      
    Case #PB_Event_Menu
      Select EventMenu()
      EndSelect
      
    Case #PB_Event_Gadget
      Select EventGadget()
          
        Case #Button_Ursprung
          gesamtkbyte=0
          anzahl=0
          Ordner_Ursprung=PathRequester("Bitte Ordner zum kopieren wählen", "c:\")
          SetGadgetText(#String_Ursprung, Ordner_Ursprung)
          
          If ExamineDirectory(0, Ordner_Ursprung, "*.*")
            While NextDirectoryEntry(0)
              If DirectoryEntryType(0) = #PB_DirectoryEntry_File
                AddElement(copyfiles())
                copyfiles()\Komplettpfad=Ordner_Ursprung+DirectoryEntryName(0)
                copyfiles()\Datei=DirectoryEntryName(0)
                copyfiles()\Pfad=Ordner_Ursprung
                copyfiles()\Size=DirectoryEntrySize(0)/1024
                gesamtkbyte+copyfiles()\Size
                anzahl+1
              EndIf
            Wend
            FinishDirectory(0)
          EndIf
          
        Case #Button_Ziel
          Ordner_Ziel=PathRequester("Bitte Zielordner wählen", "c:\")
          SetGadgetText(#String_Ziel, Ordner_Ziel)
        Case #Button_copy
          abbrechen=0
          CopyFolder()
        
          
      EndSelect
  EndSelect
  
ForEver



Procedure CopyFolder()
  Define Ordnername_Ursprung.s, anzahl_backslash, File.s, size_copy.l, x, Event, a
  size_copy=0
  
  If Ordner_Ursprung
    anzahl_backslash=CountString(Ordner_Ursprung, "\")
    Ordnername_Ursprung=StringField(Ordner_Ursprung, anzahl_backslash, "\")
    Debug "Ordnername = "+Ordnername_Ursprung
  EndIf
  
  SetGadgetAttribute(#ProgressBar_copy, #PB_ProgressBar_Maximum, gesamtkbyte) 
  
  If Ordner_Ziel And Ordner_Ursprung
    
    If FileSize(Ordner_Ziel+Ordnername_Ursprung)-1
      CreateDirectory(Ordner_Ziel+Ordnername_Ursprung)
    EndIf
    x=1
    ForEach copyfiles()
      ;Delay(1000)
      While WindowEvent() :Wend
      File=copyfiles()\Komplettpfad
      size_copy+copyfiles()\Size 
      If File
        If abbrechen=0
          If CopyFile(File, Ordner_Ziel+Ordnername_Ursprung+copyfiles()\Datei)<>0
            SetGadgetState(#ProgressBar_copy, size_copy)
            SetGadgetText(#String_Copyinfo, "Kopiere : "+x+"/"+anzahl+" "+File)
            If x=anzahl
              SetGadgetState(#ProgressBar_copy, 0)
              SetGadgetText(#String_Copyinfo, "Fertig")
              EndIf
          EndIf
        Else
          SetGadgetState(#ProgressBar_copy, 0)
          SetGadgetText(#String_Copyinfo, "Abbruch durch Benutzer ! Kopiert wurden "+Str(x)+" von "+Str(anzahl)+ " Dateien :")
       
          Break
        EndIf
      EndIf
      x+1
      a=0
      Repeat
        Event=WaitWindowEvent()
        If Event=#PB_Event_Gadget
          If EventGadget()=#Button_Abbrechen
            abbrechen=1  
         EndIf
        EndIf
        a+1
     Until a>3
      
      
      
    Next
  Else
    MessageRequester("Error", "Bitte Ursprungs und Zielordner wählen !")
  EndIf
EndProcedure
Purebasic 5.51
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: foreach Schleife abbrechen

Beitrag von NicTheQuick »

Dritte Möglichkeit: Du nutzt BindGadgetEvent() für den "Abbrechen"-Button. Damit kann eine Procedure gestartet werden, sobald du auf den Button klickst, die die "abbrechen"-Variable auf 1 setzt. Aber trotzdem musst du hierfür mindestens ein "While WindowEvent() : Wend" in der Kopierprozedur einbauen.
schleicher
Beiträge: 214
Registriert: 30.03.2014 19:57
Computerausstattung: Purebasic 5.70
Wohnort: 18314 Löbnitz

Re: foreach Schleife abbrechen

Beitrag von schleicher »

NicTheQuick hat geschrieben:Dritte Möglichkeit: Du nutzt BindGadgetEvent() für den "Abbrechen"-Button.
Daran hatte ich auch schon gedacht, aber ich bin mit der 2.Variante schonmal zufrieden.Danke
Purebasic 5.51
Antworten