Gelöst: Einfache "Busy"-Anzeige will nicht

Anfängerfragen zum Programmieren mit PureBasic.
EmmJott
Beiträge: 40
Registriert: 25.10.2024 12:23

Gelöst: Einfache "Busy"-Anzeige will nicht

Beitrag von EmmJott »

Hallo Ihr Lieben,

habe ein Progrämmchen geschrieben, dass Verzeichnisse liest und in eine Liste einträgt. Je nach Verzeichnis kann das schon mal eine Weile dauern. Dachte mir, ich könnte mittels

Code: Alles auswählen

AddWindowTimer(#window,123,1000)

Verzeichnis einlesen, in Liste eintragen, sortieren, ...

RemoveWindowTimer (#window,123)
und

Code: Alles auswählen

Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Timer And EventTimer() = 123
	string$ + "X"
	StatusBarText(#statusbar,1,string$)
	If LEN(string$) = 10
	string$ =""
	EndIf
EndIf    
Until Event = #PB_Event_CloseWindow
zwischenzeitlich jede Sekunde ein weiteres "X" in die Statuszeile eintragen, so daß der Anwender sieht, dass die Kiste rödelt und nicht tatenlos ist oder sich gar aufgehängt hätte. Tut's aber nicht. Hab ich's nur nicht richtig gemacht, oder geht das gar nicht auf diese Art?
Zuletzt geändert von EmmJott am 07.11.2024 11:29, insgesamt 1-mal geändert.
Bin aktiv in der rentenvorbereitenden Arbeitslosigkeit - zwangsweise. Auch nach >30 Jahren im Betrieb springst Du über die Klinge, wenn der (Miss-)Manager seinen Hintern retten will. Lasst Euch von euren Arbeitgebern bloß nix von wegen Loyalität erzählen - wenn's drauf ankommt, ist die nix Wert!
Benutzeravatar
mk-soft
Beiträge: 3844
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von mk-soft »

Du wirst wohl das Einlesen der Verzeichnisse in einem Thread auslagern müssen damit der EventLoop weiter funktioniert.
Für Anfänger muss man sich aber mit Threads intensive beschäftigen da hier einiges zu beachten ist.
Zum Beispiel sollte man nicht die Gadgets aus Threads ändern da diese unter Windows Teilweise geht, aber unter macOS oder Linux zum Absturz führt.
Und dann immer die Compiler Option ThreadSafe aktivieren.

Hier einige Beispiele um mit Threads zu arbeiten. Aber bitte sehr genau studieren und das Control nicht umbauen (Aber die Examples).
Link: Mini Thread Control
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8807
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: Einfache "Busy"-Anzeige will nicht

Beitrag von NicTheQuick »

Um genauer zu sagen, was du falsch machst, müsste ich mehr Kontext sehen. Aber ich habe eine Vermutung:
Das Einlesen des Verzeichnisses läuft vermutlich nicht in einem Thread, oder? Denn nur dann könnte es es unabhängig von der Eventschleife laufen. Oder umgekehrt beschrieben: Solange dein Programm `WaitWindowEvent()` nicht aufrufen kann, werden auch die Timer-Events nicht abgearbeitet.

Das Einlesen des Verzeichnisses müsstet du also in einen Thread auslagern, damit parallel deine Eventschleife laufen kann. Das ist dann wieder nicht mehr ganz so Anfänger-geeignet, aber trotzdem noch relativ leicht machbar. Schau dir dazu `CreateThread()` und vielleicht ein paar Beispiele im Forum an. Und stelle sicher, dass du in den Compiler-Optionen "Thread-sichere Executable erstellen" aktiviert hast.
EmmJott
Beiträge: 40
Registriert: 25.10.2024 12:23

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von EmmJott »

Hallo,

vielen Dank für die Antworten. Klingt nach starkem Tobak für mich - das Thema Thread erscheint mir doch sehr nebulös. Wenn ich euch richtig verstanden habe, müsste ich entweder das Datensammeln oder die Fortschrittsanzeige in einen Thread auslagern. Wenn ich mir das tatsächlich aussuchen kann, was wäre denn eurer Erfahrung nach einfacher? Könnte mir auch eine animierte GIF in einem separaten Fenster vorstellen, da müsste ich nicht allzuviel meines jetzigen Progs über'n Haufen werfen ...

edit: ... glaube ich ...
Bin aktiv in der rentenvorbereitenden Arbeitslosigkeit - zwangsweise. Auch nach >30 Jahren im Betrieb springst Du über die Klinge, wenn der (Miss-)Manager seinen Hintern retten will. Lasst Euch von euren Arbeitgebern bloß nix von wegen Loyalität erzählen - wenn's drauf ankommt, ist die nix Wert!
Benutzeravatar
mk-soft
Beiträge: 3844
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von mk-soft »

Du must das Datensammeln in Thread auslagern. Die GUI EventLoop darf nicht durch lange Prozesse unterbrochen werden.
Schau dir die Beispiele in Mini Thread Control an.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
H.Brill
Beiträge: 496
Registriert: 15.10.2004 17:42
Wohnort: 66557 Neunkirchen

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von H.Brill »

Naja, wenn das Programm sonst nichts machen muß, kannste die Suche ja mit einem Button starten und halt
einfach warten, bis es mit dem Directory fertig ist.
Die Progressbar kann man ja so anpassen, daß der Maximalwert immer die Anzahl der Dateien eines Ordners ist.
(siehe SetGadgetAttribute() ). Den Timer habe ich durch For i = 1 To 500 ersetzt, damit man auch was sieht.
Den kannst du auch später wieder rausnehmen und mit dem Code ersetzen, was du mit den Dateien machen willst.

Vielleicht so etwa :

Code: Alles auswählen

Procedure.i CountFiles (sPath.s)
   Protected numFiles = 0
   Protected handle
   If Right(sPath, 1) <> "\"
      sPath + "\"
   EndIf
   
   handle = ExamineDirectory(#PB_Any, sPath, "*.*")
   If handle = 0
      ProcedureReturn  0
   EndIf
   
   While NextDirectoryEntry(handle)
     If DirectoryEntryType(handle) = #PB_DirectoryEntry_File
       numFiles + 1
     Else
       If DirectoryEntryName(handle) <> "." And DirectoryEntryName(handle) <> ".."
           numFiles + CountFiles(sPath + DirectoryEntryName(handle)) 
       EndIf
     EndIf
   Wend
   FinishDirectory(handle)
   
   ProcedureReturn numFiles
 EndProcedure
 
path$ = "C:\Temp\"
cfiles.l = CountFiles(path$)

If OpenWindow(0, 0, 0, 400, 100, "Timer Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    ProgressBarGadget(0, 10, 10, 380, 20, 0, cfiles)
    
    Value = 0
    Repeat
      Event = WaitWindowEvent()
      
      If ExamineDirectory(0, path$, "*.*")  
         While NextDirectoryEntry(0)
            If DirectoryEntryType(0) = #PB_DirectoryEntry_File
               Type$ = "[File] "
               Value + 1
               SetGadgetState(0, Value)
               For i = 1 To 500
               Next  
            EndIf
         Wend
      EndIf    
      
   Until Event = #PB_Event_CloseWindow
 EndIf
Ist jetzt nur für den einen Ordner.
Vielleicht kann man das auch noch mit einer Sanduhr als Cursor verfeinern.

Evtl kannst du damit ja was anfangen.
PB 6.10
Benutzeravatar
#NULL
Beiträge: 2237
Registriert: 20.04.2006 09:50

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von #NULL »

Das geht notfalls auch ohne Threads, wird dann halt etwas komplizierter. Du musst die Aufgabe nur so aufteilen, dass sie stückchenweise arbeitet und nach jedem Schritt rausspringen und später weitermachen kann.
Ein Beispiel mit ExamineDirectory().
Erweitern kann man das mit einer Structure, die die Daten für eine examine session enthält und übergeben wird, so dass auch mehrere sessions parallel laufen können und auch rekursiv.
Du kannst auch in der Prozedur ein custom event mit Daten des aktuellen Eintrags oder dem Status posten, dann hast du jeden Eintrag direkt als Event in der Event Schleife.

Code: Alles auswählen

EnableExplicit

Define win, event, quit

win = OpenWindow(#PB_Any, 50, 100, 800, 600, "title")
AddKeyboardShortcut(win, #PB_Shortcut_Escape, 10)

Procedure examineDir(dir.s = "")
  Static dirPath.s
  Static exDir
  Protected Type$
  Protected Size$
  
  If Not Len(dirPath)
    If Len(dir)
      dirPath = dir
    EndIf
  EndIf
  
  If Len(dirPath)
    If Not exDir
      Debug "examine.. (" + dirPath + ")"
      exDir = ExamineDirectory(#PB_Any, dirPath, "*.*")
    EndIf
    
    If exDir
      If NextDirectoryEntry(exDir)
        
        If DirectoryEntryType(exDir) = #PB_DirectoryEntry_File
          Debug "[File] " + DirectoryEntryName(exDir) + " (Size: " + DirectoryEntrySize(exDir) + ")"
        Else
          Debug "[Directory] " + DirectoryEntryName(exDir)
        EndIf
        
      Else
        Debug "..finished"
        FinishDirectory(exDir)
        exDir = 0
        dirPath = ""
        ProcedureReturn #False
      EndIf
    EndIf
  EndIf
  ProcedureReturn #True
EndProcedure


Define more
more = examineDir(#PB_Compiler_Home)

Repeat
  
  If more
    more = examineDir()
    PostEvent(#PB_Event_FirstCustomValue) ; damit WaitWindowEvent nicht stehen bleibt
    If Not more
      Debug "is alle"
    EndIf
  EndIf
  
  event = WaitWindowEvent()
  Select event
    Case #PB_Event_CloseWindow
      quit = #True
    Case #PB_Event_Menu
      Select EventMenu()
        Case 10
          quit = #True
      EndSelect
  EndSelect
Until quit
my pb stuff..
Bild..jedenfalls war das mal so.
Benutzeravatar
HeX0R
Beiträge: 3040
Registriert: 10.09.2004 09:59
Computerausstattung: AMD Ryzen 7 5800X
96Gig Ram
NVIDIA GEFORCE RTX 3060TI/8Gig
Win11 64Bit
G19 Tastatur
2x 24" + 1x27" Monitore
Glorious O Wireless Maus
PB 3.x-PB 6.x
Oculus Quest 2 + 3
Kontaktdaten:

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von HeX0R »

Es geht auch viel einfacher, nicht ganz so wie man es eigentlich macht, aber zumindest anfängerfreundlich:
Den Timer per BindEvent() einbinden, eine Timerprozedur erstellen, die den Fortschritt zeigt und dann in der zeitaufwändigen Schleife While WindowEvent() : Wend einbauen.
Man kann auch den CloseWindow Event per BindEvent() dazunehmen, damit man die Schleife auch abbrechen könnte.
Benutzeravatar
TheCube
Beiträge: 169
Registriert: 20.07.2010 23:59
Computerausstattung: Risen 3400G 16MB Win10-64Bit
Wohnort: NRW

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von TheCube »

Klasse Idee die Tmer einfach per Bindevent() einzubinden, und nicht klassisch in der Eventschleife abzuarbeien ... selbst nie dran gedacht. :oops:
So muss man nicht gleich Threads einrichten, wenn man zuverlässig vllt. nur alle Sekunde in z.B. der Statusbar einen Text aktualisiert,
ein Icon blinken lässt oder was sonst so zeitunkritisch aber sicher regelmässig ausgeführt werden soll.
Bei der klassischen Timer-Eventabfrage pausiert ja alles bei Bedienung von Menüs, anpacken/schieben des Fensters, oder gar Messagerequestern.
EmmJott
Beiträge: 40
Registriert: 25.10.2024 12:23

Re: Einfache "Busy"-Anzeige will nicht

Beitrag von EmmJott »

Hallo Allerseits,

sitze mit offenem Mund staunend auf dem Beifahrersitz und lausche den Fachleuten. Könnte mir jemand ein Beispiel mit dem Timer per Bindevent() formulieren?
Bin aktiv in der rentenvorbereitenden Arbeitslosigkeit - zwangsweise. Auch nach >30 Jahren im Betrieb springst Du über die Klinge, wenn der (Miss-)Manager seinen Hintern retten will. Lasst Euch von euren Arbeitgebern bloß nix von wegen Loyalität erzählen - wenn's drauf ankommt, ist die nix Wert!
Antworten