Entwickler-Ecke

WinForms - Selbstgebaute Progressbar richtig füllen


Garzec - Di 19.07.16 13:49
Titel: Selbstgebaute Progressbar richtig füllen
Hallo,

ich habe mit meinem Anfängerhalbwissen eine runde Progressbar in einem Usercontrol gebastelt. Google sei Dank. Der Kreis füllt sich auch prima, ich stehe nur grade vor dem Problem, diesen über meine Variable zu füllen.

Ich benutze einen MP3Player über die winmm.dll, der Kreis soll also passend zum Lied gefüllt werden. Jetzt habe ich ein ulong Property, das die Dauer des Liedes berechnet bzw. hält.

Folgende Methoden füllen den Kreis


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
        private void ProgressUpgrade(object fortschritt)
        {
            progessBarCustom.Invoke((MethodInvoker)delegate
            {
                progessBarCustom.UpdateProgress(Convert.ToInt32(fortschritt));
            });
        }



C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
 private void ProgressBarFuellen()
        {
            Task.Run(() =>
            {
                for (int i = 0; i < 101; i++)
                {
                    new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(ProgressUpgrade)).Start(i);
                    System.Threading.Thread.Sleep(50);
                }
            });
        }


Zu meiner Frage:

Da sich der Kreis momentan noch von alleine füllt, muss er sich jetzt in Abhängigkeit zur Lieddauer füllen. Wenn ich versuche,


C#-Quelltext
1:
System.Threading.Thread.Sleep(Convert.ToInt32(datei.Duration / 100));                    


zu schreiben, ist das glaube ich 1. Blödsinn und 2. kommt eine Format Exception auf.

Weiß jemand, wie ich die Dauer nun dort einpflege =?


Ralf Jansen - Di 19.07.16 15:26

Anstatt i einfach hoch zu zählen berechne i doch einfach. Du solltest doch Gesamtlaufzeit und aktuellen Zeitpunkt im Titel irgendwie rausbekommen können und daraus i berechnen.
Aus deiner Vorschleife For-Schleife wird dann halt einfach ein while oder do while Konstrukt.

Pseudocode

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
double runtime = ERMITTLELAUFZEIT();
double currenttime = 0.0;

while(currenttime < runtime)
{    
    ProgressUpgrade(currenttime/runtime * 100);
    System.Threading.Thread.Sleep(50);
    currentime = ERMITTLEZEITPUNKT();
}


Garzec - Di 19.07.16 15:38

Hey,
vielen Dank für die Antwort. Die Laufzeit kann ich berechnen, mithilfe dieser Berechnung


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
public ulong Duration
        {
            get
            {
                StringBuilder builder = new StringBuilder(128);
                mciSendString("status mediafile length", builder, 128, IntPtr.Zero);
                return Convert.ToUInt64(builder.ToString());
            }
        }


Den aktuellen Zeitpunkt der Datei kann man aber meines Wissens nicht bestimmen. Genau da liegt mein Problem :P


Ralf Jansen - Di 19.07.16 15:47

laut google sollte es "status mediafile position" sein.


Th69 - Di 19.07.16 15:50

Hallo Garzec,

Thread-Sleep ist zum einen sehr ungenau (ca. 15ms Auflösung), so daß es passieren kann, daß die ProgressBar über 100 hinausläuft, aber der Hautpfehler bei deiner Berechnug ist, daß du die Dauer (duration) in Sekunden (höchstwahrscheinlich ;- ) hast, aber die Methode die Zeit in Millisekunden erwartet.

Besser wäre es m.E. wenn du dir beim Liedstart die aktuelle Zeit holst (DateTime.Now) und dann in einem Timer (von ca. 1 Sekunde oder evtl. auch 500ms) wartest und dann den ProgressBar-Wert dort berechnest (über die aktuelle Zeit in Abhängigkeit der Dauer).

Edit: oder über den von Ralf Jansen vorgeschlagenen Wert.


Garzec - Di 19.07.16 20:29

Vielen Dank für eure Antworten.

Jetzt habe ich folgende Berechnungen:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
        public ulong Duration
        {
            get
            {
                StringBuilder builder = new StringBuilder(128);
                mciSendString("status mediafile length", builder, 128, IntPtr.Zero);
                return Convert.ToUInt64(builder.ToString());
            }
        }

        public ulong LiedPosition
        {
            get
            {
                StringBuilder builder = new StringBuilder(128);
                mciSendString("status mediafile position", builder, 128, IntPtr.Zero);
                return Convert.ToUInt64(builder.ToString());
            }
        }


Und bei Aufruf dann folgende Methode:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
private void ProgressBarFuellen()
        {
            Task.Run(() =>
            {
                ulong laufzeit = datei.Duration;
                ulong aktuelleZeit = 0;
                while (aktuelleZeit < laufzeit)
                {
                    ProgressUpgrade(aktuelleZeit / laufzeit * 100);
                    System.Threading.Thread.Sleep(50);
                    aktuelleZeit = datei.LiedPosition;
                }
            });
        }


Beim Start taucht tatsächlich eine Exception auf (falsches Format), obwohl das richtige Zeitformat wiedergegeben wird. Bei einem Lied von 4min 31sek. wird eine Zahl von ~~~27000 geliefert. Das sollten also die Millisekunden sein.

Nun frage ich mich, was ihn an dem Format stört =?


Ralf Jansen - Di 19.07.16 21:03

Zitat:
Nun frage ich mich, was ihn an dem Format stört =?

Es hilft uns wenn du sagst wo. Und wie das Format wirklich aussieht.


C#-Quelltext
1:
aktuelleZeit / laufzeit * 100                    


Das wird nicht funktionieren. Wenn die beiden Variablen Ganzzahlen sind ist das Ergebnis auch immer eine ganze Zahl und da aktuelleZeit immer kleiner Laufzeit ist kommt da immer 0 raus (oder im speziellen Sonderfall halt 100). Du musst schon mit Fließkommazahlen rechnen so wie in meinem Beispiel oder so rechnen das auch eine sinnvolle Division möglich ist.
Beispiel mit Ganzzahldivision

Quelltext
1:
2:
999/1000 * 100 = 0    weil 999/1000 = 0 ist mit Rest 999
(999*100)/1000 = 99   Rest 900 aber der ist hier egal ;)



Bitte nicht heimlich crossposten [https://www.spieleprogrammierer.de/16-eingabe-audio-physik-netzwerk-scripting-und-ki/25850-dauer-einer-mp3-datei-ermitteln/].


Garzec - Di 19.07.16 22:14

Sorry, der Post ist zwar noch nicht alt, da ging es aber noch um die Ermittlung der Dauer einer Datei :) Jetzt geht es ja um das Füllen einer Progressbar über die Zeiten