Hallo,
ich habe öfters Programme (Konsolenanwendung, C, Visual Studio), die
viele Sekunden bis einige Minuten dauern. Zum Beispiel Anwendung um
einen µC zu flashen.
Dabei möchte ich dem Benutzer alle paar Sekunden eine Rückmeldung geben
um anzuzeigen, dass es einen Fortschritt gibt und dass das Programm
nicht einfach abgestürzt ist. Ich persönlich mag möglichst detaillierte
Ausgaben. Die Programme werden auch von "Laien" verwendet, die eine
möglichst einfache Ausgabe wünschen.
Meine Idee ist, einfach eine Prozentangabe anzuzeigen. Sie soll den
Fortschritt für den kompletten Programmablauf anzeigen. Nach jeder
Funktion, die etwas länger dauert (z.B. 1 Sekunde) wird sie
aktualisiert.
Mein Problem ist eine möglichst geschickte Implementierung, die ich
immer wieder verwenden kann.
Beispiel Flashen: Es gibt die Funktionen Connect(), Erase(), Write() und
Verify().
Da es 4 Stück sind, würde die Prozentangabe nach jeder Funktion um 25%
steigen. Eine Lösung wäre natürlich eine Funktion ShowProgress(), die
mit jedem Aufruf eine statische Variable um 25 erhöht und sie anzeigt.
Allerdings sind die 25% von der Anzahl der Funktionen abhängig und ich
müsste sie jedes Mal ändern, wenn ich eine neue Funktion hinzufüge. Um
bei dem Beispiel zu bleiben, wenn die Funktion Reset() hinzukommt,
dürfte ShowProgress() die Variable nur um 20 erhöhen.
Gibt es ein Möglichkeit zur Compilezeit die Anzahl der Aufrufe zählen zu
lassen? Eine Art define COUNTOF(ShowProgress) wie
1
__LINE__
oder
1
__FILE__
? Oder sonst eine Möglichkeit?
ShowProgress würde so aussehen:
Gruß
PP
P.S.: Ich weiß, dass die Funktionen unterschiedlich lang dauern und sich
dadurch die Prozentzahl nicht linear zu Zeit ist. Das ist aber ok.
P.P.S. Ich weiß auch, dass in diesem Beispiel die Ausgabe so aussieht:
Fortschritt: 25% Fortschritt 50% Fortschritt: 75% Fortschritt 100%
Das Problem werden ich mit \b lösen.
> Gibt es ein Möglichkeit zur Compilezeit die Anzahl der Aufrufe zählen zu
lassen?
Nein. Ist in deinem Fall auch sinnlos.
Derartige Prozentangaben werden an den Daten festgemacht. D.h. der
Prozentbalken wandert mit dem Anteil der bereits übertragenen Daten.
Für Connect u dgl. fügt man dann einfach einen gewissen Anteil an
"falschen Daten" in die Anzeige ein, oder macht zusätzlich zum Balken
noch eine Statusanzeige.
Das Problem: Im Vorfeld feststellen wieviele Daten zu bearbeiten sind.
Das ist einfach, wenn die Zahl im Programm schon vorhanden ist, aber
wenn Windows beim Umkopieren von Files erst mal eine Nachdenkpause
einlegt um die Größe der zu kopierenden Daten zu bestimmen, krieg ich
regelmässig einen Auszucker.
Auf Konsolen wurde zb gerne ein Balken gebildet aus # benutzt.
mit jeden 5% (oder so) kommt ein # dazu.
Ein Log könnte dann zb so aussehen
1
ConnectingtoServerxyyz
2
Done!
3
TransferingData(83986Bytes)
4
0102030405060708080100
5
+---+---+---+---+---+---+---+---+---+---+
6
|##############
Man sieht: Der Verbindungsaufbau hat geklappt und es wurden bereits ca.
35% der Daten übertragen.
Der Aufbau ist einfach:
Das Balkenmodul kriegt am Anfang die Maximalzahl und wird danach zb aus
der Übertragungsfunktion regelmässig mit der bereits übertragenen Menge
aufgerufen. Daraus errechnet es sich die Prozentzahl und bestimmt
wieviele # sichtbar sein müssten. Da es darüber Buch führt, wieviele #
bereits angezeigt werden, kann es daher auch leicht bestimmen, wieviele
# an die Anzeige angehängt werden müssen und gibt die dann einfach bei
Bedarf aus.
Hallo,
erstmal danke für die schnelle Antwort. Ich habe gerade gesehen, dass
ich es in µC und Elektronik gepostet habe. Könntest du es nach
PC-Programmierung verschieben?
Karl Heinz Buchegger schrieb:> Derartige Prozentangaben werden an den Daten festgemacht. D.h. der> Prozentbalken wandert mit dem Anteil der bereits übertragenen Daten.
In meinem Fall hat aber nicht jede Funktion Daten, z.B. Erase sendet nur
den Erasebefehl mit ein paar Bytes, die Ausführung kann aber schon mal 8
Sekunden gehen.
Karl Heinz Buchegger schrieb:> Das Problem: Im Vorfeld feststellen wieviele Daten zu bearbeiten sind.
Genau! Ich vereinfache das Problem in dem ich "Menge der Daten" durch
"Anzahl der Funktionsaufrufe" ersetze. Die sind sogar zur Compilezeit
bekannt. Ich könnte sie natürlich von Hand zählen, aber es wäre schön,
wenn der Präprozessor/Compiler/wer auch immer das für mich übernehmen
könnte.
Gruß
PP
Habe gerade erst das Post von 13:33 gesehen:
Karl Heinz Buchegger schrieb:> Connecting to Server xyyz> Done!> Transfering Data (83986 Bytes)> 0 10 20 30 40 50 60 70 80 80 100> +---+---+---+---+---+---+---+---+---+---+> |##############
Ich möchte nicht den Text der Funktion ausgeben, die er gerade ausführt.
Das Programm startet und der Benutzer sieht nur die Prozentzahl, die
eben alle paar Sekunden (kann unterschiedlich lang sein) um ein paar
Prozentpunkte steigt. Sobald sie bei hundert ist, ist das Programm
fertig.
Gruß
PP
Paulchen Panther schrieb:> Hallo,>> erstmal danke für die schnelle Antwort. Ich habe gerade gesehen, dass> ich es in µC und Elektronik gepostet habe. Könntest du es nach> PC-Programmierung verschieben?>> Karl Heinz Buchegger schrieb:>> Derartige Prozentangaben werden an den Daten festgemacht. D.h. der>> Prozentbalken wandert mit dem Anteil der bereits übertragenen Daten.> In meinem Fall hat aber nicht jede Funktion Daten, z.B. Erase sendet nur> den Erasebefehl mit ein paar Bytes, die Ausführung kann aber schon mal 8> Sekunden gehen.
Du musst ja nicht die Anzahl der Daten nehmen. Dem Balkenmodul ist das
ja völlig schnurz, was die Zahlen zu bedeuten haben. In dem Fall kannst
du ja auch jede Sekunde einen dazunehmen.
Natürlich kannst du auch die Anzahl der Aufrufe nehmen, klar. Nur ist
diese Zahl nicht sehr aussagekräftig, ausser als 'Schritt 1 von 4'. Da
aber deine Schritte sich im Zeitbedarf wesentlich unterscheiden, wird
das etwas zu grob sein. Benutzer tendieren nämlich auch dazu, eine
einigermassen gleichmässig wachsende Fortschrittsanzeige zu erwarten.
Bleibt der Balken für längere Zeit stehen, werden sie nervös.
> "Anzahl der Funktionsaufrufe" ersetze. Die sind sogar zur Compilezeit> bekannt.
Wie das?
for( i = 0; i < NrBytes; ++i )
TransferByte( Bytes[i] );
wieviele Aufrufe von TransferBytes werden erfolgen?
Paulchen Panther schrieb:> Ich vereinfache das Problem in dem ich "Menge der Daten"> durch "Anzahl der Funktionsaufrufe" ersetze.> Die sind sogar zur Compilezeit bekannt.
Sind sie eben nicht, spätestens wenn Funktionen aus einer Schleife
heraus aufgerufen werden.
Rufus Τ. Firefly schrieb:> Paulchen Panther schrieb:>> Ich vereinfache das Problem in dem ich "Menge der Daten">> durch "Anzahl der Funktionsaufrufe" ersetze.>> Die sind sogar zur Compilezeit bekannt.>> Sind sie eben nicht, spätestens wenn Funktionen aus einer Schleife> heraus aufgerufen werden.
Die Programme sind so aufgebaut, dass die Anzahl der Aufrufe konstant
und zur Compilezeit bekannt ist.
Danke für das Verschieben!
Paulchen Panther schrieb:> Rufus Τ. Firefly schrieb:>> Paulchen Panther schrieb:>>> Ich vereinfache das Problem in dem ich "Menge der Daten">>> durch "Anzahl der Funktionsaufrufe" ersetze.>>> Die sind sogar zur Compilezeit bekannt.>>>> Sind sie eben nicht, spätestens wenn Funktionen aus einer Schleife>> heraus aufgerufen werden.>> Die Programme sind so aufgebaut, dass die Anzahl der Aufrufe konstant> und zur Compilezeit bekannt ist.
Na dann zähl sie.
Mir kommt echt vor, du machst hier aus einer Mücke einen Elefanten.
Karl Heinz Buchegger schrieb:> Mir kommt echt vor, du machst hier aus einer Mücke einen Elefanten.
Zugegeben, ich könnte es auch von Hand machen ;-)
Ich dachte vielleicht hat hier jemand ne simple Lösung. Schließlich bin
ich nicht der erste, der eine Fortschrittsanzeige programmiert.
Gruß
PP
Paulchen Panther schrieb:> Karl Heinz Buchegger schrieb:>> Mir kommt echt vor, du machst hier aus einer Mücke einen Elefanten.>> Zugegeben, ich könnte es auch von Hand machen ;-)> Ich dachte vielleicht hat hier jemand ne simple Lösung.
Wozu?
Im Allgemeinen Fall ist es nicht möglich diese Anzahl festzustellen.
> Schließlich bin> ich nicht der erste, der eine Fortschrittsanzeige programmiert.
Weil alle anderen das anders machen als du.
so wäre das allgemein verwendbar.
Am Anfang sag ich dem Balken die Grenzen in denen sich der Wert, den er
in UpdateProgress bekommen wird, bewegen wird. Ich werd ihm
wahrscheinlich auch noch mitteilen in welchen Prozentabständen ich ein
Tickmark haben will und eventuell welches Zeichen dafür verwendet werden
soll.
Und in weiterer Folge ruf ich dann UpdateProgress mit der jeweiligen
Zahl auf.
Edit:
Ob das dann ein Balken oder eine Prozentzahl ist, ist gehupft wie
gesprungen. Prozentzahlen funktionieren genau gleich, nur dass ich beim
Config Call dann eben noch die Beschriftung mit dazunehme.
Du kannst natürlich eine Klasse ProcessingStep schreiben, davon dann
abgeleitet deine einzelnen Schritte.
Die baust du in deine Liste, iterierst darüber und aktualisierst in der
gleichen schleife die Anzeige.
so etwa:
for(int i =0;i<steps.length;i++){
steps[i].run();
Percentage = (unsigned int) ( (100 * Progress) / steps.length);
printf("Fortschritt: %u\% ", Percentage);
}
Tom K. schrieb:> Bei genauerem Nachdenken funktioniert das natürlich nicht mit Schleifen.> Und kommentierte Schritte werden auch fälschlich mitgezählt
Danke für das Beispielprogramm. Es scheint wohl keine immer
funktionierende, einfache Lösung zu geben außer: Von Hand zählen und die
Anzahl in einem Define einzutragen.
Vielen Dank für eure Beiträge!
Mach das doch wie FTP,... je xxx Datenmengen ein Hash, keine Prozente.
Wenn du magst, ev. jede Sekunde noch einen Punkt während der Erase oder
auch
ein E anstelle des #. Die Benutzer merken sich wie lange das dauert und
wissen auch ob ein langes Programm oder ein kurzes gefläsht wird.