Einzelnen Beitrag anzeigen

Delphi.Narium

Registriert seit: 27. Nov 2017
2.598 Beiträge
 
Delphi 7 Professional
 
#8

AW: KI Code : Editor für Daten

  Alt 31. Jul 2025, 13:31
Aktuell erhalte ich von der KI keine direkte Anleitung, wie ich ein Problem am besten implementieren kann. Der Code, den ich erhalte, ist meist das Ergebnis einer längeren Iteration mit den entsprechenden Tools.
Kann ich meine Fragen bereits so formulieren, dass ich in der KI-Antwort auch die am besten geeigneten Komponenten (z. B. Value Editor, MemIni-Dateien ...) aufgezeigt bekomme?
Welches KI-Tool bietet hierbei die beste Unterstützung?
Kommt drauf an, was man will.

Zur Zeit habe ich 26 KIs, die ich situationsbedingt, kontextbedingt, ... befrage. Jede hat ihre Stärken und Schwächen. Bei komplexeren Sachen frage ich zuerst eine KI und wenn das Ergebnis für mich brauchbar erscheint, frage ich eine andere, ob es wirklich brauchbar ist.

Da Du Deine gestellten Fragen nicht zur Verfügung stellst, ist es kaum möglich noch Ratschläge, Tipps, Anregungen zu geben, ob und wie Du Deine Fragestellungen ergänzen könntest.

Stelle uns Deine Fragen zur Verfügung, dann können wir ggfls. Deine Frage
Zitat von bernhard_LA:
Kann ich meine Fragen bereits so formulieren, dass ich in der KI-Antwort auch die am besten geeigneten Komponenten (z. B. Value Editor, MemIni-Dateien ...) aufgezeigt bekomme?
beantworten. Ohne Kenntnis Deiner Fragen ist Deine Frage nicht zu beantworten.

Deine anfangs geposteten Quelltexte hab' ich einfach per Copy&Paste Perplexity.ai zur Verfügung gestellt und gefragt, ob's ok ist (s. o.). Als Ergebnis kam sofort eine Verbesserung heraus.

Und da Du ja ChatGPT nutzt, habe ich ChatGPT mal gefragt:
Zitat von Frage:
Gibt es noch Verbesserungspotential, Fehler, Redundanzen, ...?
Dashier ist dabei rausgekommen:
Zitat von Antwort:
Dein INI-Datei-Editor ist sauber strukturiert, modular aufgebaut und trennt die GUI sinnvoll von der Datenlogik. Sehr durchdacht für ein 2-Stunden-Ergebnis mit KI-Unterstützung! Trotzdem gibt es noch einige Verbesserungsansätze, die du in Betracht ziehen könntest – teils stilistisch, teils funktional:

"Kritik & Verbesserungsvorschläge"

"1. Redundanz vermeiden"
Delphi-Quellcode:
// Doppelt aufgerufen:
FDataItemList.LoadFromStringList(StringList);
FDataItemList.LoadFromStringList(StringList);
Zitat von Fortsetzung der Antwort:
Nur ein Aufruf genügt.

"2. 'FItemIndex' initialisieren"
FItemIndex: Integer;
Zitat von Fortsetzung der Antwort:
Der Index ist anfangs nicht gesetzt (Default = 0), was u.*U. zu einem Fehler führt, wenn 'FDataItemList.Count = 0'. Besser:
FItemIndex := -1;
Zitat von Fortsetzung der Antwort:
Und in 'FormCreate' z.*B.:
Delphi-Quellcode:
if FDataItemList.Count > 0 then
  FItemIndex := 0;
Zitat von Fortsetzung der Antwort:


"3. Typisierung / Eingabebeschränkung vereinheitlichen"

Du verwendest Eingabebeschränkung sowohl bei 'KeyDown' als auch bei 'ValidateInput'. Das ist gut – aber du solltest sie ggf. zentralisieren, um Redundanz zu vermeiden. Der Code in 'KeyDown' und 'ValidateInput' ist teilweise doppelt.

Optional: Eine Methode 'IsValidCharForType(Char, TInputType): Boolean' auslagern.

"4. Verbesserung bei der Darstellung"

In 'DisplayActiveItem':
edt_Datatype.Text := GetEnumName(...);
Zitat von Fortsetzung der Antwort:
Diese Information sollte ggf. "nicht" editierbar sein, sondern nur angezeigt werden ? 'TLabel' oder 'TReadOnly = True'.

"5. Robustheit bei der Navigation"

Aktuell kann der Benutzer mit „Up“ über das Listenende hinaus navigieren:
Delphi-Quellcode:
FItemIndex := FItemIndex + 1;
FItemIndex := Min(FItemIndex, FDataItemList.Count - 1);
Zitat von Fortsetzung der Antwort:
Besser wäre:
Delphi-Quellcode:
if FItemIndex < FDataItemList.Count - 1 then
  Inc(FItemIndex);
Zitat von Fortsetzung der Antwort:
Gleiche Logik bei 'btn_DownClick'.

"6. Wertlose 'edt_propertyValueEnter'-Methode"

Aktuell leer:
Delphi-Quellcode:
procedure TForm1.edt_propertyValueEnter(Sender: TObject);
begin
  /// check for valid user inputs and save data
end;
Zitat von Fortsetzung der Antwort:
Diese Methode könnte entfernt oder genutzt werden, z.*B. zum "Zurückspeichern vorheriger Eingaben", wenn der Benutzer „vorspult“ ohne zu bestätigen.

"7. JSON-Ausgabe könnte mit 'Indent' formatiert sein"

Zur besseren Lesbarkeit in der 'TMemo':
Result := JSONArray.Format(2); // statt ToJSON
Zitat von Fortsetzung der Antwort:
Erfordert ggf. alternative Methode oder JSON-Helper.

"8. Enum-Parsing konsistent"

Du benutzt einmal:
if SameText(DataTypeStr, 'Boolean') then ...
Zitat von Fortsetzung der Antwort:
und einmal:
if SameText(DataTypeStr, 'itBoolean') then ...
Zitat von Fortsetzung der Antwort:
? Vereinheitlichen. Entweder mit oder ohne 'it'-Prefix. Ggf. Hilfsfunktion 'TInputTypeHelper.ToString/FromString'.

"9. Erweiterbarkeit"

Wenn du weitere Typen einführen willst (z.*B. 'itColor', 'itPath'), wäre es hilfreich, für jeden Typ Methoden einzuführen:
Delphi-Quellcode:
function TInputType.IsValid(const Value: string): Boolean;
function TInputType.AllowedChars: TCharSet;
Zitat von Fortsetzung der Antwort:
"10. Vorschlag für 'TDataItem.ToJSON'"

Der Code zum Erzeugen des JSON-Objekts liegt aktuell in der List-Klasse. Objektorientierter wäre:
function TDataItem.ToJSON: TJSONObject;
Zitat von Fortsetzung der Antwort:
Dann sähe 'TDataItemList.GetAsJSON' so aus:
Delphi-Quellcode:
for DataItem in Self do
  JSONArray.AddElement(DataItem.ToJSON);
Zitat von Fortsetzung der Antwort:
Positives

' "Entkopplung GUI <-> Logik:" sehr gelungen.
' "Modularisierung:" Datenhaltung, Validierung und Darstellung getrennt.
' "Fehlertoleranz:" Validierung bei Eingabe, inklusive Rückmeldung an den User.
' "JSON-Schnittstelle:" Praktisch für Persistenz.
' "Erweiterbarkeit:" Die 'TInputType'-Konstruktion lässt sich später leicht erweitern.

Fazit

Du hast eine solide, flexible Grundlage geschaffen – vor allem, weil du "nicht" starr an einer FMX-basierten GUI festhängst. Die Daten- und Logikebene lässt sich leicht auch über CLI, Web-Frontend oder Kommandozeile verwenden. Genau richtig für einen INI/Settings-Editor mit Validierung.

Wenn du möchtest, helfe ich dir gern bei:

' Unit-Tests für die Datamodule
' Refactoring zu MVVM/MVC
' Zusätzliche Typen/Validierungen (z.*B. 'itPath', 'itEnum', …)
' Auto-Vervollständigung oder Tooltips für den Editor

Willst du in diese Richtung noch weiter optimieren?
Zitat von Frage:
Könnten Sie mir bitte eine, nach Ihren Anregungen, Kriterien, ... überarbeitete Version der Quelltexte zur Verfügung stellen?
Zitat von Antwort:
Gerne! Im Folgenden findest du die überarbeiteten Versionen beider Units, basierend auf den genannten Verbesserungsvorschlägen:

"1. 'Unit_TDataModule.pas' – überarbeitet"
Delphi-Quellcode:
unit Unit_TDataModule;

interface

uses
  System.Classes, System.SysUtils, System.Generics.Collections, System.JSON,
  System.IOUtils, TypInfo;

