ListViewGadget leeren und neu befüllen

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: ListViewGadget leeren und neu befüllen

Beitrag von ts-soft »

@AndyMars
Dein Code hat ein Problem, es wird ein Event im Callback gestohlen! Es
können ja ausser Cancel auch andere Ereignisse auftreten!
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
AndyMars
Beiträge: 141
Registriert: 08.09.2004 11:59
Computerausstattung: Win11 Prof 64bit, i5-13500 @ 4.8 GHz, 32GB RAM, Nvidia RTX 4070 TI
Wohnort: Zürich, Schweiz
Kontaktdaten:

Re: ListViewGadget leeren und neu befüllen

Beitrag von AndyMars »

ts-soft hat geschrieben:@AndyMars
Dein Code hat ein Problem, es wird ein Event im Callback gestohlen! Es
können ja ausser Cancel auch andere Ereignisse auftreten!
Da hast du recht! Aber ich habe es ehrlich gesagt lieber sequentiell - bei mir müssen User warten, bis eine Datei kopiert ist, oder sie müssen abbrechen. Das ist nicht sehr nett, aber sicherer - bei solchen Backgroundsachen muss der Programmierer verdammt gut aufpassen, dass sein Programm keinen Scheiss macht, wenn der User es darauf anlegt...
frankmannb
Beiträge: 47
Registriert: 21.02.2010 13:02

Re: ListViewGadget leeren und neu befüllen

Beitrag von frankmannb »

AndyMars hat geschrieben:Och Thomas... ich war wieder mal langsamer... /:->

Getesteter Code :D :

Code: Alles auswählen

;CopyFileEx1004.pb
;Beispiel für WinAPI CopyFileEx
;PB 4,4

Procedure.l _CopyFileExCallback(TotalFileSize.q, TotalBytesTransferred.q, StreamSize.q, StreamBytesTransferred.q, dwStreamNumber.l, dwCallbackReason.l, hSourceFile.l, hDestinationFile.l, lpData.l)
  TotalMB=TotalFileSize/1048576
  MBTrans=TotalBytesTransferred/1048576
  SetGadgetText(0,Str(MBTrans)+"/"+Str(TotalMB)+" MB")
  ev=1
  While ev
  	ev=WindowEvent()
  	If ev=#PB_Event_Gadget
  		If EventGadget()=1 ;STOP-Button
  			ProcedureReturn 1 ;1=PROGRESS_CANCEL
  		EndIf
  	EndIf
  Wend
  ProcedureReturn 0 ;0=PROGRESS_CONTINUE
EndProcedure

Procedure.l _CopyFileEx(pSource.s,pTarget.s)
  Erg = CopyFileEx_(@pSource.s, @pTarget.s, @_CopyFileExCallback(), 0, 0, 0)
  ProcedureReturn Erg
EndProcedure

If OpenWindow(0,200,200,80,50,"CopyFileEx Test")
	TextGadget(0,5,5,60,20,"")
	ButtonGadget(1,5,25,60,20,"STOP")
	;hier natürlich bei euch existierende Pfade angeben (mit ner groooossen Datei)
	If _CopyFileEx("D:\_Downloads\3DMark06_v110_installer.exe","D:\_temp\3DMark06_v110_installer.exe")
		Debug "Kopieren erfolgreich"
	Else
		Debug "Fehler beim Kopieren"
	EndIf
	Repeat
		ev=WaitWindowEvent()
	Until ev=#PB_Event_CloseWindow 
	CloseWindow(0)
EndIf
Edit2: Evtl. müsste man einen Abbruch noch besser behandeln, damit nicht einfach ein Fehler auftritt - aber ihr dürft ruhig auch noch ein wenig hirnen...

Edit: Hach sind wir wieder produktiv! Gleich zwei Methoden im Angebot. Jetzt kann sich aber niemand mehr beschweren... ;)

Gruss Andy
Hallo Andy vielen Dank für den Beispielcode. Ich denke davon werde ich schon was für mein Programm verwenden können, werde mal schauen. Eine Frage hätte ich allerdings. Was bedeuten die @ vor den Stringvariablen und warum ist einmal hinter der procedure ein "_" (CopyFileEx_) und das nächste mal _CopyFileExCallback() so wie in diesem beispiel.

Procedure.l _CopyFileEx(pSource.s,pTarget.s)
Erg = CopyFileEx_(@pSource.s, @pTarget.s, @_CopyFileExCallback(), 0, 0, 0)
ProcedureReturn Erg
EndProcedure

kann man irgendwo erlesen was sich hinter den weiteren Parametern von _CopyFileExCallback verbirgt?

Danke und Grüße aus Potsdam
frankmannb
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: ListViewGadget leeren und neu befüllen

Beitrag von ts-soft »

Naja, meinen Code hab ich zwischendurch mal getestet, ist Fehlerfrei.
Crossplattform, keine API, unterstützt auch x64 usw.
Und um meinen Code zu verstehen genügt die Hilfe, die mit PB mitgeliefert wird,
suchen in MSDN entfällt also.

