| Autor |
Beitrag |
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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 
      
Beiträge: 120
XP
Delphi
|
Verfasst: 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 
      
Beiträge: 120
XP
Delphi
|
Verfasst: 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.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TForm1.DatenverarbeitungVSTMB256plus; var ParserTreeView :TMyBaseParser; begin ParserTreeView := TMyParserMB256plus.Create; ParserTreeView.Parse(DataMB256plus); TreeViewResult(ParserTreeView); ParserTreeView.Free; end; |
Einloggen, um Attachments anzusehen!
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 
      
Beiträge: 120
XP
Delphi
|
Verfasst: 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.
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
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;
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)];
CurLine := ReadLine; if Pos('Ereignis:', CurLine) = 1 then begin Delete(CurLine, 1, 10); CurEntry.LfdNr := CurLine; CurLine := ReadLine; end;
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; end;
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?????
[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 
      
Beiträge: 120
XP
Delphi
|
Verfasst: 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
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 
      
Beiträge: 120
XP
Delphi
|
Verfasst: Sa 21.02.09 16:02
Das mache ich ja eigendlich mit der Funktion
Delphi-Quelltext 1: 2: 3:
| if Buffer[I] = #13 then if Buffer[I+2] = #13 then begin |
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: 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 
      
Beiträge: 120
XP
Delphi
|
Verfasst: 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...
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
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; 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
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.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure TForm1.DatenverarbeitungVSTMB256plus; var ParserTreeView :TMyBaseParser; begin ParserTreeView := TMyParserMB256plus.Create; ParserTreeView.Parse(DataMB256plus); TreeViewResult(ParserTreeView); ParserTreeView.Free; end; |
Die Übergabe dann an das String Grid über TreeViewResult 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:
| 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.
|
|
|