type
  TInputType = (itString, itNumber, itBoolean);

  TDataItem = class
  private
    FName: string;
    FDataType: TInputType;
    FValue: string;
    FDefaultValue: string;
  public
    property Name: string read FName write FName;
    property DataType: TInputType read FDataType write FDataType;
    property Value: string read FValue write FValue;
    property DefaultValue: string read FDefaultValue write FDefaultValue;

    constructor Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
    procedure ResetToDefault;
    function ToJSON: TJSONObject;
  end;

  TDataItemList = class(TObjectList<TDataItem>)
  private
    function GetAsJSON: string;
  public
    property AsJSON: string read GetAsJSON;

    procedure LoadFromStringList(AStringList: TStringList);
    procedure SaveToFile(const AFileName: string);
    procedure LoadFromFile(const AFileName: string);
  end;

function ParseInputType(const DataTypeStr: string): TInputType;
function InputTypeToString(DataType: TInputType): string;

implementation

function ParseInputType(const DataTypeStr: string): TInputType;
begin
  if SameText(DataTypeStr, 'Boolean') then
    Result := itBoolean
  else if SameText(DataTypeStr, 'Number') then
    Result := itNumber
  else if SameText(DataTypeStr, 'String') then
    Result := itString
  else
    raise Exception.CreateFmt('Unknown data type: %s', [DataTypeStr]);
end;

function InputTypeToString(DataType: TInputType): string;
begin
  case DataType of
    itBoolean: Result := 'Boolean';
    itNumber: Result := 'Number';
    itString: Result := 'String';
  else
    Result := '';
  end;
end;

{ TDataItem }

constructor TDataItem.Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
begin
  inherited Create;
  FName := AName;
  FDataType := ADataType;
  FDefaultValue := ADefaultValue;
  FValue := ADefaultValue;
end;

procedure TDataItem.ResetToDefault;
begin
  FValue := FDefaultValue;
end;

function TDataItem.ToJSON: TJSONObject;
begin
  Result := TJSONObject.Create;
  Result.AddPair('Name', Name);
  Result.AddPair('DataType', InputTypeToString(DataType));
  Result.AddPair('Value', Value);
  Result.AddPair('DefaultValue', DefaultValue);
end;

{ TDataItemList }

function TDataItemList.GetAsJSON: string;
var
  JSONArray: TJSONArray;
  DataItem: TDataItem;
begin
  JSONArray := TJSONArray.Create;
  try
    for DataItem in Self do
      JSONArray.AddElement(DataItem.ToJSON);
    Result := JSONArray.Format(2); // formatiert für bessere Lesbarkeit
  finally
    JSONArray.Free;
  end;
end;

procedure TDataItemList.LoadFromStringList(AStringList: TStringList);
var
  i: Integer;
  Parts: TArray<string>;
begin
  for i := 0 to AStringList.Count - 1 do
  begin
    Parts := AStringList[i].Split(['|']);
    if Length(Parts) <> 3 then
      raise Exception.CreateFmt('Invalid format in line %d: %s', [i + 1, AStringList[i]]);

    Add(TDataItem.Create(Parts[0], ParseInputType(Parts[1]), Parts[2]));
  end;
end;

procedure TDataItemList.SaveToFile(const AFileName: string);
begin
  TFile.WriteAllText(AFileName, AsJSON);
end;

procedure TDataItemList.LoadFromFile(const AFileName: string);
var
  JSONArray: TJSONArray;
  JSONObject: TJSONObject;
  JSONString: string;
  i: Integer;
begin
  JSONString := TFile.ReadAllText(AFileName);
  JSONArray := TJSONObject.ParseJSONValue(JSONString) as TJSONArray;
  if not Assigned(JSONArray) then
    raise Exception.Create('Invalid JSON format.');

  try
    for i := 0 to JSONArray.Count - 1 do
    begin
      JSONObject := JSONArray.Items[i] as TJSONObject;
      Add(TDataItem.Create(
        JSONObject.GetValue<string>('Name'),
        ParseInputType(JSONObject.GetValue<string>('DataType')),
        JSONObject.GetValue<string>('DefaultValue')
      ));
      Self.Last.Value := JSONObject.GetValue<string>('Value');
    end;
  finally
    JSONArray.Free;
  end;
end;

end.
Zitat von Fortsetzung der Antwort:
"2. 'StudyDatamodule.pas' – überarbeitet"
Delphi-Quellcode:
unit StudyDatamodule;

interface

uses
  System.SysUtils, System.Classes, System.Types, System.UITypes, System.Rtti,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo, FMX.Edit,
  Unit_TDataModule, Math;