Hier nochmal eine verfeinerte Version:

Code: Alles auswählen

Procedure CopyFileBuffer(source.s, dest.s, buffersize = 4096)
  Static FD, FS
  Protected *mem, result
  
  If Not FD
    FD = CreateFile(#PB_Any, dest)
    If FD And buffersize >= 1028
      FileBuffersSize(FD, buffersize)
    EndIf
  EndIf
  
  If Not FS
    FS = ReadFile(#PB_Any, source)
    If FS And buffersize >= 1028
      FileBuffersSize(FS, buffersize)
    EndIf
  EndIf
  
  *mem = AllocateMemory(buffersize)
  
  If *mem And FS And FD
    If Loc(FS) + buffersize < Lof(FS)
      ReadData(FS, *mem, buffersize)
      WriteData(FD, *mem, buffersize)
    Else
      buffersize = Lof(FS) - Loc(FD)
      If buffersize
        ReadData(FS, *mem, buffersize)
        WriteData(FD, *mem, buffersize)
      EndIf
      CloseFile(FS)
      CloseFile(FD)
      FD = 0
      FS = 0
      result = #True
    EndIf
    FreeMemory(*mem)
  EndIf
  ProcedureReturn result
EndProcedure

While Not CopyFileBuffer("D:\_Downloads\3DMark06_v110_installer.exe", "D:\_temp\3DMark06_v110_installer.exe")
Wend
wobei die While Wend schleife nur der Demo dient. Tatsächlich soll die Procedure nur bei Timerereignis aufgerufen werden, so kann das Programm normal weiterlaufen.
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
frankmannb
Beiträge: 47
Registriert: 21.02.2010 13:02

Re: ListViewGadget leeren und neu befüllen

Beitrag von frankmannb »

@CodeCommander
Auch dir vielen Dank für deine Hilfe mein Problem zu lösen. Ich werde auch versuchen deinen code zu verstehen und ihn in mein Programm einzubauen. Nur ist es erstmal bei mir so das ich eben noch anfänger bin und noch nicht so professional programmieren kann wie Ihr. Ich finde es aber super wie viele von euch hier Ihr bestes geben um anderen zu helfen. Sobald ich eine Version für mein Programm verwendet habe werde ich dies hier kundtun.

grüße aus Potsdam und nochmals vielen Dank
frankmannb
Benutzeravatar
AndyMars
Beiträge: 141
Registriert: 08.09.2004 11:59
Computerausstattung: Win11 Prof 64bit, i5-13500 @ 4.8 GHz, 32GB RAM, Nvidia RTX 4070 TI
Wohnort: Zürich, Schweiz
Kontaktdaten:

Re: ListViewGadget l&b - bzw. Kopieren mit Fortschrittsanze

Beitrag von AndyMars »

ts-soft hat geschrieben:Crossplattform, keine API, unterstützt auch x64 usw.
Also langsam beginnt mir dein Code zu gefallen. :)

Einzig anmerken müsste man, das keine Datei-Attribute, -Datum und NTFS-DataStreams mit kopiert werden - was vielleicht auch gar nicht so tragisch ist... (die ersten beiden wären auch einfach noch hinzu zu fügen - Get-,Set-,-FileAttributes,-FileDate). (Macht CopyFileEx intern noch einen CRC Test?...)

Antworten muss ich nun dennoch:
frankmannb hat geschrieben:Hallo Andy vielen Dank für den Beispielcode. Ich denke davon werde ich schon was für mein Programm verwenden können, werde mal schauen. Eine Frage hätte ich allerdings. Was bedeuten die @ vor den Stringvariablen und warum ist einmal hinter der procedure ein "_" (CopyFileEx_) und das nächste mal _CopyFileExCallback() so wie in diesem Beispiel.

Procedure.l _CopyFileEx(pSource.s,pTarget.s)
Erg = CopyFileEx_(@pSource.s, @pTarget.s, @_CopyFileExCallback(), 0, 0, 0)
ProcedureReturn Erg
EndProcedure

kann man irgendwo erlesen was sich hinter den weiteren Parametern von _CopyFileExCallback verbirgt?

Danke und Grüße aus Potsdam
frankmannb
Ach. Ja, das ist etwas verwirrend im Beispiel - weil ich sehr ähnliche Namen verwendet hab...

Ich stelle meinen Prozeduren gerne ein _ voran, weil sie dann schneller in der Codevervollständigung erscheinen und sich zudem offensichtlich von internen PB Funktionen unterscheiden. Bei nachfolgendem _ wie bei CopyFileEx_, bedeutet das für PB, dass es sich um eine API-Funktion handelt: CopyFileEx Function

Dieser API-Funktion kann man eine Adresse einer eigenen Funktion angeben, die wiederum von von der API-Funktion aufgerufen wird - deshalb heisst das auch Callback: "zurück rufen". Mit dem @ macht man genau das, man gibt die Adresse einer eigenen Prozedur an - in unserem Fall die von _CopyFileExCallback(). Dieser Prozedur werden einige Daten übergeben - das sind genau diese Parameter, nach denen du fragst: CopyProgressRoutine Callback Function - benutzen muss man diese Parameter nicht - aber die Prozedur muss die Parameter haben.

Ich hab den Code nochmal geändert, mit anderen Prozedurnamen und noch einer kleinen Unterscheidung, ob vom User unterbrochen wurde.

TS-Soft hat recht, dass mein Eventhandling nicht vom Feinsten ist... So ist das Schliessen des Fensters während des Kopierens zBsp nicht möglich... Wobei man sich darüber noch streiten könnte, ob das möglich sein soll... ^^
Was ich noch gut fände, wäre ein separater Dialog fürs Kopieren und/oder das Deaktivieren von anderen Dialogen - so dass es für den User unzweifelhaft klar ist, dass nichts anderes geht, weil jetzt gerade kopiert wird. Ich behaupte jetzt einfach mal, dass dies der separate Dialog für's Kopieren IST... ;)

Code: Alles auswählen

;CopyFileEx1004b.pb
;Beispiel für WinAPI CopyFileEx
;PB 4.4

Procedure.l WinCopyFileCallBack(TotalFileSize.q, TotalBytesTransferred.q, StreamSize.q, StreamBytesTransferred.q, dwStreamNumber.l, dwCallbackReason.l, hSourceFile.i, hDestinationFile.i, lpData.l)
  Shared SWinCopyFileBreak.b
  If TotalFileSize
  	Proz=100*TotalBytesTransferred/TotalFileSize
	  SetGadgetState(2,Proz)
  EndIf
  ev=1
  While ev
  	ev=WindowEvent()  ;hier werden alle Events gefressen - ausser die folgenden...
  	If ev=#PB_Event_Gadget
  		If EventGadget()=3 ;Abbrechen-Button
  			SWinCopyFileBreak=1
				ProcedureReturn 1 ;1=PROGRESS_CANCEL -> sagt CopyFileEx_, dass es abbrechen soll
  		EndIf
  	ElseIf ev=#PB_Event_CloseWindow
			SWinCopyFileBreak=2
			ProcedureReturn 1 ;1=PROGRESS_CANCEL
		EndIf
  Wend
  ProcedureReturn 0 ;0=PROGRESS_CONTINUE
EndProcedure

Procedure.l WinCopyFile(pSource.s,pTarget.s)
	Shared SWinCopyFileBreak.b
	If OpenWindow(0,200,200,400,105,"Datei Kopieren")
		TextGadget(0,5,5,390,20,"Kopiere von: "+pSource,#PB_Text_Center)
		TextGadget(1,5,25,390,20,"nach: "+pTarget,#PB_Text_Center)
		TextGadget(2,160,50,60,20,"")
		ProgressBarGadget(2,20,50,360,20,0,100)
		ButtonGadget(3,160,80,80,20,"Abbrechen")
		
		SWinCopyFileBreak=0
  	Erg = CopyFileEx_(@pSource.s, @pTarget.s, @WinCopyFileCallBack(), 0, 0, 0) ;Windows API-Befehl
  	
		If Erg=0
			Erg=-SWinCopyFileBreak
		EndIf
		
		CloseWindow(0)
	EndIf	
  ProcedureReturn Erg
EndProcedure

;hier natürlich bei euch existierende Pfade angeben (mit ner groooossen Datei)
Erg=WinCopyFile("D:\_Downloads\3DMark06_v110_installer.exe","D:\_temp\3DMark06_v110_installer.exe")

If Erg=1 ;hier könnte man selber auf das Fehler-/Abbruch-/Ergebnis reagieren
	Debug "Kopieren erfolgreich"
Else
	If Erg=-1
		Debug "Kopieren abgebrochen"
	ElseIf Erg=-2
		Debug "Kopieren abgebrochen durch Fenster schliessen"
	Else
		Debug "Fehler beim Kopieren"
	EndIf
EndIf
frankmannb
Beiträge: 47
Registriert: 21.02.2010 13:02

Re: ListViewGadget leeren und neu befüllen

Beitrag von frankmannb »

ts-soft hat geschrieben:wobei die While Wend schleife nur der Demo dient. Tatsächlich soll die Procedure nur bei Timerereignis aufgerufen werden, so kann das Programm normal weiterlaufen.
Hallo TS-Soft,

ich versuche gerade deinen Code bei mir im Programm unterzubringen. Das Klappt sofern man nicht in das Fenster klickt prima. Aber ich bekomme es nicht hin das das Programm "normal" weiterläuft (ohne keine Rückmeldung ) oder das ich das Programm abbrechen kann. Irgendwie stehe ich hier auf dem Schlauch. Könntest du mir hier nochmal helfen und mir ein kleines Beispiel mit einem Abbrechen bzw. fortsetzten Button coden?.

Vielen Dank
frankmannb
Antworten