Autor Beitrag
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19346
Erhaltene Danke: 1754

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 20.02.09 19:31 
Naja, du reagierst ja darauf, dass Daten verfügbar sind, wenn ich mich richtig erinnere, oder? Weil anders geht es ja nicht. Und dann liest du ja nur was an Daten vorhanden ist.
Allerdings musst du auch das ganze Programm daran ausrichten, dass ereignisgesteuert Daten ankommen.
Jens Hartmann Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120

XP
Delphi
BeitragVerfasst: Fr 20.02.09 19:36 
Ja, aber wie gesagt, es kann ja nicht an der Hardware liegen,
In das Memo wird ja auch super schnell geschreiben,

Ich sag mal so 2 Datensätze pro Sekunde.

Und wie geagt, mit Delay(3000) geht es ja ab Datensatz3 super gut.

Nur mit Delay(3000), das ist ja keine Lösung. Mein Programm würde nie so arbeiten können, und die Daten sind ja auch viel schneller.

Außerdem, wie du schon gesagt hast, reagiere ich ja darauf, das ich Daten habe.

Hier mal ein Ausdruck vom Memo
Einloggen, um Attachments anzusehen!
Jens Hartmann Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120

XP
Delphi
BeitragVerfasst: Fr 20.02.09 20:59 
Habe die Anweisung zum Sprung in die Klasse Parsen, jetzt in einer Procedure verlegt. Damit habe ich zumindestens jetzt erreicht, das die Daten im StringGrid angezeigt werden.

Leider wird jedoch zwischendurch schon mal ein Datensatz doppelt oder dreifach ins Grid eingetragen.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
{Datenübernahme in StringGrid}
procedure TForm1.DatenverarbeitungVSTMB256plus;
var
  ParserTreeView     :TMyBaseParser;
begin
  ParserTreeView := TMyParserMB256plus.Create;
  ParserTreeView.Parse(DataMB256plus);
  TreeViewResult(ParserTreeView);
  ParserTreeView.Free;
end;
Einloggen, um Attachments anzusehen!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 20.02.09 22:47 
Wozu muss der Parser ständig neu erzeugt werden?

Warum keine Ressourcen-SCchutz-Blöcke?

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Jens Hartmann Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120

XP
Delphi
BeitragVerfasst: Fr 20.02.09 23:14 
Über die Klasse Parser, wandel ich meine Datensatz so um wie ich gerne hätte. Ich passe den Datensatz so an, das er in die entsprechenden Zellen im Grid eingetragen wird.

siehe mein Thread bei DP

www.delphipraxis.net...lich+darstellen.html


Hier mal das aktuelle Unit, welches zum großen Teil Jaenicke zu verdanken ist.
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
unit VSTUtils;

interface

uses
  Windows, SysUtils;

type
  TMyDataEntry = record

    LfdNr, Datum, Uhrzeit, Ereignis, Teilnehmer, Bereich : String;
  end;

  TMyBaseParser = class
  private
    Data: String;
    DataPointer: Integer;
    function OemToAnsi(const OemStr: string): string;
    procedure SkipSpaces;
    procedure SkipTrash;
    function GetTextLength(UpToLineEnd: Boolean): Integer;
    function ReadLine: String;
  public
    Entries: array of TMyDataEntry;
    procedure Parse(Text: String); virtual; abstract;
  end;

  TMyParserMB256plus = class(TMyBaseParser)
  private
  public
    procedure Parse(Text: String); override;
  end;

var
Zähler : integer;

implementation

{ TMySimpleBaseParser }

function TMyBaseParser.OemToAnsi(const OemStr: string): string;
begin
  SetLength(Result, Length(OemStr));
  if Length(Result) > 0 then
    OemToCharBuff(PChar(OemStr), PChar(Result), Length(Result));
end;

procedure TMyBaseParser.SkipSpaces;
begin
  while (DataPointer < Length(Data)) and (Data[DataPointer] = ' ') do
    Inc(DataPointer);
end;