type
  TForm1 = class(TForm)
    mmo1: TMemo;
    btn_InitList: TButton;
    edt_propertyValue: TEdit;
    lbl_PropertyName: TLabel;
    btn_Up: TButton;
    btn_Down: TButton;
    edt_Datatype: TEdit;
    btn_ListasJSON: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btn_UpClick(Sender: TObject);
    procedure btn_DownClick(Sender: TObject);
    procedure edt_propertyValueExit(Sender: TObject);
    procedure edt_propertyValueKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
    procedure btn_ListasJSONClick(Sender: TObject);
  private
    FDataItemList: TDataItemList;
    FItemIndex: Integer;
    procedure DisplayActiveItem(Index: Integer);
    procedure SaveInputToItem;
    function ValidateInput(const Value: string; DataType: TInputType): Boolean;
  public
  end;

var
  Form1: TForm1;

implementation

{$R '.fmx}

procedure TForm1.FormCreate(Sender: TObject);
var
  StringList: TStringList;
begin
  StringList := TStringList.Create;
  FDataItemList := TDataItemList.Create(True);
  try
    StringList.Add('EnableLogging|Boolean|true');
    StringList.Add('MaxLogFileSize|Number|1048576');
    StringList.Add('LogFilePath|String|C:\Logs\app.log');
    StringList.Add('Theme|String|dark');
    StringList.Add('RetryDelay|Number|5');

    FDataItemList.LoadFromStringList(StringList);

    if FDataItemList.Count > 0 then
    begin
      FItemIndex := 0;
      DisplayActiveItem(FItemIndex);
    end;

  finally
    StringList.Free;
  end;
end;

procedure TForm1.DisplayActiveItem(Index: Integer);
var
  DataItem: TDataItem;
begin
  if (Index < 0) or (Index >= FDataItemList.Count) then Exit;

  DataItem := FDataItemList[Index];
  lbl_PropertyName.Text := DataItem.Name;
  edt_propertyValue.Text := DataItem.Value;
  edt_Datatype.Text := InputTypeToString(DataItem.DataType);
end;

procedure TForm1.SaveInputToItem;
var
  DataItem: TDataItem;
  UserInput: string;
begin
  if (FItemIndex < 0) or (FItemIndex >= FDataItemList.Count) then Exit;

  DataItem := FDataItemList[FItemIndex];
  UserInput := Trim(edt_propertyValue.Text);

  if not ValidateInput(UserInput, DataItem.DataType) then
  begin
    ShowMessage(Format('Invalid input for %s. Expected a %s.', [DataItem.Name, InputTypeToString(DataItem.DataType)]));
    edt_propertyValue.SetFocus;
    Exit;
  end;

  DataItem.Value := UserInput;
end;

function TForm1.ValidateInput(const Value: string; DataType: TInputType): Boolean;
var
  TempFloat: Double;
  TempBool: Boolean;
begin
  case DataType of
    itString: Result := True;
    itNumber: Result := TryStrToFloat(Value, TempFloat);
    itBoolean: Result := TryStrToBool(Value, TempBool);
  else
    Result := False;
  end;
end;

procedure TForm1.btn_UpClick(Sender: TObject);
begin
  if FItemIndex < FDataItemList.Count - 1 then
  begin
    SaveInputToItem;
    Inc(FItemIndex);
    DisplayActiveItem(FItemIndex);
  end;
end;

procedure TForm1.btn_DownClick(Sender: TObject);
begin
  if FItemIndex > 0 then
  begin
    SaveInputToItem;
    Dec(FItemIndex);
    DisplayActiveItem(FItemIndex);
  end;
end;

procedure TForm1.edt_propertyValueExit(Sender: TObject);
begin
  SaveInputToItem;
end;

procedure TForm1.edt_propertyValueKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
var
  DataItem: TDataItem;
begin
  if (FItemIndex < 0) or (FItemIndex >= FDataItemList.Count) then Exit;

  DataItem := FDataItemList[FItemIndex];

  case DataItem.DataType of
    itNumber:
      if not (KeyChar in ['0'..'9', '.', '-', #8]) then
        KeyChar := #0;
    itBoolean:
      if not (KeyChar in ['t','r','u','e','f','a','l','s','e', #8]) then
        KeyChar := #0;
  end;
end;

procedure TForm1.btn_ListasJSONClick(Sender: TObject);
begin
  mmo1.Lines.Text := FDataItemList.AsJSON;
end;

end.
Zitat von Fortsetzung der Antwort:
Wenn du möchtest, kann ich daraus auch ein kompaktes Demo-Projekt (.dproj + .fmx) ableiten oder Unit-Tests für 'TDataItemList' schreiben. Wäre das hilfreich für dich?
ChatGPT hat also noch mehr drauf und kann das ursprüngliche Ergebnis noch verbessern.
  Mit Zitat antworten Zitat