Announcement

Collapse
No announcement yet.

Probleme mit zur Laufzeit erzeugten Lineseries

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Probleme mit zur Laufzeit erzeugten Lineseries

    Hallo,<br>
    ich habe einen Fehler der auftaucht, wenn ich TLineseries zur Laufzeit erzeuge. Das Problem war, daß ich 16 Ströme in einem Chart anzeigen mußte. Da ich zur Faul war 16 mal auf hinzufügen zu klicken habe ich diese zur Laufzeit erzeugt.
    <pre>
    Stroeme:Array[1..16] of Tlineseries;
    .
    .
    .
    Stroeme[i]:=Tlineseries.Create(self);
    chart.AddSeries(Stroeme[i]);
    </pre>
    Nun passiert im folgenden Codeteil etwas was ich nicht verstehen kann:
    <pre>
    for i:=1 to 16 do
    begin
    Stroeme[i].active:=(Messwerte[i].ffilename<>'') and Messwerte[i].fselected;
    end;
    </pre>
    Und zwar durchläuft das Programm mit I=1 und 2 die Schleife ganz normal.<br>Ab i=3 jedoch stürzt das Programm mit der Fehlermeldung EAccessviolation ab. Der Debugger zeigt auch bei stroeme[3] "nicht verfügbarere Wert" an. Die Ansicht von z.B. Stroeme[3].active zeigt im Debugger aber doch einen richtigen Wert an.<br>
    Hat dazu jemand eine Idee ? Ich benutze Delphi5 prof Update Pcak 1

  • #2
    Hallo Frank,<br>ich denke, dass stroeme nicht Dein Problem ist. Das Problem liegt sicher darin, dass Du i für Stroeme und Messwerte verwendest. Zeigt Messwerte[3] wirklich auf ein Objekt ? <br>Jens Schuman

    Comment


    • #3
      Hallo Jens,<br>
      eigentlich kann da nicht das Problem sein. Messwerte ist folgendes Record:<br>
      <pre>
      TMesswertDatensatz=record
      FFilename: String; //Name des Datensatzes bei '' nicht vorhanden
      Fselected: Boolean; //Wird Eintrag angezeigt
      FReferenz: Integer; //Referenzverweis auf den Eintrag in der Listbox
      Messwertdaten: TMesswertdaten; //Dateninhalt
      end;
      Messwerte: Array[1..16] of TMesswertDatensatz;
      Stroeme:Array[1..16] of Tlineseries;
      </pre>
      Ich hatte auch schon daran gedacht, daß Messwerte der Übeltäter ist, und darum das folgende gemacht:<br>
      <pre>
      var
      i:Integer;
      aktiv:Boolean;
      begin
      for I:=low(Stroeme) to high(Stroeme) do
      begin
      aktiv:=(Messwerte[i].ffilename<>'') and Messwerte[i].fselected;
      Stroeme[i].active:=aktiv;
      end;
      end;
      </pre>
      Hier kam aber auch der Fehler genau in der Zeile Stroeme[3].active:=aktiv. Eine Sache ist mir wohl noch beim Untersuchen der Lineseries aufgefallen. Strome[1] und Strome[2] haben als Owner einen Zeiger auf mein Chart Stroeme[>=3] haben dort nil stehen. Dieser Verweis verschwindet aber erst nachdem der Konstruktor verlassen worden ist.<br>
      Ich versuch noch mal das ganze möglicht klein zu fassen, um den ganzen Code posten zu können. Vielleich könnt Ihr das dann besser nachvollziehen.<br>
      Gruß Fran

      Comment


      • #4
        Moin Frank,<br>dieser Code läuft bei mir mit D5 pro SP1 einwandfrei<br>
        <pre><font size="1" face="Verdana">
        procedure TForm1.btnAddClick(Sender: TObject);
        var
        iCnt : Integer;
        begin
        For iCnt:=1 to 16 do
        begin
        Stroeme[iCnt]:=TLineSeries.Create(Self);
        Chart1.AddSeries(Stroeme[iCnt]);
        end;
        end;

        procedure TForm1.Button2Click(Sender: TObject);
        var
        iCnt : Integer;
        begin
        For iCnt:=1 to 16 do
        begin
        Stroeme[iCnt].Active:=True;
        Stroeme[iCnt].Add(Random(10),'T');
        end;
        end;
        </font></pre>
        <br>Jens Schuman

        Comment


        • #5
          Hallo Jens,<br>
          das gleiche hatte ich gerade auch gemacht, um den Fehler weiter einzuschränken, aber es funktionierte auch bei mir einwandfrei. Ich nimm jetzt mal nach und nach alles raus, bis eigentlich nur noch das Grundgerüst wie bei deinem Code drinsteht. Dann sollte ich den Übeltäter eigentlich finden. Ich werde mich aber noch mal dazu melden und erzählen, was es denn war.<br>
          Erst mal Dank

          Comment


          • #6
            So ich habe jetzt den Übeltäter gefunden. Und zwar kann der Benutzer auswählen ob er die Serien als Line oder Barseries sehen möchte. Die Umwandlung mache ich über folgenden Code.<br>
            <pre>
            procedure TForm1.Button3Click(Sender: TObject);
            var I:Integer;
            TheSeries:TChartSeries;
            begin
            With chart1 Do
            Begin
            For i := 0 To SeriesCount - 1 Do
            Begin
            TheSeries := series[i];
            If checkbox1.checked Then
            ChangeSeriesType(TheSeries, TBarSeries)
            Else
            ChangeSeriesType(TheSeries, TLineSeries);
            End;
            End;
            end;
            </pre>
            Wenn Du diesen Code bei dir einfügst und nochmal Button2 drückst gibt es den Fehler, der auch bei mir aufgetaucht ist. Allerdings dann schon bei Stroeme[2]. Ich habe jetzt auch schon stroeme als TChartSeries definiert, es hat sich aber nichts verändert. Im Prinzip kann ich zwar auf die Barseries verzichten, aber andererseits ist es für den Endbenutzer immer ne schöne Spielerei.<br>
            Hat vielleicht jemand noch eine Idee ? Es interessiert mich ja nun doch wo das Problem lieg

            Comment


            • #7
              Moin Frank,<br>ich habe Deinen Code 1 zu 1 kopiert und erhalte keinen Fehler. <br>Jens Schuman

              Comment


              • #8
                Wie ? Das verstehe ich jetzt aber gar nicht mehr. Hier ist noch mal mein voller Code.
                <pre>
                type
                TForm1 = class(TForm)
                Chart1: TChart;
                Button1: TButton;
                Button2: TButton;
                CheckBox1: TCheckBox;
                procedure FormCreate(Sender: TObject);
                procedure Button1Click(Sender: TObject);
                procedure Button2Click(Sender: TObject);
                private
                { Private-Deklarationen }
                Stroeme: Array [1..16] of TChartseries;
                public
                { Public-Deklarationen }
                end;

                var
                Form1: TForm1;

                implementation

                {$R *.DFM}

                procedure TForm1.FormCreate(Sender: TObject);
                var iCnt:integer;
                begin
                for iCnt:= low(Stroeme) to high(Stroeme)do
                begin
                Stroeme[iCnt]:=TChartseries.Create(nil);
                chart1.AddSeries(Stroeme[iCnt]);
                end;
                end;

                procedure TForm1.Button1Click(Sender: TObject);
                var iCnt:integer;
                begin
                for iCnt:= low(Stroeme) to high(Stroeme)do
                begin
                Stroeme[iCnt].active:=true;
                end;
                end;

                procedure TForm1.Button2Click(Sender: TObject);
                var iCnt:Integer;
                TheSeries:TChartSeries;
                begin
                With chart1 Do
                Begin
                For iCnt := 0 To SeriesCount - 1 Do
                Begin
                TheSeries := series[iCnt];
                If checkbox1.checked Then
                ChangeSeriesType(TheSeries, TBarSeries)
                Else
                ChangeSeriesType(TheSeries, TLineSeries);
                End;
                End;
                end;
                </pre>
                Wenn ich jetzt auf Button2 drücke und danach auf Button1 kommt bei Stroeme[iCnt].active:=true; mit iCnt:=1 eine Schutzverletzung. Weichen vielleicht die Versionen von TChart untereinander ab ? Ich habe TChart pro 4.0

                Comment


                • #9
                  Hallo Frank,<br>Du hast recht. Bei tritt der Fehler auch auf. Aber erst nachdem der Serientype getauscht wurde.Folgender Code läuft bei mir.<br>
                  <pre><font size="1" face="Verdana">

                  Stroeme : Array[1..16] of TChartSeries;

                  procedure TForm1.Button1Click(Sender: TObject);
                  var I:Integer;
                  TheSeries:TChartSeries;
                  begin
                  With chart1 Do
                  Begin
                  For i := 0 To SeriesCount - 1 Do
                  Begin
                  If checkbox1.checked Then
                  ChangeSeriesType(<b>Stroeme[i+1]</b>, TBarSeries)
                  Else
                  ChangeSeriesType(<b>Stroeme[i+1]</b>, TLineSeries);
                  End;
                  End;
                  end;
                  </font></pre>
                  <br> Die Zeile TheSeries := series[i]; macht wahrscheinlich die Probleme. Da ich leider nicht die TeeChart Sourcen habe, komme mit dem Debugger auch nicht weiter.
                  <br>Jens Schuman

                  Comment


                  • #10
                    Ja funktioniert bei mir auch. Vielen Dank. <br>
                    Aber trotzdem sehr interessant, in den FAQ unter http://www.steema.com/support/faq/NewVCL/faq_vcl.htm haben die genau mein Vorgehen beschreiben um den Seriestyp zur Laufzeit zu verändern. Eigentlich sollte über die Zuweisung TheSeries := series[i]; doch beides die gleichen Objekte sein. Nur ich denke auch, daß man hier ohne die Sourcen nicht weiter kommt.<br>
                    Also noch mal vielen Dan

                    Comment


                    • #11
                      Hi

                      Ich vermute .ChangeSeriesType(<b>var</b> Series: TChartSeries, ..) ist so deklariert. Der TChart versucht eine Serie mit einem bestimmten Klassentyp in ein neues Object mit einem anderen Klassentyp zu konvertieren. D.h. .ChangeSeriesTypes() verwandelt eine Chartserie in einen anderen Typ indem es die originale Serie in ein neues Object kopiert und das alte zerstört. Da Du nun aber eine temopräre Variable nutzt wird NUR diese aktualisiert und Deine array[] of ChatSeries zeigt dann auf zerstörte Objecte.<br>
                      Einfach mal nach dem Aufruf von .ChangeSeriesType() folgenden Code einfügen:

                      <pre>

                      Series := Stroeme[iCnt]
                      ChangeSeriesType(Series, ...);
                      if Series <> Stroeme[iCnt] then
                      MessageBox('Fehler: neues Object wurde erstellt');

                      </pre>

                      gruß Hage

                      Comment


                      • #12
                        Hagen, Du hast recht. <br>ChangeSeriesType ist wirklich als ChangeSeriesType(Var ASeries:TChartSeries;NewType:TChartSeriesClass); deklariert. <br>
                        Deine Erklärung klingt absolut plausibel, und die Meldung kommt nach jedem Aufruf. Wobei ich auch zugeben muß, daß ich später gar nicht mehr daran gedacht habe in die Deklaration zu schauen

                        Comment


                        • #13
                          Hallo,<br>da stellt sich doch glatt die Frage, ob man die Series überhaupt über Stroeme verwalten muß. Günstiger wäre es dann gleich über Chart.Series zu gehen.<br>Jens Schuman

                          Comment


                          • #14
                            Wieso, er braucht doch nur Deinen Code verwenden. Anstatt mit einer temporären Variable muss er halt mit dem Array[] Eintrag arbeiten.<br>
                            Allerdings triff Frank garkeine Schuld, sondern dem Coder der TChart Komponente. <b>Es gilt als heiliges Gebot der programmierung, das der Aufrufer einer funktion für die Alloziereung und Deallozierung aller benötigter Objecte verantwortlich ist !</b>. Wir sehen nun wohin das führt wenn sich daran im Design nicht gehalten wird.<br>

                            Gruß hage

                            Comment

                            Working...
                            X