procedure TMyBaseParser.SkipTrash;
begin
  while (DataPointer < Length(Data)) and (Data[DataPointer] in [#13, #10, #32]) do
    Inc(DataPointer);
end;

function TMyBaseParser.GetTextLength(UpToLineEnd: Boolean): Integer;

  function IsTerminatingChar(CharIndex: Integer): Boolean;
  begin
    if UpToLineEnd then
      Result := Data[CharIndex] in [#13, #10]
    else
      Result := Data[CharIndex] in [#13, #10, #32];
  end;

var
  CurPointer: Integer;
begin
  CurPointer := DataPointer;

  while (CurPointer <= Length(Data)) and not IsTerminatingChar(CurPointer) do
    Inc(CurPointer);

  Result := CurPointer - DataPointer;
end;

function TMyBaseParser.ReadLine: String;
var
  TextLen: Integer;
begin
  TextLen := GetTextLength(True);
  Result := Copy(Data, DataPointer, TextLen);
  DataPointer := DataPointer + TextLen;
  SkipTrash;
end;

{ TMyParserMB256plus }

procedure TMyParserMB256plus.Parse(Text: String);
var
  CurEntry  : ^TMyDataEntry;
  CurLine   : String;
  TempDatum : String;
  Temp1     : String;
  Temp2     : String;

begin
  Data := Text;
  DataPointer := 1;
  SetLength(Entries, 0);
  SkipTrash;
  while DataPointer < Length(Data) do
  begin
    SetLength(Entries, Length(Entries) + 1);
    CurEntry := @Entries[High(Entries)];

{Indexbehandlungsroutine}
    CurLine := ReadLine;
    if Pos('Ereignis:', CurLine) = 1 then
      begin
        Delete(CurLine, 1, 10);
        CurEntry.LfdNr := CurLine;
        CurLine := ReadLine;
      end;

{Datum & Uhrzeitbehandlungsroutine}
    if Pos('Datum:', CurLine) = 1 then
      begin
        TempDatum := CurLine;
        Delete(CurLine, 1, 7);
        Delete(CurLine, 11, 19);
        CurEntry.Datum := CurLine;
        CurLine := TempDatum;
        Delete(Curline,1, 28);
        CurEntry.Uhrzeit := Curline;
        {Ende Datumseintrag}
    end;

{Ereignisbehandlungsroutine}
        CurEntry.Ereignis := ReadLine;
        CurLine := ReadLine;
      if Pos('Hauptbereich:', CurLine) <> 1 then
        begin
          if Pos('AP', CurLine)
          or Pos('IE', CurLine)
          or Pos('Makro', CurLine)
          or Pos('Modem', CurLine)= 1 then
            begin
              CurEntry.Teilnehmer := CurLine;
              CurEntry.Bereich := ReadLine;
            end;
        end
      else
        begin
          CurEntry.Bereich := CurLine;
        end;
  end;
end;
end.




Zitat:
Ben hat geschrieben

Warum keine Ressourcen-SCchutz-Blöcke?



Was bedeutet das?????
:nixweiss:

[EDIT] Die drei Datensätze die immer gleich sind, sind aber direkt auch 2 fehlende. siehe Bild im Anhang
Einloggen, um Attachments anzusehen!
Jens Hartmann Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120

XP
Delphi
BeitragVerfasst: Sa 21.02.09 14:59 
So, habe jetzt mal den ganzen Tag Daten lesen lassen, funktioniert super, und wird auch alles eingetragen.
Mein Problem, liegt also somit woanders, und zwar, wenn ich länger keine Verbindung zur Hardware hatte, gibt es in der einen gewissen Puffer.

Dieser wird sofort Übergeben und damit hat meine Programm ein Problem, sobald der Puffer leer ist, und nur noch die Normalen Daten kommen, werden diese sauber eingefüllt. Im Anhang ist ein Bild mit so einem Anfangspuffer.

Habe ich eine Möglichkeit, das irgendwie zu lösen, Ich weiß ja jetzt auch nicht, ob es eventuell Möglich, jenachdem was da gerade an der Hardwáre passiert, wie dann die Daten kommen. Es kann ja sein, nur das kann ich halt an meiner Testanlage nicht prüfen, das es bei großen Systemen, je nach Datenaufkommen, auch schon mal zu diesem Problem kommen kann.

Mein Programm macht ja folgendes, es ließt den Puffer der Anlage, und Übergibt den an die Var. Buffer. Die Variable Buffer wird verarbeitet und anschließend wird erneut der Puffer der Zentrale ausgelesen, Auch dieser kann ja unterumständen schon wieder mehr als einen Datensatz haben.
Einloggen, um Attachments anzusehen!
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 21.02.09 15:44 
So wie dein Beispiel-Screenshot aussieht, scheint er neue Datensätze immer mit #13#10 zu trennen. Deine Prüfung, ob also ein Datensatz vorliegt, könnte daher so aussehen, dass Du auf das Vorhandensein eines Zeilenumbruchs prüfst. und nicht nur einen Datensatz mit einmal liest, sondern solange neue Datensätze erwartest, wie der Puffer noch einen Zeilenumbruch enthält.

d.h. du schneidest Dir von deinem Puffer immer den Anfang ab (wenn da ein Datensatz steht) und verarbeitest diesen Datensatz. Steht im Puffer danach noch ein Datensatz, verarbeitest Du diesen auch gleich (ohne Pause). Wenn jedoch kein vollständiger Datensatz mehr im Puffer steht, wartest Du solange, bis dies wieder der Fall ist.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Jens Hartmann Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120

XP
Delphi
BeitragVerfasst: Sa 21.02.09 16:02 
Das mache ich ja eigendlich mit der Funktion

ausblenden Delphi-Quelltext
1:
2:
3:
if Buffer[I] = #13 then
   if Buffer[I+2] = #13 then
      begin
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 21.02.09 16:42 
Im Grunde brauchst Du etwa folgenden Aufbau:

Datenquelle --> Lese-Puffer --> Datensatz-Erkennung --> Datensatz-Liste --> Datensatz-Anzeige (Verarbeitung) --> GUI

Dieser Ansatz läuft dann sogar Thread-Basiert und man kann sogar ohne den Main-Thread großartig auszulasten, Ereignisse "live" anzeigen.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
Jens Hartmann Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120

XP
Delphi
BeitragVerfasst: Sa 21.02.09 17:00 
Ja, aber meiner Ansicht nach mache ich das doch schon so, oder ich verstehe, deinen Ansatz nicht.

Daten von der COM-Schnittstelle lesen...
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var
  Daten          : String;
begin
  ComPort1.ReadStr(Daten, Count);
  Buffer:=Buffer+Daten;
  Bufferverarbeitung;
end;


Datensatz erkennen, Zeilenweise für TXT-Datei und Memo und Satzweise für Grid oder ListView
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
Procedure TForm1.Bufferverarbeitung;
Var
     I                  :Integer;
     Laenge             :Integer;
     ID                 :String;
begin
Laenge:=Length(Buffer);
I:=1;
while I < Laenge+1 do
                begin
                Zeile:=Zeile+Buffer[I];
                DataMB256plus:=DataMB256plus+Buffer[I];

                          if Buffer[I] = #13 then
                            if Buffer[I+2] = #13 then
                            begin
                            DataMB256plus := StringReplace(DataMB256plus, #154, 'Ü', [rfReplaceAll]);
                            DataMB256plus := trim(StringReplace(DataMB256plus, #$D,  '',  [rfReplaceAll]));
                            DataMB256plus:= StringReplace(DataMB256plus, #129, 'ü', [rfReplaceAll]);
                            DataMB256plus := trim(StringReplace(DataMB256plus, #132, 'ä', [rfReplaceAll]));
                            DataMB256plus := StringReplace(DataMB256plus, #142, 'Ä', [rfReplaceAll]);
                            DataMB256plus := StringReplace(DataMB256plus, #148, 'ö', [rfReplaceAll]);
                            DataMB256plus := StringReplace(DataMB256plus, #153, 'Ö', [rfReplaceAll]);
                            DataMB256plus := StringReplace(DataMB256plus, #154, 'Ü', [rfReplaceAll]);
                            DataMB256plus := StringReplace(DataMB256plus, #10#13, ' ', [rfReplaceAll]);

                            DatenverarbeitungVSTMB256plus;  //Sprung in Procedure
                            DataMB256plus := '';
                            end;

                IF Buffer[I] =#13 then
                  begin

                    case RGZentralentyp.ItemIndex of
                      0 : DatenverarbeitungMB24;
                      1 : DatenverarbeitungMB48;
                      2 : DatenverarbeitungMB100;
                      3 : DatenverarbeitungMB256;
                      4 : DatenverarbeitungUEZ2000;
                      5 : DatenverarbeitungBMC1024;
                    end;
                end;
                INC(I);
                end;

Buffer:='';
end;


Hierbei ist die Case-Anweisung die Verarbeitung Zeilenweise und die erste IF-Abfrage die Verarbeitung Satzweise

Verarbeitung Zeilenweise um die Anzeige Memo zu realiseren und das Speichern als TXT Datei
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
procedure TForm1.DatenverarbeitungMB256;
Var
  Datum              :String;
  Jahr               :String;
  Monat              :String;
  Sicherung          :String;
  Übergabe           :Integer;
  SL                 :TStringList;
  I                  :Integer;
  IA                 :Integer;
  IB                 :Integer;
  IC                 :Integer;
  ID                 :Integer;
  N                  :Integer;
begin
  Datum := DatetoStr(Date);
  Jahr := FormatDateTime('yyyy',strtodatetime(Datum));
  Monat := FormatDateTime('mmmm',strtodatetime(Datum));
  CreateDir('..\Daten\');
  CreateDir('..\Daten\'+Jahr);
  CreateDir('..\Daten\'+Jahr+'\'+Monat);

  sl := TStringList.Create;
  try
    MMUEZ2000.Lines.Add(Zeile);
    sl.AddStrings(MMUEZ2000.Lines);
    for i := 0 to sl.Count -1 do
      begin
        sl[i] := trim(StringReplace(sl[i], #$D,  '',  [rfReplaceAll]));
        sl[i] := StringReplace(sl[i], #129, 'ü', [rfReplaceAll]);
        sl[i] := trim(StringReplace(sl[i], #132, 'ä', [rfReplaceAll]));
        sl[i] := StringReplace(sl[i], #142, 'Ä', [rfReplaceAll]);
        sl[i] := StringReplace(sl[i], #148, 'ö', [rfReplaceAll]);
        sl[i] := StringReplace(sl[i], #153, 'Ö', [rfReplaceAll]);
        sl[i] := StringReplace(sl[i], #154, 'Ü', [rfReplaceAll]);
        sl[i] := StringReplace(sl[i], #10#13, ' ', [rfReplaceAll]);

      if sl[i] <> '' then
          Zeile:='';
          Memo.Lines.Append(SL[I]);
          Speichermemo.Lines.Append(SL[I]);
      end;
      MMUEZ2000.Clear;
    sl.Free;
  finally

  end;
  Zeile:='';
  Sicherung := ('..\Daten\'+Jahr+'\'+Monat+'\'+Datum+'.txt');
  Speichermemo.Lines.SaveToFile(Sicherung);
  Label1.Caption := Sicherung;
end;


Die Verarbeitung des kompletten Satzes wird dann durch die Klasse Parsen ausgeführt.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
{Datenübernahme in StringGrid}
procedure TForm1.DatenverarbeitungVSTMB256plus;
var
  ParserTreeView     :TMyBaseParser;
begin
  ParserTreeView := TMyParserMB256plus.Create;
  ParserTreeView.Parse(DataMB256plus);            //Sprung in die Klasse Parsen, habe ich weiter oben komplett gezeigt
  TreeViewResult(ParserTreeView);
  ParserTreeView.Free;
end;


Die Übergabe dann an das String Grid über TreeViewResult
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
{Datensatzverarbeitung}
procedure TForm1.TreeViewResult(ParserTreeView: TMyBaseParser);
var
  i: Integer;
  Temp1 : String;
  Temp2 : String;
  Temp3 : String;
  Temp4 : String;
  Temp5 : String;
  Temp6 : String;
begin
  for i := 0 to High(ParserTreeView.Entries) do
  begin
  Temp1 := ParserTreeView.Entries[0].LfdNr;
  Temp2 := ParserTreeView.Entries[0].Datum;
  Temp3 := ParserTreeView.Entries[0].Uhrzeit;
  Temp4 := ParserTreeView.Entries[0].Ereignis;
  Temp5 := ParserTreeView.Entries[0].Teilnehmer;
  Temp6 := ParserTreeView.Entries[0].Bereich;

      RCount := RCount+1;
      SGMB256plus.RowCount := RCount+1;
      SGMB256plus.Cells[0, RCount] := Temp1;

      SGMB256plus.Cells[1, RCount] := Temp2;

      SGMB256plus.Cells[2, RCount] := Temp3;

      SGMB256plus.Cells[3, RCount] := Temp4;

      SGMB256plus.Cells[4, RCount] := Temp5;

      SGMB256plus.Cells[5, RCount] := Temp6;

  Application.ProcessMessages;
  end;
end;


Damit erfülle ich doch komplett den Ablauf den du meinst, oder versteh ich da was nicht?

Gruß

Jens
Übrigens, zwischendurch nochmal ein großes Dankeschön an all Eure Bemühungen.