Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Probleme beim Umstellen von Array zu Stringlist (https://www.delphipraxis.net/140231-probleme-beim-umstellen-von-array-zu-stringlist.html)

BAMatze 14. Sep 2009 08:28


Probleme beim Umstellen von Array zu Stringlist
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo aus einem mir noch nicht nachvollziehbaren Grund bremst sich meine eigene Klasse nach der Umstellung der Klasse von einem festen Array auf ein TStringList, komplett aus, so dass man das Programm nicht mehr benutzen kann (Cursor ändert sich durch Windows in crHourGlass nicht durch das Programm)- passiert gleich beim Starten.

Hier mal die Klasse:

Delphi-Quellcode:
Type TOszilloskopKanal = class
 
  private
    FsLDaten: TStringList; // <-- Hier war vorher ein array of double
    FadExtremaWert: array[0..4] of double;
    FdMaxWert, FdMinWert: double;
    FbAbfragen: boolean;
    FiIdent: integer;
    FsName: string;
    FKanalColor, FBackgroundColor: TColor;
    FOnChangeEingang: TOnChangeEingangEvent;
    procedure SetYWert(dWert: double);
    procedure SetName(sWert: string);
    procedure SetKanalFarbe(cWert: TColor);
    function GetYWert(Index: integer): double;
    function GetName: string;
    function GetKanalFarbe: TColor;
    function GetIdent: integer;
    function GetCountEingangswerte: integer;
    function GetMax: double;
    function GetMin: double;
  protected
    procedure doChangeEingang;
  published
    property OnChangeEingang: TOnChangeEingangEvent read FOnChangeEingang write FOnChangeEingang;
  public
    constructor create(Number: integer); reintroduce;
    destructor destroy; override;
    property EingangY: double write SetYWert;
    property IdentNumber: integer read GetIdent;
    property AusgangY[Index: integer]: double read GetYWert;
    property Name: string read GetName write SetName;
    property KanalColor: TColor read GetKanalFarbe write SetKanalFarbe;
    property CountEingangsWerte: integer read GetCountEingangswerte;
    property Max: double read GetMax;
    property Min: double read GetMin;
end;

implementation

constructor TOszilloskopKanal.Create(Number: integer);
var i: integer;
begin
  inherited create;
  FiIdent := Number;
  FsName := 'Signal '+ inttostr(Number);
  FKanalColor := clblue;
  FsLDaten := TStringList.Create;
  FsLDaten.Add('0');
  FdMaxWert := 0;
  FdMinWert := 0;
end;

destructor TOszilloskopKanal.Destroy;
begin
  FsLDaten.Free;
  inherited destroy;
end;

// Es werden immer nur die letzen Werte gesetzt
procedure TOszilloskopKanal.SetYWert(dWert: double);
begin
  FsLDaten.Add(floattostr(dWert));
  //Extremas überprüfen und ggf neu setzen
  if dWert > FdMaxWert then FdMaxWert := dWert;
  if dWert < FdMinWert then FdMinWert := dWert;
  doChangeEingang;
end;

// Getter und Setter wurden entfernt, um den Text hier möglichst kurz zu halten

procedure TOszilloskopKanal.doChangeEingang;
begin
  if Assigned(FOnChangeEingang) then FOnChangeEingang(Self, FiIdent);
end;

end.
Da ich eventuell noch vermute, dass die übergeordnete Klasse der Verursacher des Problems ist, hier noch mal auszüge, die die Schnittstellen in der höheren Klasse darstellen:

Delphi-Quellcode:
constructor TOszilloskop.create(AOwner: TComponent; CountChannel: Integer);
var i, j: integer;
begin
  inherited create(AOwner);
  Controlstyle := Controlstyle - [csAcceptsControls]; // Der Componente wird nicht erlaubt
                                                      // andere Componenten aufzunehmen,
                                                      // als die, die durch den Programmierer
                                                      // hier einprogrammiert werden.
  //Initialisierung
  SetLength(FSignal, CountChannel);
  for i := 0 to CountChannel-1 do
    begin
      FSignal[i] := TOszilloskopKanal.create(i+1);
      j := i;
      if j >= 5 then repeat j := j-5; until (j < 5);
      case j of
      0 : FSignal[i].KanalColor := clmaroon;
      1 : FSignal[i].KanalColor := clblue;
      2 : FSignal[i].KanalColor := clgreen;
      3 : FSignal[i].KanalColor := clyellow;
      4 : FSignal[i].KanalColor := clred;
      else FSignal[i].KanalColor := clwhite;
      end;
      FSignal[0].OnChangeEingang := FOnSignalEingang;

  FDarstellungsBitmap := TBitmap.Create;
  FDarstellungsBitmap.Width := FiDisplayWidth;
  FDarstellungsBitmap.Height := FiDisplayHeight;

end;

destructor TOszilloskop.Destroy;
var i: integer;
begin
  // Freigabe
  for i := 0 to Length(FSignal)-1 do FSignal[i].Free;
  SetLength(FSignal,0);
  inherited destroy;
end;

// Wenn im Eingang ein Signal anliegt, wird die höhere Klasse darüber informiert und (soll) das Bild für den Kanal neu zeichnen!!
procedure TOszilloskop.FOnSignalEingang(Sender: TObject; const IdentNumber: integer);
var i: integer;
    TempBitmap: TBitmap;
// zu jedem FSignal gehört ein FBitmap, in welchem der Graph, welcher im FSignal gespeichert sein soll, darstellt wird.
begin
  GetRange;
  Maske_erstellen;
  TempBitmap := TBitmap.Create;
  TempBitmap.Height := FiDisplayHeight;
  if FSignal[IdentNumber].CountEingangsWerte < FiDisplayWidth then
    begin
      TempBitmap.Width := FSignal[IdentNumber].CountEingangsWerte;
      TempBitmap.Canvas.CopyRect(rect(0,0,FSignal[IdentNumber].CountEingangsWerte-1,FiDisplayHeight),FBitmap[IdentNumber-1].Canvas,rect(0,0,FSignal[IdentNumber].CountEingangsWerte-1,FiDisplayHeight));
      //TempBitmap.Assign(FBitmap[IdentNumber-1]);
      TempBitmap.Canvas.Pen.Color := FCtransparentColor;
      TempBitmap.Canvas.MoveTo(TempBitmap.Width, 0);
      TempBitmap.Canvas.LineTo(TempBitmap.Width, FiDisplayHeight);
      TempBitmap.Canvas.Pen.Color := FSignal[IdentNumber-1].KanalColor;
      TempBitmap.Canvas.MoveTo(TempBitmap.Width-1, FiDisplayHeight-5 - round((FSignal[IdentNumber-1].AusgangY[FSignal[IdentNumber-1].CountEingangswerte-2]- FdDisplayMin)*FdDisplayStrech));
      TempBitmap.Canvas.LineTo(TempBitmap.Width, FiDisplayHeight-5 - round((FSignal[IdentNumber-1].AusgangY[FSignal[IdentNumber-1].CountEingangswerte-1]- FdDisplayMin)*FdDisplayStrech));
      FBitmap[IdentNumber].Width := FSignal[IdentNumber].CountEingangsWerte;
      FBitmap[IdentNumber].Assign(TempBitmap);
    end
  else
    begin
      TempBitmap.Width := FiDisplayWidth;
    end;
  TempBitmap.Free;
  for I := 0 to Length(FSignal)-1 do InitBitmap(i+1);
  FPB_Display.Refresh;
end;
Sieht jemand eventuell, wo der Fehler liegt?
Habe zum besseren Verständnis mal das Projekt angehängt.

Vielen Dank
BAMatze

Klaus01 14. Sep 2009 08:56

Re: Probleme beim Umstellen von Array zu Stringlist
 
Guten Morgen,

ich wieß nicht ob das Problem daran liegt,
aber warum nutzt Du zum (zwischen)speichern von double
Werten eine StringList?
Wenn Du die Werte zeichnen willst, musst Du sie auch wieder
konvertieren oder?

Wäre eine TList mit double Einträgen hier nicht sinnvoller?


[edit]
Delphi-Quellcode:
procedure TForm1.FormShow(Sender: TObject);
begin
  ControlerBoard := TControlerBoard.create;
  ControlerBoard.Initialising;
  sleep(4000);
end;
Verzögert den Programmstart um 4 Sekunden.

Grüße
Klaus

BAMatze 14. Sep 2009 09:14

Re: Probleme beim Umstellen von Array zu Stringlist
 
Hallo @Klaus das mit der TList schaue ich mir gleich mal an, kannte ich einfach noch nicht. Ziel für mich ist es, dass ich vom Start des Programmes bis zur Terminierung alle Daten im Speicher behalte. Die bisherige Lösung über ein Array (dieses Array hatte die Größe der Breite vom Darstellungsbildschirm) führte zum Datenverlust aller Werte außerhalb des Darstellungsbildschirmes.
Bei der Verwendung von Array muss ich mich außerdem immer um die Vergrößerung des Feldes selber kümmern, was nachteilhaft ist, wie ich finde (ständig müssen Arrays erstellt, kopiert und bearbeitet werden) nachteilhaft ist, wenn ich bei einer Liste (wie z.B. TStringList) einfach nur ein Add ausführen muss.
Die Zeitverzögerung ist mir bewusst, die hat sich nur eingeschlichen, weil ich es aus einem großen Projekt zur einfacheren Bearbeitung ausgelagert hab. Aber daran liegt der Fehler nicht, da ich das bei mir über 10sek hab laufen lassen und nichts wirklich passierte. Die Nachrichtenschleife des Projektes arbeitet irgenwie nicht und das Programm läd (anscheinend) nicht fertig.

BAMatze

[Edit1] Der Fehler konnte insofern schon eingegrenzt werden, dass beim auskommentieren folgender Zeile in der Oberklasse:
Delphi-Quellcode:
procedure TOszilloskop.FOnSignalEingang(Sender: TObject; const IdentNumber: integer);
var i: integer;
    TempBitmap: TBitmap;
begin
  GetRange;
  Maske_erstellen;
  TempBitmap := TBitmap.Create;
  TempBitmap.Height := FiDisplayHeight;
  if FSignal[IdentNumber].CountEingangsWerte < FiDisplayWidth then
    begin
      TempBitmap.Width := FSignal[IdentNumber].CountEingangsWerte;
      TempBitmap.Canvas.CopyRect(rect(0,0,FSignal[IdentNumber].CountEingangsWerte-1,FiDisplayHeight),FBitmap[IdentNumber-1].Canvas,rect(0,0,FSignal[IdentNumber].CountEingangsWerte-1,FiDisplayHeight));
      //TempBitmap.Assign(FBitmap[IdentNumber-1]);
      TempBitmap.Canvas.Pen.Color := FCtransparentColor;
      TempBitmap.Canvas.MoveTo(TempBitmap.Width, 0);
      TempBitmap.Canvas.LineTo(TempBitmap.Width, FiDisplayHeight);
      TempBitmap.Canvas.Pen.Color := FSignal[IdentNumber-1].KanalColor;
      TempBitmap.Canvas.MoveTo(TempBitmap.Width-1, FiDisplayHeight-5 - round((FSignal[IdentNumber-1].AusgangY[FSignal[IdentNumber-1].CountEingangswerte-2]- FdDisplayMin)*FdDisplayStrech));
      TempBitmap.Canvas.LineTo(TempBitmap.Width, FiDisplayHeight-5 - round((FSignal[IdentNumber-1].AusgangY[FSignal[IdentNumber-1].CountEingangswerte-1]- FdDisplayMin)*FdDisplayStrech));
      FBitmap[IdentNumber].Width := FSignal[IdentNumber].CountEingangsWerte;
      FBitmap[IdentNumber].Assign(TempBitmap);
    end
  else
    begin
      TempBitmap.Width := FiDisplayWidth;
    end;
  TempBitmap.Free;
  for I := 0 to Length(FSignal)-1 do InitBitmap(i+1);
  //FPB_Display.Refresh; // <-- Hier scheint es ein Problem zu geben. Wenn auskommentiert, ist Problem gelöst aber es gibt keine Darstellung (was natürlich logisch ist, weil die Paintbox nicht gezeichnet wird!)
end;
[/Edit]
[Edit2] Fehler steckt in Folgendem Quellcode, was ich aber nicht verstehe, da dieser bisher noch nie Probleme gemacht hat:
Delphi-Quellcode:
//Quellcodeteil aus der NewPaint-procedure in Oberklasse
for i := 0 to Length(FCB_Layer)-1 do
    begin
      if FCB_Layer[i].Checked then transparentBlt(FDarstellungsBitmap.Canvas.Handle, 0, 0, FDarstellungsBitmap.width, FDarstellungsBitmap.Height,
      Fbitmap[i+1].Canvas.Handle, 0, 0, Fbitmap[i+1].Width, Fbitmap[i+1].Height, FCtransparentColor);
    end;
[/Edit]

Klaus01 14. Sep 2009 09:20

Re: Probleme beim Umstellen von Array zu Stringlist
 
Hallo BAMatze,

habe gerade dein Edit gelesen.

Bei mir startet das Projekt ohne Verzögerung wenn ich die 4 Sekunden
Sleep auskommentiere.

Ob es daran liegt, das hier das Programm auf einem DualCore Rechner läuft?

Grüße
Klaus

BAMatze 14. Sep 2009 09:24

Re: Probleme beim Umstellen von Array zu Stringlist
 
Läuft bei dir der Darstellungsbildschirm auf der Form2? kannst du auf diesen wechseln? bei mir freezt das nämlich alles ein :(

[Edit] auch ohne das sleep(4000); ändert sich bei mir leider nichts, muss wohl an dem DualCoreRehner liegen.[/Edit]

Klaus01 14. Sep 2009 09:30

Re: Probleme beim Umstellen von Array zu Stringlist
 
.. was ich bei mir noch auskommentiert habe ist:
Delphi-Quellcode:
 //Application.MainFormOnTaskbar := True;
Ansonsten ließ sich das Programm nicht kompilieren.

Auf die Form2 (die mit dem Fadenkreuz) kann ich ohne Problem wechseln.

Zitat:

[Edit2] Fehler steckt in Folgendem Quellcode, was ich aber nicht verstehe, da dieser bisher noch nie Probleme gemacht hat:
Greifen mehrere Threads auf die "Paintbox" zu?
Blockieren diese eventuell den Refresh?

Grüße
Klaus

Medium 14. Sep 2009 09:38

Re: Probleme beim Umstellen von Array zu Stringlist
 
Zitat:

Zitat von BAMatze
Ziel für mich ist es, dass ich vom Start des Programmes bis zur Terminierung alle Daten im Speicher behalte.

Wie hoch ist die Frequenz mit der du neue Werte bekommst? Ich frage, weil es dann schon mächtig fix passieren kann dass du ein extrem unhandliches Listchen vor dir hast. Konzeptionell würde ich hier eher vorschlagen wirklich nur die Daten die zur Anzeige gebraucht werden vorzuhalten, und alte Daten blockweise in ein File zu werfen.

Das könnte z.B. so ausschauen, dass du ein Array mit 2*Bildbreite nimmst, und sobald du [Bildbreite] neue Daten hinten angepappt hast, schreibst du die davor stehenden [Bildbreite] Daten weg. Ausserdem ist es mit einem Array bei sequenziellen Datenströmen nicht unbedingt ein ewiges herumkopiere, solange du eines fester Länge hast. Stichwort: Ringpuffer.

BAMatze 14. Sep 2009 10:11

Re: Probleme beim Umstellen von Array zu Stringlist
 
Also ich lasse derzeit über einen separaten Thread Daten von einem Analogen Eingang einer ControlerBoardkarte im 50ms-Takt schreiben. Habe das in meinem letzten Thread wie folgt gelöst und es funktioniert auch jetzt noch, wenn ich die Forschleife in der NewPaint-Procedure auskommentiere.

[Edit] Der Hinweis mit dem Thread war glaube ich das richtig. Der Thread sieht NOCH wie folgt aus:

Thread-Quellcode (Auszug):
Delphi-Quellcode:
procedure TControlCardControlThread.Execute;
var c, iIndex: integer;
    //TempTisch: TTischInfo;
    //Punkte, Geschwindigkeiten, Beschleunigungen: array[1..3] of double = [0,0,0];
   
begin
  repeat
    c := GetTickCount;

    //bReaktion := boolKombination(4);
 
    Synchronize(Sync);
 
    c := {interval}50 - (GetTickCount - c);
    if c > 0 then Sleep(c);
  until Terminated;
end;

procedure TControlCardControlThread.Sync;
var
  i: Integer;
begin
  Form3.ProgressBar1.Position := ReadanalogChannel(1);
  Form3.ProgressBar2.Position := ReadanalogChannel(2);
  for i := 1 to 5 do
    begin
      if ReaddigitalChannel(i) then
        begin
          case i of
          1: Form3.CheckBox9.Checked := true;
          2: Form3.CheckBox10.Checked := true;
          3: Form3.CheckBox11.Checked := true;
          4: Form3.CheckBox12.Checked := true;
          5: Form3.CheckBox13.Checked := true;
          end;
        end
      else
        begin
          case i of
          1: Form3.CheckBox9.Checked := false;
          2: Form3.CheckBox10.Checked := false;
          3: Form3.CheckBox11.Checked := false;
          4: Form3.CheckBox12.Checked := false;
          5: Form3.CheckBox13.Checked := false;
          end;
        end;

    end;
  Form2.EingangsSignal[0] := ReadanalogChannel(1);
  if ReadDigitalChannel(5) then Form2.EingangsSignal[1] := 256
  else Form2.EingangsSignal[1] := 0;
end;
Greife dämlicher Weise direkt auf visuelle Komponenten zu, was ja nicht wirklich glücklich ist und (verständlicher Weise) zu Fehlern führt. Wenn ich die Zugriffe auf die visuellen Komponenten auskommentiere, funktioniert alles (auch die NewPaint-Procedure) :wall: . Werde ich jetzt mal umbauen.
[/Edit]

@Medium ist ein guter Hinweis, das mit dem Ringpuffer, werde ich mich jetzt wohl doch mal mit beschäfftigen müssen und dann wie du vorschlägst die nicht benötigten Daten in eine File schreiben.
Aber hab da noch eine Frage, wenn ich bis zum Anfang zurück scrollen will, dauert das ja sicherlich mit dem Laden der Daten etwas oder ist die Ladezeit (ca 500-600 Punkte werden dargestellt) maginal/trivial?

Medium 14. Sep 2009 11:30

Re: Probleme beim Umstellen von Array zu Stringlist
 
Wenn du die Werte binär wegspeicherst (also bloß kein Textfile und FloatToStr oder so Gelümmel ;)), kannst du die benötigte Position im FileStream nachher recht fix mit Seek(Pos*SizeOf(WerteTyp)) anspringen. Das Auslesen selber ist dann eher nur noch eine Formalie - wichtig ist nur dass du nicht aufwendig vorher rumsuchen musst.

Du musst evtl. mit der Größe des Teilpuffers der weggespeichert wird etwas herumspielen, bis du eine Größe hast die keine Ruckler verursacht - bei 50ms Updatezeiten könnte man das evtl. ab und an merken. Ich denke mal Blockgrößen von 1024 bis 4096 Bytes sollten im geeigneten Rahmen liegen. (Es müssen ja nicht [Bildbreite] Werte sein. Wenn dein Puffer [Blocksize]+[Bildbreite] ist, nimmst du den hinteren Teil zum Zeichnen, und nach [Blocksize] Inputs den vorderen Teil wegschreiben, bevor dessen erstes Element wieder überschrieben wird.)

BAMatze 14. Sep 2009 12:49

Re: Probleme beim Umstellen von Array zu Stringlist
 
Cool schonmal ein paar Informationen, die mir die Arbeit erleichtern werden. Habe ebend über eine Art kleine DB nachgedacht, wo ich nen Index als Position verwende (ala 1, 2,3; 2, 1,4 und so weiter (1. Zahl Index 2. Zahl doubleWert) so dass ich über die Bildlaufleiste Feststellen kann, dass ich z.B. die Werte 300 - 799 laden muss. Aber hast recht kann natürlich auch über die Speicherposition dies direkt ansprechen.
Jetzt muss ich aber noch eine Nachlässigkeit zugeben, habe bisher immer alles in eine Textfile (ini oder txt) gespeichert, weil das immer das einfachste fßür mich war. Werde mich also erstmal mit binär-Dateien auseinandersetzen müssen. Denke aber mal Binärdatei wird sicherlich heißen Zahl in Dualcode (Basis 2) speichern.

BAMatze

[Edit] Die Datei braucht übrigens nur für den Zeitpunkt der Messung zur Verfügung zu stehen. Spätestens bei Beenden des Programms sollte alles aufgeräumt werden und die Daten können verworfen werden, da anhand des Graphen der Bediener entscheidet, ob alles seine Richtigkeit hatte. (Nur eine Ergänzung weil ich hier irgendwas mit einem Stream lese in der SuFu) Könnte man das in dem Fall auch in einen Stream packen? [/Edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:34 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz