Wie funktionierende ProgressBar

Nachfrager

Grünschnabel
Hallo!

Ich habe folgende Fragestellung: Wie programmiere ich eine funktionstüchtige ProgressBar, die nicht nur hin und her läuft. Meine Entwicklungsumgebung ist = Borland C++ Builder 6. Ziel ist, das a) eine Datei und b) mehrere Dateien kopiert werden und der Status des Vorgangs in einer ProgressBar sichtbar ist.

Grüße
Jannis
 
Danke erstmal!! Aber ich sitze vorm nächsten Problem: In der ProgressBar tut sich nur beim Programmstart etwas. wenn ich über einen Button eine ca. 15 MB große Datei kopiere, tut sich in der ProgressBar garnichts. Muss ich vielleicht dem Timer bzw. Dem Vorgang des Timers irgendwie sagen, dass er nicht nur beim Programmstart was machen soll mein code:

Code:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
MEMORYSTATUS lpBuffer;
lpBuffer.dwLength = sizeof(MEMORYSTATUS); 
GlobalMemoryStatus (&lpBuffer); 
ProgressBar1->Position = lpBuffer.dwMemoryLoad;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
CopyFile("C:\\test.txt", "C:\\test2.txt", true);
}
//---------------------------------------------------------------------------
 
Der ProgressBar muss von dir regelmässig geupdated werden. Wenn CopyFile da eine Systemfunktion ist, hast du allerdings schlechte Karten. Zum einen kommst du erst wieder zur Bearbeitung, wenn das File fertig kopiert ist. Ein Thread würde helfen, aber dann kommt es zum zweiten Problem: Du kannst bei CopyFile den aktuellen Stand nicht feststellen.

Du musst an der Stelle das Kopieren selbst übernehmen; und zwar scheibchenweise. D.h. lies 64 kB (Beispiel) ein, schreibe sie raus und update den ProgressBar.
 
Hallo,

ab hier wirds mir ein bisschen kompliziert... Könntest du mir mal ein Beispiel coden? Wäre dafür sehr dankbar!

Grüße
Jannis
 
Dann fehlt ja fast der Lerneffekt :)

Das eigentliche Problem ist nur das Aufteilen des Kopiervorganges. Wenn man das schrittweise angeht, ist das ganz einfach:

Ich markier das hier mal als Pseudocode:

do
{
LeseBlockAusQuellDatei
SchreibeBlockInZielDatei
}
while ( BlockGroesse > 0 );

D.h. du definierst dir einen Zwischenpuffer, 64kB ist eine ganz gute Grösse. Du versuchst 64kB in den Puffer zu laden. Du schreibst die gelesene Zahl an Bytes in die Zieldatei. War die gelesene Zahl an Bytes kleiner als 64kB hast du gerade den letzten Block kopiert. Wenn es 64kB war, dann lies den nächsten Block ein.

Nach jedem Block kannst du den Progressbar updaten.
 
Hallo,

das Updaten der ProgressBar lass ich später drankommen, aber ich komme mit deinem "Pseudocode" nur halbwegs weiter. Mein aktueller Code:

Code:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
int stream1;
char buf1[64];
int numRead1;
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------


void __fastcall TForm1::Button1Click(TObject *Sender)
{
do
{
  stream1 = FileOpen("C:\\test.txt", fmOpenRead);
  numRead1 = FileRead(stream1, buf1, 64);
  buf1[numRead1] = '\0';
  FileClose(stream1);
  ShowMessage(AnsiString(buf1) + ": " + AnsiString(sizeof(buf1)) + " bytes.");
}
while (sizeof(buf1) > 0);
}
//---------------------------------------------------------------------------

Das Problem ist, dass nur die LETZTEN 64 bytes (find ich erstmal einfacher als Kilobytes) ausgelesen werden. Außerdem war mir nicht direkt klar, ob das while (Puffergröße > 0); nur ein Beispiel war oder ob ich damit was anfangen sollte, denn das wurde immer nur "Endlosschleife"... Wäre für weitere Ansätze sehr dankbar.

Grüße
Jannis
 
Ist ein kleiner Denkfehler drin; das File darfst du natürlich nur einmal aufmachen, nicht immer wieder. Sprich, außerhalb der do/while-Schleife.

Die while-Schleife sollte als Bedingung dann while ( numRead1 > 0 ) haben; d.h. solange etwas aus der Datei gelesen werden kann, solange soll das Ganze laufen.

Versuch mal so:

Code:
stream1 = FileOpen("C:\\test.txt", fmOpenRead);
do
{
  numRead1 = FileRead(stream1, buf1, 64);
  //buf1[numRead1] = '\0';
  //ShowMessage(AnsiString(buf1) + ": " + AnsiString(sizeof(buf1)) + " bytes.");
}
while ( numRead1 > 0 );
FileClose(stream1);

Vorsicht auch mit dem buf1[numRead1] = '\0'. Wenn du genau 64 Bytes einliest, dann schreibst du diese 0 über die Array-Grenzen hinaus. Dann hast du einen der beliebtesten Fehler. Mal klappt alles, mal kracht es genau da, mal irgendwo später.

Ich meine, dadurch, dass du das Ganze selbst versuchst, läufst du eventuell auf einige Fehler mehr, aber du verstehst dann auch eher, wie das ablaufen soll. Und vor allem macht man üblicherweise bestimmte Fehler nicht nochmal.
 
Ist ein kleiner Denkfehler drin; das File darfst du natürlich nur einmal aufmachen, nicht immer wieder.

Ja, genau, stimmt ja... Aber ich komme ein Problem weiter: ich bin davon ausgegangen, dass in buf1 dann der Dateiinhalt gespeichert wird, aber die MessageBox sagt mir dann folgendes:

Code:
90
1234567890
12345678567890
1234567890
1234567890
12345678

wobei aber in der eigentlichen Datei folgendes stand:

Code:
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
1234567890
12345678

,sprich: 54 von 128 Bytes gelesen. Manche gelesenen Zeilen sind aber Quatsch, z.B. was hat es mit der 90 auf sich, und warum wiederholt sich ein teil in der 3. Zeile... Ich find das merkwürdig! Bitte um Aufklärung...

EDIT: Hab mein Code vergessen:

Code:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Progress1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
int stream1;
char buf1[64];
int numRead1;
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------


//---------------------------------------------------------------------------


void __fastcall TForm1::Button1Click(TObject *Sender)
{
stream1 = FileOpen("C:\\test.txt", fmOpenRead);
do
{
numRead1 = FileRead(stream1, buf1, 64);
}
while (numRead1 > 0);
FileClose(stream1);

ShowMessage (buf1);

}
//---------------------------------------------------------------------------

Grüße
Jannis
 
Zuletzt bearbeitet:
Hmm, das ist jetzt schwer zu sagen. Die Datei musst du im binär-Modus öffnen. Da sind dann auch noch Zeilenumbrüche mit drin. Insofern ist die Testausgabe über eine MessageBox wohl auch ungenau, manche Zeichen sind nicht vernünftig darstellbar.

Geh im Debug-Modus schrittweise durch und prüf den Inhalt von bufl. Da müssen immer 64 Bytes drin stehen, ausser evtl. im letzten Schwung.
 
Zurück