chart control frage

  • VB.NET

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von Kangaroo.

    chart control frage

    Hallo leute, ich habe eine frage:

    ich möchte 10000 werte (Single) darstellen. jetzt muss ich eine schleife laufen lassen die ungefähr so aussieht:

    Quellcode

    1. For Me.i = 1 To 10000
    2. Chart1.Series(1).Points.Add(istWertArray(i))
    3. Next i


    und das ist bei mir in einem timer.

    meine frage ist wie ich das machen kann, dass es nicht stockt. es ist zum kotzen...

    hat da jemand erfahrung?

    danke im vorraus

    EugenIS schrieb:

    hat da jemand erfahrung?

    Ich hab's noch niue benutzt, ist das das neue aus Oct 2010 ? Ich habe es noch nicht ausprobiert, insofern weiss ich nicht wie gut die Performance ist.

    Vermutlich wäre es besser die Updates in einem Background-Thread zu machen, allerdings müsstest Du dann jedes Mal für den Update invoken.

    Du kannst auch mal probehalber versuchen in Deiner Schleife nach dem .Add ein Application.DoEvents aufzurufen.

    Wenn Du Zeit hast stopp doch mal die Performance mit einer Stopwatch Klasse.
    uj. alles bahnhof. was genau soll ich mit meiner schleife machen? ich meine hab jetzt ein fenster, und ein timer holt sich die werte irgend wo ab. und weiter? wie könnte ich im hintergrund das machen lassen, ohne das das fenster beginnt zu stocken. ist timer kein hintergrundprozess?

    danke...

    EugenIS schrieb:

    uj. alles bahnhof. was genau soll ich mit meiner schleife machen?

    Na, dann mal alles gaaaanz langsam:

    Was meinst Du erst einmal mit "stocken" ? Du setzt in Deinem Timer 10.000 Werte auf einmal , während dieses Vorgangs kannst Du Deine Form nicht bewegen. Wenn das Chart Control langsam ist, dann kann das seine Zeit dauern. Entweder Du nimmst weniger Werte auf einmal, oder Du versuchst mal

    VB.NET-Quellcode

    1. For Me.i = 1 To 10000
    2. Chart1.Series(1).Points.Add(istWertArray(i))
    3. Application.DoEvents()
    4. Next i

    Nicht schön , aber naja ...

    Solltest Du eiin anderes Problem haben dann beschreib das bitte mal genauer, zum Raten hab ich keine grosse Lust.

    Und nein, ein Timer ist kein Hintergrundprozess.
    bo ich platze bald. also irgend wie klappt es auf brechen und biegen nicht. wie wird den ein echter hintergrund prozess gemacht? meint ihr ein backgroundworker? hab ich auch schon ausprobiert. genau die selbe scheiße. nur mit einem timer kämpft man viel weniger.

    kann mir jemand einen echt konstruktiven tipp geben? wie mach ich einen "echten" unabhängigen hintergrund prozess?

    hab 4 Arrays, mit jeweils 10000 werten. diese werte müssen 1 mal pro 10 sekunden aktualisiert werden. wie kann ich das so anstellen, das wärend es aktualisiert wird, mein fenster nicht gleich für sekunden hängen bleibt?

    für guten tipp bin ich wie immer sehr dankbar?

    und was genau macht
    Application.DoEvents()
    ???? :(

    EugenIS schrieb:

    es ist zum kotzen...

    EugenIS schrieb:

    bo ich platze bald

    EugenIS schrieb:

    genau die selbe scheiße

    EugenIS schrieb:

    kann mir jemand einen echt konstruktiven tipp geben?

    Bis jetzt hast Du Dich in diesem Thread nur ausgekotzt, 3 Zeilen Code gegeben die nicht funktionieren und auf keine Frage eine Antwort geschrieben. Warum sollte hier Deiner Meinung nach also irgendjemand Lust haben Dir zu helfen ? :huh:

    Wenn ich Deinen Code richtig verstehe setzt Du 10.000 Y-Werte des gleichen Datapoints, wozu soll das gut sein ?

    Bevor Du also weiter rummeckerst, dass wir Dir alle ja offenbar nur unkonstruktive Tips geben, solltest Du vielleicht mal selber etwas mehr tun um Dein Problem zu beschreiben. Hier geht es nicht nur darum Deine Schleife in einem "echten Hintergrund-Prozess" ablaufen zu lassen, sondern auch darum ob Du das Chart-Control überhaupt richtig nutzt bzw. seine Möglichkeiten ausnutzt. Auch eine DataPointCollection Class hat z.B. eine SuspendUpdates Funktion.

    Vielleicht solltest Du endlich mal aufhören zu fluchen und ein kurzes Programm schreiben , was beschreibt wie Du Dein Chart füllst., also
    - Form mit 1 Chart element
    - setzten der Chart & Series Properties im Load Event
    - Random Erzeugung der Datapoints und Füllen des Arrays
    - timer wo Du die DataPoint-Collection füllst

    Dann schaffen wir es vielleicht ausnahmsweise auch Dir "konstruktive Tips" zu geben.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kangaroo“ ()

    Alex , soviel hab selbst ich verstanden ;)

    Einen Dienst kannst Du abschreiben, da der nicht auf das GUI zugreift, und auch ein Thread / BGW muss ja wohl ständig auf den GUI-Thread invoken um das Control zu benutzen. Und wenn das 10.000x nacheinander passiert geht die Message-Queue ziemlich schnell in die Knie. Da ist es wohl egal ob im Timer oder Thread geschieht. Ich würde eher mal die SuspendUpdates / ResumeUpdates Methoden benutzen.

    Ich hab nur keine Lust hier ständig Antworten zu beliebigen Fragen zu geben, die der TE eh nicht versteht, und keine Antwort zu bekommen was er denn nun wo und wie selber ausprobiert hat.
    Vielleicht solltest Du endlich mal aufhören zu fluchen und ein kurzes Programm schreiben
    Ok. ich versuch es von anfang an:

    hab eine Adwin karte Light16. Wer die Lust mitbringt sich drüber zu informieren, dann :

    XML-Quellcode

    1. http://www.adwin.de/de/produkte/light16.html


    für die, die keine lust haben sich drüber zu informieren, sei nur so viel gesagt, dass es sich um ein echtzeitsystem handelt.

    diese karte stellt mir 4 mal 10000 werte zu verfügung, die ich mit einem befehl abholen kann: das mache ich hier als funktion:

    Quellcode

    1. Public Function get_sollWert(ByRef soll_wert_array() As Single) As Boolean
    2. If (checkCommunication = CommunicationState.Ok) Then
    3. Try
    4. soll_wert_array = adwin.Datas(2).GetAsSingle(FirstArrayIndex.One)
    5. Return True
    6. Catch ex As ADwinSystemException
    7. Return False
    8. End Try
    9. Else
    10. Return False
    11. End If
    12. End Function


    das array geb ich natürlich mit.

    so, bis jetzt kein problem. die werte sind da. hab 10000 stück erstmal von. die 3 anderen werte werden genau so abgeholt. nur die arrays haben natürlich andere namen.

    diese funktion ist richtig. hab ich schon geprüft die werte kommen an.

    WICHTIG ist es zu wissen, dass es von einem anderen timer erlädigt wird. der so zu sagen städig von alleine die werte aktualisiert. und der nachfolgender timer sollte eigenlich die werte zeichnen.

    der erste timer wird so ungefähr jede 100 ms aufgerufen, und erlädigt diverses. will jetzt hier nicht posten, wird zu viel. blos wenn er gerade die werte abholt, sperrt er die zeichnung. das sieht man durch wariable sperreWeilBeschriebenWird. hab ich jetzt für euch so gennant. ist eine boolean variable. wenn er die werte abholt, setzt er die auf true.

    jetzt hab ich die werte im array und wollte die mit einem chartcontroll ausgeben. das mache ich bis jetzt so:

    Quellcode

    1. Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    2. Chart1.Series(0).Points.Clear()
    3. Chart1.Series(1).Points.Clear()
    4. Chart1.Series(2).Points.Clear()
    5. Chart1.Series(3).Points.Clear()
    6. For Me.i = 1 To 10000
    7. While sperreWeilBeschriebenWird 'damit ist gemeint, dass er warten soll, wenn die werte gerade abgeholt werden
    8. System.Threading.Thread.Sleep(10)
    9. End While
    10. If ist_Check.Checked = True Then
    11. If sperreWeilBeschriebenWird = False Then Chart1.Series(1).Points.AddY(istWertArray(i))
    12. End If
    13. If soll_Check.Checked = True Then
    14. If sperreWeilBeschriebenWird = False Then Chart1.Series(2).Points.AddY(sollWertArray(i))
    15. End If
    16. If diff_Check.Checked = True Then
    17. If sperreWeilBeschriebenWird = False Then Chart1.Series(3).Points.AddY(istMinusSollArray(i))
    18. End If
    19. If f_check.Checked = True Then
    20. If sperreWeilBeschriebenWird = False Then Chart1.Series(4).Points.AddY(f_Array(i))
    21. End If
    22. Next i
    23. Me.Refresh()
    24. End Sub


    jetzt vermute ich das ich hier quatsch gemacht habe. und das mein lösungsansatzt so nicht gemacht wird.


    so, jetzt bin ich euren wunsch nachgegangen die ganzen karten auf den tisch zu legen. wer kann mir jetzt helfen. oder ist es noch verwirender?
    Also erst einmal danke für die ausführliche(re) Info, jetzt kann man sich wenigstens etwas darunter vorstellen. Nachstellen kann man Dein Problem natürlich nicht, da die Arrays mit Deiner Karte in einem anderen Timer erzeugt werden und Du keine Testfunktion mit Random-Werten zur Verfügung gestellt hast. Insofern kann man nur Vorschläge machen, die Du halt selber austesten musst ;)

    Grundsätzliches:
    In Forms Anwendungen gibt es immer genau 1 sogenannten GUI-Thread (GT), auf dem die gesamte Kommunikation zwischen allen vorhandenen Controls läuft. Controls basieren auf Fenstern und kommunizieren im Hintergrund über Messages, daher müssen sie auch immer auf genau diesem GT angesprochen werden. Auch wenn Du versuchst Arbeiten im Hintergrund ausführen zu lassen: sobald Du auf ein Control zugreifst musst Du vorher auf diesen GT switchen (invoken) um Änderungen durchzuführen.

    Das gleiche gilt für Windows.Forms.Timer : auch ihre Funktionen / Events laufen in dem GT, also muss 1 Timer erst einmal mit seinen Aufgaben fertig sein bevor ein 2ter Windows.Forms.Timer anfangen kann. Insofern sollte Deine Abfrage auf den Semaphor sperreWeilBeschriebenWird überflüssig sein. Henauso sollte jetzt auch klar sein warum Dein Fenster stockt: die Form Events (Ziehen, Vergrössern, Refresh) laufen ebefalls über den GT, wenn Dein Timer also noch beschäftigt ist, so werden diese Events gepuffert und werden erst ausgeführt sobald der GUI-Thread wieder frei ist.

    Hoffe das ist halbwegs klar geworden :huh:

    Zu Deinem Problem:
    - warum läuft Dein 1.Timer alle 100ms
    - wäre es nicht sinnvoll das Zeichnen des Charts aus dem 1.Timer heraus anzustossen , er muss eh warten bis das Zeichnen fertig ist (s.o)
    - Du setzt die Y-Werte einzeln, lt. MSDN Doku zur DataPointCollection Class scheint man die Y-Werte auch gleich als ganzes Double-Array übergeben zu können, also gleich .AddY(istWertArray).
    - Y-Werte sind als Double definiert, hoffe Deine Arrays auch
    - ich würde vor dem Zeichnen Point.SuspendUpdates und am Ende Point.ResumeUpdates aufrufen

    Auf jeden Fall ist wichtig Application.DoEvents nicht aufzurufen, da dieser Befehl erlauben würde andere GUI-Messages ( also auch Timer1-Tick) zu verarbeiten

    My 5 Cent ...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kangaroo“ ()

    danke erstmal. ich glaub so sollte es funktionieren:

    ist erstmal simulator:

    Quellcode

    1. Public Class Form1
    2. Delegate Sub progresschanged(ByVal value As Integer, ByVal zahl As Double)
    3. Dim eugen(1000) As Double
    4. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    5. For i As Integer = 0 To 1000
    6. eugen(i) = Rnd() * 1000
    7. Next
    8. Dim thr1 As New Threading.Thread(AddressOf aktualisiere)
    9. If thr1.IsAlive Then
    10. MsgBox("ist schon gestartet")
    11. Else
    12. thr1.Start()
    13. End If
    14. End Sub
    15. Public Sub aktualisiere()
    16. Dim change As New progresschanged(AddressOf change01)
    17. For i As Integer = 0 To 100
    18. Me.Invoke(change, i, Convert.ToDouble(Rnd))
    19. Threading.Thread.Sleep(10)
    20. Next
    21. End Sub
    22. Public Sub change01(ByVal i As Integer, ByVal zahl As Integer)
    23. ProgressBar1.Value = (i / 100) * 100
    24. Chart1.Series(0).Points.DataBindY(eugen)
    25. End Sub
    26. End Class


    teste noch


    noch eine frage: was beduetet invoke? was sag ich ihm damit?

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „EugenIS“ ()

    Ich habe mal Deinen Simulator genommen und das Zeichnen des ganzen zufällig erzeugten Arrays gemessen, und zwar in 1 Durchgang ohne es aufzuteilen:

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class Form1
    3. Dim rnd As New Random ' Zufallszahlen Generator
    4. Const MaxCount As Integer = 10000 ' Länge des Random-Arrays
    5. Dim sw As New Stopwatch ' stoppUhr
    6. Dim dblArray(MaxCount) As Double ' Radom Double-Array
    7. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    8. ' füllen des Array mit Zufallszahlen Double
    9. For i = 0 To MaxCount - 1
    10. dblArray(i) = rnd.NextDouble
    11. Next
    12. ' StoppUhr starten
    13. sw.Start()
    14. ' Chart1.Series(0).Points.SuspendUpdates()
    15. ' Zeichnen des Charts
    16. For i = 0 To MaxCount - 1
    17. Chart1.Series(0).Points.Add(dblArray(i))
    18. Next
    19. 'Chart1.Series(0).Points.ResumeUpdates()
    20. 'Me.Refresh
    21. ' stopwatch ausgeben
    22. sw.Stop()
    23. MessageBox.Show("Zeichen brauchte ms: " & sw.ElapsedMilliseconds)
    24. End Sub
    25. End Class


    Ergebnis: hier braucht der Zeichenvorgang nur 48ms für 10.000 Zahlen, mit SuspendUpdates / ResumeUpdates wird das nochmal gedrückt auf 18ms.

    Am Zeichnen des Charts kann Dein Problem also wohl kaum liegen.

    Edit: ich habe nachträglich mal mit 4 Arrays / 4 Series gemessen, auch hier liegt das gesamte Ergebnis zum Hinzufügen der Arrays zum Chart im 50ms Bereich
    Nur das Me.Refresh braucht ca 1 Sekunde, aber das kann wohl auch kaum unterdrückt oder beschleunigt werden

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Kangaroo“ ()

    also ich muss zu dienem beitrag echt danke sagen. das ist nicht selbsverständlich.

    was das problem angeht, hab ich immer noch.
    naja. muss ich halt suchen woran es liegt.
    wollte jetzt was neues ausprobieren. und habe noch zwei fragen:

    gibt es eine alternative zu Me.Refresh() ? etwas was schneller läuft? (ich will nur die zeichnung aktualisieren)

    und wie könnte ich bei chart controll nur einen punkt ERSETZEN?

    ich kenne bis jetzt nur chart1.Series(0).Points.DataBindY(array). gibt es da eine möglichkeit einfach z.B. beim x=5 die zahl 60 setzen? halt überschreiben und die zeichnung aktualisieren?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „EugenIS“ ()

    EugenIS schrieb:

    was das problem angeht, hab ich immer noch.

    War ja zu befürchten , allerdings ist 1 sec für den Refresh ja auch nicht die Welt. Wenn Deine Form länger stockt, dann liegts evtl an etwas anderem. Nimm Dir mal die Stopwatch Klasse und schau mal nach wo die Zeit verloren geht. Z.B. ist ein Threadings.Thread.Sleep auch tödlich wenn es auf dem GUI-Thread ausgeführt wird.

    EugenIS schrieb:

    gibt es eine alternative zu Me.Refresh() ? etwas was schneller läuft?

    Jedes Control hat eine Refresh Methode, also auch Dein Chart1, allerdiings wird da wohl auch die meiste Zeit draufgehen.

    EugenIS schrieb:

    ich kenne bis jetzt nur chart1.Series(0).Points.DataBindY(array). gibt es da eine möglichkeit einfach z.B. beim x=5 die zahl 60 setzen? halt überschreiben und die zeichnung aktualisieren?

    Gibt reichlich Möglichkeiten: im Namespace System.Windows.Forms.DataVisualization.Charting findest Du alle interessanten Klassen um das Chart Control herum die Du verwendest (Series, DataPointCollection, DataPoint).

    Schau Dir mal gerade die DatapointCollection hat, die hat die verschiedensten Möglichkeiten einien Punkt zum Chart hinzuzufügen :rolleyes: