![]() |
Re: StringGrid mit Daten füllen und farblich Darstellen
Das heißt also, das ich mich jetzt erstmal mit dem VirtualTreeView beschäftigen sollte.
Das werde ich jetzt erstmal machen, ich denke das ich da bestimmt auf Dich zukomme. Ich werde aber dann dazu einen neune Tread aufmachen, damit auch andere später die Fragen dazu finden und nutzten könne. Also danke schon mal bis bald. Gruß Jens |
Re: StringGrid mit Daten füllen und farblich Darstellen
Hallo Sebastian,
So ich habe mich jetzt mit dem VirtualTreeView beschäftig, und versuche jetzt da mal weiterzukommen. Als erstes habe ich mir deine Klasse Parsen kopiert und eine Klasse TreeViewParsen erstellt, um mir die vorhanden nicht zu zerstören. Das funktioniert auch genau so wie vorher mit Parsen. Jetzt habe ich versucht in meiner Buffer Verarbeitung von COM1 nur die aktuelle Zeile einlesen, um mir das öffnen der Datei zu sparen, und vorallem das immer wiederholte lesen der gesamten Datei. Also ist mein Ziel jetzt, Zeile lesen und im VirtualStringTree einzupflegen. Leider hänge ich schon an folgendem Punkt: Meine Zeile wird eingelesen und erhält auch den aktuellen Wert.
Delphi-Quellcode:
Wir hatten schon mal darüber gesprochen, das ich das mit StringReplaced lassen könnte, da diese Funktion in Parsen ja vorhanden ist. Leider funktiioniert das aber nicht.
Procedure TForm1.Bufferverarbeitung;
Var I :Integer; Laenge :Integer; ParserTreeView : TMyBaseParser; begin Laenge:=Length(Buffer); I:=1; while I < Laenge+1 do begin Zeile:=Zeile+Buffer[I]; IF Buffer[i] =#13 then begin ParserTreeView := TMyParserMB256plus.Create; ParserTreeView.Parse(Zeile); TreeViewResult(ParserTreeView); ParserTreeView.Free; case RGZentralentyp.ItemIndex of 0 : DatenverarbeitungMB24; 1 : DatenverarbeitungMB48; 2 : DatenverarbeitungMB100; 3 : DatenverarbeitungMB256; 4 : DatenverarbeitungUEZ2000; 5 : DatenverarbeitungBMC1024; end; end; INC(I); end; Buffer:=''; end; Wenn ich beim Debuggen in Liste überwachter Ausdrücke mir den Wert von Zeile ansehe, ist das soweit in Ordnung, das immer nur die aktuelle Zeile vorhanden ist. Natürlich mit den ganzen Steuerzeichen. Es wird dann auch die Klasse Parsen durchgeführt, und an folgendem Punkt überspringt dann mein Programm
Delphi-Quellcode:
Was mache ich falsch
procedure TMyParserMB256plus.Parse(Text: String);
var CurEntry: ^TMyDataEntry; CurLine: String; i1 : integer; i2 : integer; temp : String; begin Data := Text; DataPointer := 1; SetLength(Entries, 0); SkipTrash; CurLine := ReadLine; while DataPointer < Length(Data) do [b]//Hier bleibt mein Programm stehen und Überspringt die gesamte Zuweisung von Entries[/b] begin SetLength(Entries, Length(Entries) + 1); CurEntry := @Entries[High(Entries)]; Gruß Jens |
Re: StringGrid mit Daten füllen und farblich Darstellen
So funktioniert das auch nicht. Ich habe ja geschrieben: An Parse kannst du nur ganze Datensätze übergeben. Wenn du das nicht gewährleisten kannst, dann müsstest du das Parsen selbst zeilenweise aufbauen, d.h. eine Methode AddLine oder so basteln, die immer nur eine Zeile hinzufügt z.B.
Dann müsste jeweils der aktuelle Status, also an welcher Stelle des Parsens man ist gespeichert werden ODER so lange Zeilen hinzugefügt werden bis der aktuelle Eintrag komplett ist. Wo genau kommen denn die Daten an? Letztlich ließe sich das genau dort bereits verarbeiten ohne viele Zwischenschritte. Dafür könnte sich ein ![]() Beispiel: der Automat bleibt bei Buchstaben in dem entsprechenden Zustand und bei Zeichen #13 geht er in den nächsten Zustand über. Das ist praktisch die selbe Vorgehensweise wie bei einem Taschenrechner. Wenn man das erst richtig verstanden hat, dann ist das auch relativ einfach zu implementieren. Das Planen ist das größere Problem. ;-) |
Re: StringGrid mit Daten füllen und farblich Darstellen
Hallo Sebastian,
ich sitze jetzt schon den ganzen Nachmittag hiervor und vor ca. 5 Minuten, habe ich es jetzt aufjedenfall so weit, das ich alle Zeilen sauber und richtig auswerte. Ich denke nur nach deiner gerade gestellten antwort, das das wahrscheinlich total falsch ist, was ich gemacht habe. Hier meine Lösung:
Delphi-Quellcode:
und hier die Verarbeitung in ParserUtils:
Procedure TForm1.Bufferverarbeitung;
Var I :Integer; Laenge :Integer; Übergabe :String; ParserTreeView : TMyBaseParser; begin Laenge:=Length(Buffer); I:=1; while I < Laenge+1 do begin Zeile:=Zeile+Buffer[I]; IF Buffer[i] =#13 then begin Übergabe := Zeile; Übergabe := StringReplace(Übergabe, #154, 'Ü', [rfReplaceAll]); Übergabe := trim(StringReplace(Übergabe, #$D, '', [rfReplaceAll])); Übergabe:= StringReplace(Übergabe, #129, 'ü', [rfReplaceAll]); Übergabe := trim(StringReplace(Übergabe, #132, 'ä', [rfReplaceAll])); Übergabe := StringReplace(Übergabe, #142, 'Ä', [rfReplaceAll]); Übergabe := StringReplace(Übergabe, #148, 'ö', [rfReplaceAll]); Übergabe := StringReplace(Übergabe, #153, 'Ö', [rfReplaceAll]); Übergabe := StringReplace(Übergabe, #154, 'Ü', [rfReplaceAll]); Übergabe := StringReplace(Übergabe, #10#13, ' ', [rfReplaceAll]); ParserTreeView := TMyParserMB256plus.Create; ParserTreeView.Parse(Übergabe); TreeViewResult(ParserTreeView); ParserTreeView.Free; case RGZentralentyp.ItemIndex of 0 : DatenverarbeitungMB24; 1 : DatenverarbeitungMB48; 2 : DatenverarbeitungMB100; 3 : DatenverarbeitungMB256; 4 : DatenverarbeitungUEZ2000; 5 : DatenverarbeitungBMC1024; end; end; INC(I); end; Buffer:=''; end;
Delphi-Quellcode:
procedure TMyParserMB256plus.Parse(Text: String);
var CurEntry: ^TMyDataEntry; CurLine: String; i1 : integer; i2 : integer; temp : String; begin Data := Text; OemToAnsi(Data); DataPointer := 1; SetLength(Entries, 0); SkipTrash; CurLine := ReadLine; //while DataPointer = Length(Data) do //begin SetLength(Entries, Length(Entries) + 1); CurEntry := @Entries[High(Entries)]; {Indexbehandlungsroutine} if Pos('Ereignis:', CurLine) = 1 then begin Delete(CurLine, 1, 10); CurEntry.LfdNr := StrToInt(CurLine); CurLine := ReadLine; end; {Datum & Uhrzeitbehandlungsroutine} if Pos('Datum:', CurLine) = 1 then begin Temp := CurLine; Delete(CurLine, 1, 7); Delete(CurLine, 11, 19); CurEntry.Datum := CurLine; CurLine := Temp; Delete(Curline,1, 28); CurEntry.Uhrzeit := Curline; CurLine := ReadLine; end; {Ereignisbehandlungsroutine} if Pos('Ereignis:', CurLine) <> 1 then begin if Pos('Datum:', CurLine) <> 1 then begin if Pos('Extern', CurLine) or Pos('Intern', CurLine) or Pos('Unscharf', CurLine)= 1 then begin CurEntry.Ereignis := CurLine; CurLine := ReadLine; end; end; end; if Pos('Ereignis:', CurLine) <> 1 then begin if Pos('Datum:', CurLine) <> 1 then begin if Pos('AP', CurLine) or Pos('IE', CurLine) = 1 then begin CurEntry.Teilnehmer := CurLine; CurLine := ReadLine; end; end; end; if Pos('Ereignis:', CurLine) <> 1 then begin if Pos('Datum:', CurLine) <> 1 then begin if Pos('Hauptbereich:', CurLine) = 1 then begin CurEntry.Bereich := CurLine; CurLine := ReadLine; end; end; end; end; Die ankommenden Daten kommen von der COM Schnittstelle und werden so eingelesen:
Delphi-Quellcode:
Gruß Jens
procedure TForm1.ComPort1RxChar(Sender: TObject; Count: Integer);
var Daten: String; begin ComPort1.ReadStr(Daten, Count); Buffer:=Buffer+Daten; Bufferverarbeitung; end; |
Re: StringGrid mit Daten füllen und farblich Darstellen
Wenn die Daten immer diese Zeilenanfänge haben, dann ist das natürlich auch möglich das daran zu erkennen. In den Beispielen war das aber nicht immer so. Und sobald du eine Zeile ohne den Kontext nicht zuordnen kannst, kommst du so nicht weiter.
Wichtig ist dabei aber, dass du die Anzahl der Einträge nur erhöhen darfst, wenn auch tatsächlich der Anfang eines neuen Eintrags, also dessen erste Zeile, vorliegt. Denn sonst füllst du die Zeile immer in einen neuen Eintrag. Nebenbei sehe ich keinen Grund für eine globale Variable Buffer, das kannst du doch auch direkt an die entsprechende Verarbeitungsroutine (Bufferverarbeitung) als Parameter weiterleiten (es sei denn du willst jedesmal den kompletten Buffer wirklich durchlaufen). Globale Variablen sind zwar nicht per se schlecht, aber je mehr man sie benutzt, desto unübersichtlicher wird das Programm. Und man muss dann ganz genau dokumentieren wo in die Variablen geschrieben wird und wo sie wann benutzt werden (als Kommentar bei der Deklaration der Variablen z.B.). Übersichtlicher ist es, wenn man globale Variablen nur da benutzt, wo es nötig ist. // EDIT: Ich meinte das, wenn du nur die aktuelle Zeile verarbeitest, aber ich sehe gerade, dass du immer den kompletten Buffer neu analysiert. :gruebel: |
Re: StringGrid mit Daten füllen und farblich Darstellen
Das mit der Var. Buffer ist mir bekannt, habe ich allerdings noch als global, weil ich nicht wußte ob ich mal drauf zugreifen muss.
Ich brauche aber nur die Var. Zeile als Global und das werde ich somit ändern. Ich denke schon das ich das so machen kann, da jede neue Zeile mit einer neuen Ereignissnummer anfängt. Ich muss jetzt nur noch alle Möglichen Ereigniss in die If / Or Abfrage setzten (soviele sind es nicht) und denke mir dann, das ich die Daten an das VirtualStringTree übergeben kann. Ich muss doch eigendlich nur mit der ersten gelesenen Ereignisnummer anfangen, die Daten die da kommen weiter eintragen, und sollte eine weitere Ereignisnummer kommen den VirtualSringTree um eine weitere Zeile erweitern. Weiß nicht, aber denke mir das das so hinhauen könnte. Wenn diese Lösung hier nicht so gut ist, will ich es auch gerne anders Probieren. Wenn das so Funktioniert, braucht ich für andere Zentralentypen nur die entsprechenden If/OR Abfragen und das wär´s. Da die Datensätze bei anderen Zentralentypen anders aufgebaut sein können, muss ich eh, je nach Eingestelltem Zentraltyp das VirtualStringTree neu zeichnen. Gruß Jens |
Re: StringGrid mit Daten füllen und farblich Darstellen
Habe jetzt noch eine wenig ausprobiert,und bin leider doch nicht so weit.
Ich habe die entgegennahme jetzt direkt in die Verarbeitung der Schnittstellendaten eingepflegt. Habe jetzt mal Texte geändert und so, sieht dann so ein Datensatz aus. #$A#$D#$A'Ereignis: 6091'#$D#$A'Datum: 09.12.2008, Uhrzeit: 18:31:41'#$D#$A'Unscharf'#$D#$A'Hauptbereich: 001, Unterbereich: 000'#$D Ergebnis als Textdatei gespeichert Hab den mal als Quellcode gewandelt, damit man die Kommentare erkenne kann
Delphi-Quellcode:
Ich hoffe du kannst erkennen, das die Datensätze doch unterschiedlich sein können. Ich übergebe jetzt doch wieder einen kompletten Datensatz an die Parsefunktion.
Ereignis: 5773 //Immer so
Datum: 09.12.2008, Uhrzeit: 19:07:31 //Immer so Sabotagemeldergruppe: 0004 EIN //Doch sehr viele Varianten erscheint aber in jedem Datensatz AP E/A E: 04 Differential-Eingang //Wenig Varianten, aber dafür nicht in jedem Datensatz vorhanden Hauptbereich: 001, Unterbereich: 000 //Text kann evtl. auch "vbaelrvgbaelrvub" sein //(Hauptbereich z.B. könnte auch einen selbst erstellten Namen habe) Ereignis: 5774 Datum: 09.12.2008, Uhrzeit: 19:07:31 AP E/A E: 05 Sabotage Sirene EIN Hauptbereich: 001 Mein Problem ist jetzt, immer noch die genaue Zuweisung der Daten in die richtigen Zeilen Wenn ich mir den kompletten Datensatz ansehe, habe ich ja immer die Trennung zwischen den Zeilenvorschüben, Leider weiß ich immer noch nicht wie ich erkennen soll, das in der Mitte ein Teildatensatz fehlt. Eréignis ist klar, damit fängt der Datensatz immer an Datum somit auch kein Problem und Uhrzeit bekomme ich auch gefilter. Der Teilnehmer Text, wenn er da ist, könnte ich mir momentan noch vorstellen in an den Kürzeln AP, IE, MAKRO AE zu erkenne. Der Bereich ist immer der letzte Datensatz allerdings ohne festen Namen Vieleicht kannst du mir mal folgende Funktionen von der ParsenUtils erklären. Da habert es nämlich bei mir.
Delphi-Quellcode:
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 Result := -1; CurPointer := DataPointer; while Result < 0 do begin while (CurPointer < Length(Data)) and not IsTerminatingChar(CurPointer) do Inc(CurPointer); if (CurPointer + 1 < Length(Data)) and not IsTerminatingChar(CurPointer + 1) then Inc(CurPointer) else Result := CurPointer - DataPointer; if CurPointer = Length(Data) then Result := CurPointer - DataPointer + 1; end; end; |
Re: StringGrid mit Daten füllen und farblich Darstellen
Die Funktion GetTextLength ist unnötig kompliziert (oder künstlerische Freiheit).
Delphi-Quellcode:
var
CurPointer: Integer; begin CurPointer := DataPointer; while (CurPointer <= Length(Data)) and not IsTerminatingChar(CurPointer) do Inc(CurPointer); Result := CurPointer - DataPointer; end; |
Re: StringGrid mit Daten füllen und farblich Darstellen
Kann schon möglich sein, gibt es den hier auch jemanden, der mir die Funktionen auch irgendwie erklären kann, damit auch ich den Ablauf verstehe ?
Gruß Jens |
Re: StringGrid mit Daten füllen und farblich Darstellen
Liste der Anhänge anzeigen (Anzahl: 1)
Hab es hinbekommen, den kompletten Datensatz auszuwerten. Und bekomme auch alle Rückgaben in mein Unit zurück. Leider habe ich jetzt ein anderes Problem.
Die Daten werden nur dann in mein StringGrid eingetragen, wenn ich im Debugmodus im Unit Parsen einen Breakpoint setze. Nehme ich dann den Breakpoint weg, sind meine Daten sauber und auch richtig sortiert in meinem StringGrid. Lass ich mein Programm normal laufen, gelangen keine Einträge in mein StringGrid, In einem Memo kann ich aber sehen, das Daten kommen und auch übergeben werden. Ich häng mal die komplette fertige Unit Parsen und die Übergabe an.. bzw füge sie als Code bei:
Delphi-Quellcode:
Hier die Übernahme in mein Unit
unit Parsen;
interface uses Windows, SysUtils; type TMyDataEntry = record LfdNr: Integer; 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 := StrToInt(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} {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; end.
Delphi-Quellcode:
Und im Anhang mal noch ein Bild im DebugModus, wo man sieht, das die Daten auch wirklich so sind, wie sie sein sollen.
procedure TForm1.TreeViewResult(ParserTreeView: TMyBaseParser);
var i: Integer; begin for i := 0 to High(ParserTreeView.Entries) do begin if ParserTreeView.Entries[i].LfdNr = 0 then begin RCount := RCount+1; SGMB256plus.RowCount := RCount+1; Memo2.Lines.Add(IntToStr(ParserTreeView.Entries[i].LfdNr)); SGMB256plus.Cells[0, RCount + 1] := IntToStr(ParserTreeView.Entries[i].LfdNr); end; if ParserTreeView.Entries[i].Datum <> '' then begin Memo3.Lines.Add(ParserTreeView.Entries[i].Datum); SGMB256plus.Cells[1, RCount + 1] := ParserTreeView.Entries[i].Datum; end; if ParserTreeView.Entries[i].Uhrzeit <> '' then begin Memo4.Lines.Add(ParserTreeView.Entries[i].Uhrzeit); SGMB256plus.Cells[2, RCount + 1] := ParserTreeView.Entries[i].Uhrzeit; end; if ParserTreeView.Entries[i].Ereignis <> '' then begin Memo5.Lines.Add(ParserTreeView.Entries[i].Ereignis); SGMB256plus.Cells[3, RCount + 1] := ParserTreeView.Entries[i].Ereignis; end; if ParserTreeView.Entries[i].Teilnehmer <> '' then begin Memo6.Lines.Add(ParserTreeView.Entries[i].Teilnehmer); SGMB256plus.Cells[4, RCount + 1] := ParserTreeView.Entries[i].Teilnehmer; end; if ParserTreeView.Entries[i].Bereich <> '' then begin Memo7.Lines.Add(ParserTreeView.Entries[i].Bereich); SGMB256plus.Cells[5, RCount + 1] := ParserTreeView.Entries[i].Bereich; end; end; end; Danke schon mal. Vieleicht weiß ja jemand woran es liegen kann.. MFG Jens |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:22 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz