AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

KI Code : Editor für Daten

Ein Thema von bernhard_LA · begonnen am 30. Jul 2025 · letzter Beitrag vom 31. Jul 2025
Antwort Antwort
bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.153 Beiträge
 
Delphi 11 Alexandria
 
#1

KI Code : Editor für Daten

  Alt Gestern, 22:50
Was ich benötige: Einen äußerst flexiblen INI-Datei-Editor mit einer Prüfung, ob die Benutzerdaten korrekt sind.
Ein Delphi-Formular mit entsprechenden GUI-Komponenten wäre mir viel zu statisch.


Hier ist das Ergebnis nach ca. 2 Stunden Arbeit mit ChatGPT:
In der ersten Version waren die GUI und die Nutzerlogik untrennbar miteinander verbunden.
In den folgenden Iterationen habe ich schließlich diese Klasse entwickelt.


Ich freue mich über Feedback!


Delphi-Quellcode:
unit StudyDatamodule;

interface

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

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_propertyValueEnter(Sender: TObject);
    procedure edt_propertyValueExit(Sender: TObject);
    procedure edt_propertyValueKeyDown(Sender: TObject; var Key: Word;
      var KeyChar: Char; Shift: TShiftState);
    procedure edt_propertyValueKeyUp(Sender: TObject; var Key: Word;
      var KeyChar: Char; Shift: TShiftState);
    procedure btn_ListasJSONClick(Sender: TObject);
  private
    { Private declarations }
    FDataItemList: TDataItemList;
    FItemIndex: Integer;
    procedure DisplayActiveItem(index: Integer);
    procedure SaveInputToItem;
    function ValidateInput(const Value: string; DataType: TInputType): Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}
// Example Initialization from StringList
// ere’s an updated FormCreate method that uses the new functionality:

procedure TForm1.btn_DownClick(Sender: TObject);
begin
  FItemIndex := FItemIndex - 1;

  FItemIndex := Max(FItemIndex, 0);

  DisplayActiveItem(FItemIndex);
end;

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

procedure TForm1.btn_UpClick(Sender: TObject);
begin
  FItemIndex := FItemIndex + 1;

  FItemIndex := Min(FItemIndex, FDataItemList.Count - 1);

  DisplayActiveItem(FItemIndex);
end;

procedure TForm1.DisplayActiveItem(index: Integer);
var
  DataItem: TDataItem;
begin
  DataItem := FDataItemList.Items[Index];

  lbl_PropertyName.Text := DataItem.Name;

  edt_propertyValue.Text := DataItem.Value;

  edt_Datatype.Text := GetEnumName(TypeInfo(TInputType),
    Integer(DataItem.DataType));
end;

procedure TForm1.edt_propertyValueEnter(Sender: TObject);
begin
  /// check for valid user inputs and save data
end;

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

// Restrict input while typing
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.Items[FItemIndex];

  // Restrict input for numbers and booleans
  case DataItem.DataType of
    itNumber:
      if not(KeyChar in ['0' .. '9', '.', '-', #8]) then
      // Allow digits, decimal point, negative sign, and backspace
        KeyChar := #0;
    itBoolean:
      if not(KeyChar in ['t', 'r', 'u', 'e', 'f', 'a', 'l', 's', #8]) then
      // Allow 'true' and 'false'
        KeyChar := #0;
  end;
end;

procedure TForm1.edt_propertyValueKeyUp(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
begin

end;

// Save the user's input into the active data item
procedure TForm1.SaveInputToItem;
var
  DataItem: TDataItem;
  UserInput: string;
begin
  if (FItemIndex < 0) or (FItemIndex >= FDataItemList.Count) then
    Exit;

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

  // Validate the input
  if not ValidateInput(UserInput, DataItem.DataType) then
  begin
    ShowMessage(Format('Invalid input for %s. Expected a %s value.',
      [DataItem.Name, GetEnumName(TypeInfo(TInputType),
      Integer(DataItem.DataType))]));
    edt_propertyValue.SetFocus; // Return focus to the input field
    Exit;
  end;

  // Save the validated input to the data item's Value field
  DataItem.Value := UserInput;
end;

// Validate user input based on the data type of the current item
function TForm1.ValidateInput(const Value: string;
  DataType: TInputType): Boolean;
var
  TempFloat: Double;
  TempBoolean: Boolean;
begin
  Result := False;
  case DataType of
    itString:
      Result := True; // Any string is valid
    itNumber:
      Result := TryStrToFloat(Value, TempFloat); // Validate numeric input
    itBoolean:
      Result := TryStrToBool(Value, TempBoolean);
      // Validate boolean input ('true' or 'false')
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  StringList: TStringList;
  DataItem: TDataItem;
begin
  StringList := TStringList.Create;
  FDataItemList := TDataItemList.Create(True); // Owns objects
  try
    // Populate TStringList with data using '|' as the delimiter
    StringList.Add('EnableLogging|Boolean|true');
    StringList.Add('MaxLogFileSize|Number|1048576');
    // File size in bytes (1 MB)
    StringList.Add('LogFilePath|String|C:\Logs\app.log');
    StringList.Add('EnableAutoSave|Boolean|true');
    StringList.Add('AutoSaveInterval|Number|10'); // Interval in minutes
    StringList.Add('Theme|String|dark');
    StringList.Add('ShowNotifications|Boolean|true');
    StringList.Add('MaxRetries|Number|3');
    StringList.Add('RetryDelay|Number|5'); // Delay in seconds
    StringList.Add('EnableEncryption|Boolean|true');
    StringList.Add('EncryptionKey|String|default_key');
    StringList.Add('AllowGuestAccess|Boolean|false');
    StringList.Add('DefaultLanguage|String|en');
    StringList.Add('TimeoutDuration|Number|30'); // Timeout in seconds
    StringList.Add('EnableDebugMode|Boolean|false');

    FDataItemList.LoadFromStringList(StringList);

    // Load data into TDataItemList
    FDataItemList.LoadFromStringList(StringList);

    // Display loaded items for verification
    for DataItem in FDataItemList do
      mmo1.Lines.Add(Format('Name: %s, DataType: %s, DefaultValue: %s',
        [DataItem.Name, GetEnumName(TypeInfo(TInputType),
        Integer(DataItem.DataType)), DataItem.DefaultValue]));

    DisplayActiveItem(FItemIndex);

  finally
    StringList.Free;
  end;
end;

end.

und die Klasse zur Datenspeicherung


Delphi-Quellcode:

unit Unit_TDataModule;

interface

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

type
  // Enum to represent input types
  TInputType = (itString, itNumber, itBoolean);

  // Class representing individual data items
  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); overload;
    procedure ResetToDefault; // Resets the Value to DefaultValue
  end;

  // Class representing a list of data items
  TDataItemList = class(TObjectList<TDataItem>)
  private
    function GetAsJSON: string; // Returns JSON representation of the list
  public
    property AsJSON: string read GetAsJSON; // Read-only property to get JSON string

    procedure LoadFromStringList(AStringList: TStringList); // Load items from a string list
    procedure SaveToFile(const AFileName: string); // Save items to a JSON file
    procedure LoadFromFile(const AFileName: string); // Load items from a JSON file
  end;

implementation

{ TDataItem }

constructor TDataItem.Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
begin
  inherited Create;
  FName := AName;
  FDataType := ADataType;
  FDefaultValue := ADefaultValue;
  FValue := ''; // Initialize Value to unset (empty string)
end;

procedure TDataItem.ResetToDefault;
begin
  FValue := FDefaultValue; // Reset Value to the DefaultValue
end;

{ TDataItemList }

function TDataItemList.GetAsJSON: string;
var
  JSONArray: TJSONArray;
  JSONObject: TJSONObject;
  DataItem: TDataItem;
begin
  JSONArray := TJSONArray.Create;
  try
    // Iterate through the items and convert them to JSON
    for DataItem in Self do
    begin
      JSONObject := TJSONObject.Create;
      JSONObject.AddPair('Name', DataItem.Name);
      JSONObject.AddPair('DataType', GetEnumName(TypeInfo(TInputType), Integer(DataItem.DataType))); // Convert enum to string
      JSONObject.AddPair('Value', DataItem.Value);
      JSONObject.AddPair('DefaultValue', DataItem.DefaultValue);
      JSONArray.AddElement(JSONObject);
    end;

    Result := JSONArray.ToJSON; // Return the JSON string
  finally
    JSONArray.Free;
  end;
end;

procedure TDataItemList.LoadFromStringList(AStringList: TStringList);
var
  i: Integer;
  LineParts: TArray<string>;
  Name, DefaultValue: string;
  DataType: TInputType;

  function ParseDataType(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;

begin
  for i := 0 to AStringList.Count - 1 do
  begin
    LineParts := AStringList[i].Split(['|']);
    if Length(LineParts) <> 3 then
      raise Exception.CreateFmt('Invalid format in line %d: %s', [i + 1, AStringList[i]]);

    Name := LineParts[0];
    DataType := ParseDataType(LineParts[1]);
    DefaultValue := LineParts[2];

    // Add the item and set both DefaultValue and Value
    Self.Add(TDataItem.Create(Name, DataType, DefaultValue));
    Self.Last.Value := DefaultValue; // Initialize Value to DefaultValue
  end;
end;

procedure TDataItemList.SaveToFile(const AFileName: string);
begin
  // Save the JSON representation to a file
  TFile.WriteAllText(AFileName, AsJSON);
end;

procedure TDataItemList.LoadFromFile(const AFileName: string);
var
  JSONArray: TJSONArray;
  JSONObject: TJSONObject;
  JSONString: string;
  i: Integer;
  Name, DataTypeStr, Value, DefaultValue: string;
  DataType: TInputType;

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

begin
  // Load JSON string from file
  JSONString := TFile.ReadAllText(AFileName);

  // Parse JSON string
  JSONArray := TJSONObject.ParseJSONValue(JSONString) as TJSONArray;
  if not Assigned(JSONArray) then
    raise Exception.Create('Invalid JSON format in file.');

  try
    // Iterate through JSON array and populate the list
    for i := 0 to JSONArray.Count - 1 do
    begin
      JSONObject := JSONArray.Items[i] as TJSONObject;
      Name := JSONObject.GetValue<string>('Name');
      DataTypeStr := JSONObject.GetValue<string>('DataType');
      Value := JSONObject.GetValue<string>('Value');
      DefaultValue := JSONObject.GetValue<string>('DefaultValue');
      DataType := ParseDataType(DataTypeStr);

      // Add the item
      Self.Add(TDataItem.Create(Name, DataType, DefaultValue));
      Self.Last.Value := Value; // Set the current value
    end;
  finally
    JSONArray.Free;
  end;
end;

end.
  Mit Zitat antworten Zitat
Rollo62

Registriert seit: 15. Mär 2007
4.240 Beiträge
 
Delphi 12 Athens
 
#2

AW: KI Code : Editor für Daten

  Alt Heute, 06:57
Ja kann man machen, aber warum die Datenklasse nicht von TMemInifile ableiten oder womöglich als helper und
stattdessen das Rad neu erfinden?
https://docwiki.embarcadero.com/Libr...es.TMemIniFile

Damit hätte man schon einen Großteil der Basis-Funktionen zukunftssicher abgedeckt und wäre auch noch direkt kompatibel zu den existierenden MemIniFiles im Projekt.
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
1.133 Beiträge
 
Delphi 2009 Professional
 
#3

AW: KI Code : Editor für Daten

  Alt Heute, 08:11
Wieso weder als Bild noch als Download sondern nur als Wall of Quelltext?
Janni
2005 PE, 2009 PA, XE2 PA
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.596 Beiträge
 
Delphi 7 Professional
 
#4

AW: KI Code : Editor für Daten

  Alt Heute, 09:23
Diese function ParseDataType(const DataTypeStr: string): TInputType; gibt es mehrfach. Warum?

FDataItemList.LoadFromStringList(StringList); wird mehrfach hintereinander aufgerufen, warum?

Warum gibt es leere Methoden?

Wird wirklich alles, was im Uses steht benötigt?

Habe mal Perplexity.ai um Überarbeitung gebeten. Dashier ist dabei herausgekommen:

Zitat von Frage:
Lässt sich nachfolgende Unit vereinfachen? Enthält sie Redundanzen o. ä.?
Delphi-Quellcode:
unit StudyDatamodule;

interface

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

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_propertyValueEnter(Sender: TObject);
    procedure edt_propertyValueExit(Sender: TObject);
    procedure edt_propertyValueKeyDown(Sender: TObject; var Key: Word;
      var KeyChar: Char; Shift: TShiftState);
    procedure edt_propertyValueKeyUp(Sender: TObject; var Key: Word;
      var KeyChar: Char; Shift: TShiftState);
    procedure btn_ListasJSONClick(Sender: TObject);
  private
    { Private declarations }
    FDataItemList: TDataItemList;
    FItemIndex: Integer;
    procedure DisplayActiveItem(index: Integer);
    procedure SaveInputToItem;
    function ValidateInput(const Value: string; DataType: TInputType): Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}
// Example Initialization from StringList
// ere’s an updated FormCreate method that uses the new functionality:

procedure TForm1.btn_DownClick(Sender: TObject);
begin
  FItemIndex := FItemIndex - 1;

  FItemIndex := Max(FItemIndex, 0);

  DisplayActiveItem(FItemIndex);
end;

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

procedure TForm1.btn_UpClick(Sender: TObject);
begin
  FItemIndex := FItemIndex + 1;

  FItemIndex := Min(FItemIndex, FDataItemList.Count - 1);

  DisplayActiveItem(FItemIndex);
end;

procedure TForm1.DisplayActiveItem(index: Integer);
var
  DataItem: TDataItem;
begin
  DataItem := FDataItemList.Items[Index];

  lbl_PropertyName.Text := DataItem.Name;

  edt_propertyValue.Text := DataItem.Value;

  edt_Datatype.Text := GetEnumName(TypeInfo(TInputType),
    Integer(DataItem.DataType));
end;

procedure TForm1.edt_propertyValueEnter(Sender: TObject);
begin
  /// check for valid user inputs and save data
end;

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

// Restrict input while typing
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.Items[FItemIndex];

  // Restrict input for numbers and booleans
  case DataItem.DataType of
    itNumber:
      if not(KeyChar in ['0' .. '9', '.', '-', #8]) then
      // Allow digits, decimal point, negative sign, and backspace
        KeyChar := #0;
    itBoolean:
      if not(KeyChar in ['t', 'r', 'u', 'e', 'f', 'a', 'l', 's', #8]) then
      // Allow 'true' and 'false'
        KeyChar := #0;
  end;
end;

procedure TForm1.edt_propertyValueKeyUp(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
begin

end;

// Save the user's input into the active data item
procedure TForm1.SaveInputToItem;
var
  DataItem: TDataItem;
  UserInput: string;
begin
  if (FItemIndex < 0) or (FItemIndex >= FDataItemList.Count) then
    Exit;

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

  // Validate the input
  if not ValidateInput(UserInput, DataItem.DataType) then
  begin
    ShowMessage(Format('Invalid input for %s. Expected a %s value.',
      [DataItem.Name, GetEnumName(TypeInfo(TInputType),
      Integer(DataItem.DataType))]));
    edt_propertyValue.SetFocus; // Return focus to the input field
    Exit;
  end;

  // Save the validated input to the data item's Value field
  DataItem.Value := UserInput;
end;

// Validate user input based on the data type of the current item
function TForm1.ValidateInput(const Value: string;
  DataType: TInputType): Boolean;
var
  TempFloat: Double;
  TempBoolean: Boolean;
begin
  Result := False;
  case DataType of
    itString:
      Result := True; // Any string is valid
    itNumber:
      Result := TryStrToFloat(Value, TempFloat); // Validate numeric input
    itBoolean:
      Result := TryStrToBool(Value, TempBoolean);
      // Validate boolean input ('true' or 'false')
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  StringList: TStringList;
  DataItem: TDataItem;
begin
  StringList := TStringList.Create;
  FDataItemList := TDataItemList.Create(True); // Owns objects
  try
    // Populate TStringList with data using '|' as the delimiter
    StringList.Add('EnableLogging|Boolean|true');
    StringList.Add('MaxLogFileSize|Number|1048576');
    // File size in bytes (1 MB)
    StringList.Add('LogFilePath|String|C:\Logs\app.log');
    StringList.Add('EnableAutoSave|Boolean|true');
    StringList.Add('AutoSaveInterval|Number|10'); // Interval in minutes
    StringList.Add('Theme|String|dark');
    StringList.Add('ShowNotifications|Boolean|true');
    StringList.Add('MaxRetries|Number|3');
    StringList.Add('RetryDelay|Number|5'); // Delay in seconds
    StringList.Add('EnableEncryption|Boolean|true');
    StringList.Add('EncryptionKey|String|default_key');
    StringList.Add('AllowGuestAccess|Boolean|false');
    StringList.Add('DefaultLanguage|String|en');
    StringList.Add('TimeoutDuration|Number|30'); // Timeout in seconds
    StringList.Add('EnableDebugMode|Boolean|false');

    FDataItemList.LoadFromStringList(StringList);

    // Load data into TDataItemList
    FDataItemList.LoadFromStringList(StringList);

    // Display loaded items for verification
    for DataItem in FDataItemList do
      mmo1.Lines.Add(Format('Name: %s, DataType: %s, DefaultValue: %s',
        [DataItem.Name, GetEnumName(TypeInfo(TInputType),
        Integer(DataItem.DataType)), DataItem.DefaultValue]));

    DisplayActiveItem(FItemIndex);

  finally
    StringList.Free;
  end;
end;

end.
Zitat von Antwort:
Gerne! Ich habe Ihre Delphi-Unit durchgesehen und nach folgenden Kriterien beurteilt:

- "Redundanzen/Doppelungen"
- "Codevereinfachung" – sowohl stilistisch als auch logisch
- "Allgemeine "Best Practice"-Hinweise"

## Redundanzen & Vereinfachung

1. "Doppelte Aufrufe"
Delphi-Quellcode:
    FDataItemList.LoadFromStringList(StringList);

    // Load data into TDataItemList
    FDataItemList.LoadFromStringList(StringList);
Zitat von Fortsetzung der Antwort:
? "Hier wird 'LoadFromStringList' zweimal direkt hintereinander aufgerufen. Das ist redundant, bitte einen Aufruf entfernen."

2. "Imports / Uses-Klausel"
- Prüfen Sie, ob wirklich alle Einträge benötigt werden (z.B. 'System.Types', 'System.UITypes', 'System.Variants' sowie ggf. aus FMX-Bibliotheken).

3. "Leere Methoden"
Delphi-Quellcode:
procedure TForm1.edt_propertyValueEnter(Sender: TObject);
begin
  /// check for valid user inputs and save data
end;

procedure TForm1.edt_propertyValueKeyUp(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
begin
end;
Zitat von Fortsetzung der Antwort:
? "Kann vermutlich ganz entfernt werden, wenn kein Code folgt."

4. "Index-Handling kann zusammengefasst/gesichert werden"
Sie haben in Up/Down-Buttons dieses Muster:
Delphi-Quellcode:
  FItemIndex := FItemIndex - 1;
  FItemIndex := Max(FItemIndex, 0);
Zitat von Fortsetzung der Antwort:
- und analog für +1 und Min(...)

"Tipp:"
Sie könnten eine Hilfsfunktion wie 'SetItemIndex' einführen, die sowohl den Bereich prüft als auch gleich das Item anzeigt. Dann entfällt in beiden Button-Handlern der gleichartige Code.
Delphi-Quellcode:
procedure TForm1.SetItemIndex(AIndex: Integer);
begin
  if FDataItemList.Count = 0 then Exit;
  FItemIndex := EnsureRange(AIndex, 0, FDataItemList.Count-1);
  DisplayActiveItem(FItemIndex);
end;
Zitat von Fortsetzung der Antwort:
In Down/Up nur noch:
Delphi-Quellcode:
SetItemIndex(FItemIndex-1);
SetItemIndex(FItemIndex+1);
Zitat von Fortsetzung der Antwort:
Delphi kennt 'EnsureRange' ab Berlin, sonst mit 'Min/Max' selbst bauen.

5. "Schreibweise & Konsistenz"
- "Namenskonventionen": Einheitliche Namen verwenden (z.B. 'btn_InitLIst' ? lieber überall CamelCase oder Underscore).
- "Kommentare aktualisieren": Entfernen Sie Altlasten ("// Example Initialization from StringList", da direkt darunter der echte Code steht).
- "Typangaben konsistent": Die Angabe von 'TDataItemList' usw. sollte für Dritte klar sein (z.B. woher diese Typen stammen).

6. "Vereinfachungen am Beispiel"
z.B. in DisplayActiveItem:
Delphi-Quellcode:
procedure TForm1.DisplayActiveItem(index: Integer);
begin
  if (index = FDataItemList.Count) then Exit;

  with FDataItemList.Items[index] do
  begin
    lbl_PropertyName.Text := Name;
    edt_propertyValue.Text := Value;
    edt_Datatype.Text := GetEnumName(TypeInfo(TInputType), Integer(DataType));
  end;
end;
Zitat von Fortsetzung der Antwort:
- Fehler abfangen (out-of-bounds)
- 'with' ist in kleinen Blöcken erlaubt und erhöht hier die Lesbarkeit etwas

7. "Optional: Initialwert 'FItemIndex' sichern"
Wird in 'FormCreate' 'FItemIndex' zu Beginn irgendwo gesetzt? Wenn nicht, ist er evtl. undefiniert (kann zu Problemen führen).
Delphi-Quellcode:
FItemIndex := 0;
if FDataItemList.Count > 0 then
  DisplayActiveItem(FItemIndex);
Zitat von Fortsetzung der Antwort:
8. "Kleinere Stil-Verbesserungen"
- In 'SaveInputToItem' könnten Sie 'Trim(edt_propertyValue.Text)' schon vor der Validierung übernehmen.
- In der Validierung: Case Branches ggfls. einrücken.

## Zusammenfassung

"Redundanzen:"
- 'LoadFromStringList' wird doppelt aufgerufen.
- Leere Methoden vorhanden.
- Up/Down Navigation ähnlich gelöst, kann ausgelagert werden.

"Vereinfachungsvorschläge:"
- Index-Handling über Methode vereinheitlichen.
- Methode zur Anzeige des aktiven Items könnte abgesichert und kompakter geschrieben werden.
- Variablennamen und Kommentare aufräumen.

"> Die Struktur ist sonst bereits modular und übersichtlich.
> Die Logik ist klar, nur etwas "Boilerplate" und Redundanzen, die sich leicht beheben lassen."

Wenn Sie konkrete Vereinfachung einstellen möchten, kann ich Ihnen den Codeblock entsprechend "aufräumen" und alternative Architektur vorschlagen.
Soll ich das tun?
Zitat von Frage:
Könnten Sie mir bitte eine nach Ihren Kriterien überarbeitete Unit zur Verfügung stellen? Um die Uses-Klause werde ich mich dann selbst kümmern.
Zitat von Antwort:
Sehr gerne! Hier ist eine überarbeitete Version Ihrer Unit, in der alle angesprochenen Optimierungen umgesetzt wurden:

- Redundante Aufrufe entfernt
- Leere Methoden gelöscht
- Index-Korrektur und Anzeige vereinheitlicht
- Naming vereinheitlicht
- Diverse Stil- und Fehlerbehandlungs-Verbesserungen
- Kommentare (sofern nötig) erneuert

"Hinweise:"
- Die Typen 'TDataItemList', 'TDataItem' und 'TInputType' stammen vermutlich aus Ihrer eigenen Unit – hier bleibe ich bei der Annahme wie gehabt.
- Die uses-Klausel wurde auf „minimal“ reduziert (Sie ergänzen sie selbst).
Delphi-Quellcode:
unit StudyDatamodule;

interface

uses
  System.SysUtils, System.Classes, Math, FMX.Types, FMX.Controls, FMX.Forms;

type
  TForm1 = class(TForm)
    mmo1: TMemo;
    btnInitList: TButton;
    edtPropertyValue: TEdit;
    lblPropertyName: TLabel;
    btnUp: TButton;
    btnDown: TButton;
    edtDatatype: TEdit;
    btnListAsJSON: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnUpClick(Sender: TObject);
    procedure btnDownClick(Sender: TObject);
    procedure edtPropertyValueExit(Sender: TObject);
    procedure edtPropertyValueKeyDown(Sender: TObject; var Key: Word;
      var KeyChar: Char; Shift: TShiftState);
    procedure btnListAsJSONClick(Sender: TObject);
  private
    FDataItemList: TDataItemList;
    FItemIndex: Integer;
    procedure SetItemIndex(AIndex: Integer);
    procedure DisplayActiveItem(Index: Integer);
    procedure SaveInputToItem;
    function ValidateInput(const Value: string; DataType: TInputType): Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R '.fmx}

procedure TForm1.FormCreate(Sender: TObject);
var
  StringList: TStringList;
  DataItem: TDataItem;
begin
  StringList := TStringList.Create;
  FDataItemList := TDataItemList.Create(True);
  try
    // Populate with demo data (Delimiter: '|')
    StringList.Add('EnableLogging|Boolean|true');
    StringList.Add('MaxLogFileSize|Number|1048576');
    StringList.Add('LogFilePath|String|C:\Logs\app.log');
    StringList.Add('EnableAutoSave|Boolean|true');
    StringList.Add('AutoSaveInterval|Number|10');
    StringList.Add('Theme|String|dark');
    StringList.Add('ShowNotifications|Boolean|true');
    StringList.Add('MaxRetries|Number|3');
    StringList.Add('RetryDelay|Number|5');
    StringList.Add('EnableEncryption|Boolean|true');
    StringList.Add('EncryptionKey|String|default_key');
    StringList.Add('AllowGuestAccess|Boolean|false');
    StringList.Add('DefaultLanguage|String|en');
    StringList.Add('TimeoutDuration|Number|30');
    StringList.Add('EnableDebugMode|Boolean|false');

    FDataItemList.LoadFromStringList(StringList);

    // Anzeige fürs Debugging
    for DataItem in FDataItemList do
      mmo1.Lines.Add(Format('Name: %s, DataType: %s, DefaultValue: %s',
        [DataItem.Name, GetEnumName(TypeInfo(TInputType),
        Integer(DataItem.DataType)), DataItem.DefaultValue]));

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

  finally
    StringList.Free;
  end;
end;

// Unified Item-Index Steuerung (mit Bereichsprüfung)
procedure TForm1.SetItemIndex(AIndex: Integer);
begin
  if FDataItemList.Count = 0 then Exit;
  FItemIndex := Math.EnsureRange(AIndex, 0, FDataItemList.Count - 1);
  DisplayActiveItem(FItemIndex);
end;

// Buttons für Hoch/Runter
procedure TForm1.btnUpClick(Sender: TObject);
begin
  SetItemIndex(FItemIndex + 1);
end;

procedure TForm1.btnDownClick(Sender: TObject);
begin
  SetItemIndex(FItemIndex - 1);
end;

procedure TForm1.DisplayActiveItem(Index: Integer);
var
  DataItem: TDataItem;
begin
  if (Index = FDataItemList.Count) then Exit;
  DataItem := FDataItemList.Items[Index];
  lblPropertyName.Text := DataItem.Name;
  edtPropertyValue.Text := DataItem.Value;
  edtDatatype.Text := GetEnumName(TypeInfo(TInputType), Integer(DataItem.DataType));
end;

// Eingabe validieren und speichern beim Verlassen des Felds
procedure TForm1.edtPropertyValueExit(Sender: TObject);
begin
  SaveInputToItem;
end;

// Eingaben während der Eingabe einschränken (für Zahlen und Boolean)
procedure TForm1.edtPropertyValueKeyDown(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
var
  DataItem: TDataItem;
begin
  if (FItemIndex = FDataItemList.Count) then Exit;
  DataItem := FDataItemList.Items[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',#8]) then KeyChar := #0;
  end;
end;

// Speichern des Benutzereingabe in das gerade aktive DataItem
procedure TForm1.SaveInputToItem;
var
  DataItem: TDataItem;
  UserInput: string;
begin
  if (FItemIndex = FDataItemList.Count) then Exit;
  DataItem := FDataItemList.Items[FItemIndex];
  UserInput := Trim(edtPropertyValue.Text);

  if not ValidateInput(UserInput, DataItem.DataType) then
  begin
    ShowMessage(Format('Invalid input for %s. Expected a %s value.',
      [DataItem.Name, GetEnumName(TypeInfo(TInputType), Integer(DataItem.DataType))]));
    edtPropertyValue.SetFocus;
    Exit;
  end;
  DataItem.Value := UserInput;
end;

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

// JSON-Export
procedure TForm1.btnListAsJSONClick(Sender: TObject);
begin
  mmo1.Lines.Add(FDataItemList.AsJSON);
end;

end.
Zitat von Fortsetzung der Antwort:
"Ergänzende Hinweise:"

- Die leeren Methoden, nicht verwendeten Prozeduren und doppelten Aufrufe wurden entfernt.
- Die Item-Index-Kontrolle ist jetzt gekapselt.
- Namen und Groß-/Kleinschreibung der Controls und Variablen wurden „eng an Delphi-Konventionen“ angepasst.
- Alle Fehlerfälle werden geprüft; programmlogisch ist alles enger gekapselt.
- Die uses-Klausel müssen Sie nach Ihrer FMX- und eigenen Typ-Definition ergänzen.

Falls Sie spezielle Anforderungen (z.B. weitere Fehlerbehandlung, evtl. Undo/Redo, komplexere Validierung oder Designs) benötigen: Bitte Bescheid geben!
Zitat von Frage:
Lässt sich nachfolgende Unit vereinfachen? Enthält sie Redundanzen o. ä.?
Delphi-Quellcode:
unit Unit_TDataModule;

interface

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

type
  // Enum to represent input types
  TInputType = (itString, itNumber, itBoolean);

  // Class representing individual data items
  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); overload;
    procedure ResetToDefault; // Resets the Value to DefaultValue
  end;

  // Class representing a list of data items
  TDataItemList = class(TObjectList<TDataItem>)
  private
    function GetAsJSON: string; // Returns JSON representation of the list
  public
    property AsJSON: string read GetAsJSON; // Read-only property to get JSON string

    procedure LoadFromStringList(AStringList: TStringList); // Load items from a string list
    procedure SaveToFile(const AFileName: string); // Save items to a JSON file
    procedure LoadFromFile(const AFileName: string); // Load items from a JSON file
  end;

implementation

{ TDataItem }

constructor TDataItem.Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
begin
  inherited Create;
  FName := AName;
  FDataType := ADataType;
  FDefaultValue := ADefaultValue;
  FValue := ''; // Initialize Value to unset (empty string)
end;

procedure TDataItem.ResetToDefault;
begin
  FValue := FDefaultValue; // Reset Value to the DefaultValue
end;

{ TDataItemList }

function TDataItemList.GetAsJSON: string;
var
  JSONArray: TJSONArray;
  JSONObject: TJSONObject;
  DataItem: TDataItem;
begin
  JSONArray := TJSONArray.Create;
  try
    // Iterate through the items and convert them to JSON
    for DataItem in Self do
    begin
      JSONObject := TJSONObject.Create;
      JSONObject.AddPair('Name', DataItem.Name);
      JSONObject.AddPair('DataType', GetEnumName(TypeInfo(TInputType), Integer(DataItem.DataType))); // Convert enum to string
      JSONObject.AddPair('Value', DataItem.Value);
      JSONObject.AddPair('DefaultValue', DataItem.DefaultValue);
      JSONArray.AddElement(JSONObject);
    end;

    Result := JSONArray.ToJSON; // Return the JSON string
  finally
    JSONArray.Free;
  end;
end;

procedure TDataItemList.LoadFromStringList(AStringList: TStringList);
var
  i: Integer;
  LineParts: TArray<string>;
  Name, DefaultValue: string;
  DataType: TInputType;

  function ParseDataType(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;

begin
  for i := 0 to AStringList.Count - 1 do
  begin
    LineParts := AStringList[i].Split(['|']);
    if Length(LineParts) <> 3 then
      raise Exception.CreateFmt('Invalid format in line %d: %s', [i + 1, AStringList[i]]);

    Name := LineParts[0];
    DataType := ParseDataType(LineParts[1]);
    DefaultValue := LineParts[2];

    // Add the item and set both DefaultValue and Value
    Self.Add(TDataItem.Create(Name, DataType, DefaultValue));
    Self.Last.Value := DefaultValue; // Initialize Value to DefaultValue
  end;
end;

procedure TDataItemList.SaveToFile(const AFileName: string);
begin
  // Save the JSON representation to a file
  TFile.WriteAllText(AFileName, AsJSON);
end;

procedure TDataItemList.LoadFromFile(const AFileName: string);
var
  JSONArray: TJSONArray;
  JSONObject: TJSONObject;
  JSONString: string;
  i: Integer;
  Name, DataTypeStr, Value, DefaultValue: string;
  DataType: TInputType;

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

begin
  // Load JSON string from file
  JSONString := TFile.ReadAllText(AFileName);

  // Parse JSON string
  JSONArray := TJSONObject.ParseJSONValue(JSONString) as TJSONArray;
  if not Assigned(JSONArray) then
    raise Exception.Create('Invalid JSON format in file.');

  try
    // Iterate through JSON array and populate the list
    for i := 0 to JSONArray.Count - 1 do
    begin
      JSONObject := JSONArray.Items[i] as TJSONObject;
      Name := JSONObject.GetValue<string>('Name');
      DataTypeStr := JSONObject.GetValue<string>('DataType');
      Value := JSONObject.GetValue<string>('Value');
      DefaultValue := JSONObject.GetValue<string>('DefaultValue');
      DataType := ParseDataType(DataTypeStr);

      // Add the item
      Self.Add(TDataItem.Create(Name, DataType, DefaultValue));
      Self.Last.Value := Value; // Set the current value
    end;
  finally
    JSONArray.Free;
  end;
end;

end.
Zitat von Antwort:
Ihre Unit ist bereits klar strukturiert und für den Zweck ordentlich aufgebaut – dennoch lassen sich ein paar "Redundanzen vermeiden", einige Methoden und Konstrukte "vereinfachen", und kleine Verbesserungen sind sinnvoll.
Hier folgt eine "optimierte und kommentierte Version" Ihrer Unit. Am Ende finden Sie eine "Zusammenfassung" der Änderungen und Vorschläge.
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
    constructor Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
    procedure ResetToDefault;
    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;
  end;

  TDataItemList = class(TObjectList)
  private
    function GetAsJSON: string;
    class function ParseDataType(const DataTypeStr: string): TInputType; static;
  public
    property AsJSON: string read GetAsJSON;
    procedure LoadFromStringList(AStringList: TStringList);
    procedure SaveToFile(const AFileName: string);
    procedure LoadFromFile(const AFileName: string);
  end;

implementation

{ TDataItem }

constructor TDataItem.Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
begin
  inherited Create;
  FName := AName;
  FDataType := ADataType;
  FDefaultValue := ADefaultValue;
  FValue := FDefaultValue; // Wert gleich beim Erzeugen auf Default setzen
end;

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

{ Hilfsfunktion für DataType-Parsing }

class function TDataItemList.ParseDataType(const DataTypeStr: string): TInputType;
begin
  // Erlaubt sowohl Enum-Namen als auch Klartext
  if SameText(DataTypeStr, 'Boolean') or SameText(DataTypeStr, 'itBoolean') then
    Result := itBoolean
  else if SameText(DataTypeStr, 'Number') or SameText(DataTypeStr, 'itNumber') then
    Result := itNumber
  else if SameText(DataTypeStr, 'String') or SameText(DataTypeStr, 'itString') then
    Result := itString
  else
    raise Exception.CreateFmt('Unknown data type: %s', [DataTypeStr]);
end;

{ TDataItemList }

function TDataItemList.GetAsJSON: string;
var
  JSONArray: TJSONArray;
  DataItem: TDataItem;
begin
  JSONArray := TJSONArray.Create;
  try
    for DataItem in Self do
      JSONArray.AddElement(TJSONObject.Create
        .AddPair('Name', DataItem.Name)
        .AddPair('DataType', GetEnumName(TypeInfo(TInputType), Ord(DataItem.DataType)))
        .AddPair('Value', DataItem.Value)
        .AddPair('DefaultValue', DataItem.DefaultValue)
      );
    Result := JSONArray.ToJSON;
  finally
    JSONArray.Free;
  end;
end;

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

    DataType := ParseDataType(LineParts[1]);
    // Konstruktor setzt Value gleich auf Default
    Self.Add(TDataItem.Create(LineParts[0], DataType, LineParts[2]));
  end;
end;

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

procedure TDataItemList.LoadFromFile(const AFileName: string);
var
  JSONArray: TJSONArray;
  DataItemJSON: TJSONObject;
  JSONString: string;
  i: Integer;
begin
  Self.Clear;

  JSONString := TFile.ReadAllText(AFileName);
  JSONArray := TJSONObject.ParseJSONValue(JSONString) as TJSONArray;
  if not Assigned(JSONArray) then
    raise Exception.Create('Invalid JSON format in file.');

  try
    for i := 0 to JSONArray.Count - 1 do
    begin
      DataItemJSON := JSONArray.Items[i] as TJSONObject;
      if not Assigned(DataItemJSON) then continue;
      Self.Add(TDataItem.Create(
        DataItemJSON.GetValue('Name'),
        ParseDataType(DataItemJSON.GetValue('DataType')),
        DataItemJSON.GetValue('DefaultValue')
      ));
      // Wert ggf. setzen
      Self.Last.Value := DataItemJSON.GetValue('Value', Self.Last.DefaultValue);
    end;
  finally
    JSONArray.Free;
  end;
end;

end.
Zitat von Fortsetzung der Antwort:
Was wurde VEREINFACHT und VERBESSERT?

1. "Konsistenz & Redundanzen"
- "ParseDataType" als Klassenmethode einmal zentral statt dupliziert.
- "Value" schon im Konstruktor auf den Default gesetzt ('FValue := FDefaultValue'), Initialisierung an anderer Stelle (z.B. nach 'Add') ist überflüssig.
- Beim Laden aus JSON: Wert wird direkt gesetzt, wenn vorhanden, sonst Default.

2. "String-Vergleiche beim Typ-Parsing"
- Akzeptiert jetzt auch 'itNumber', 'itBoolean' usw., wie sie beim JSON-Speichern per 'GetEnumName' entstehen.

3. "Aufräumen"
- Keine doppelten oder unnötigen lokalen Variablen/Schritte.
- '.Clear' auf der Liste vor jedem Ladevorgang (aus Datei/Strings), damit die Liste sich sauber neu befüllt.
- Verwendung von '.AddPair'-Chaining bei JSON (kürzer, übersichtlicher).

4. "Kommentare und Lesbarkeit"
- Nur noch da, wo sie Mehrwert bieten.

5. "Sonstige Kleinigkeiten"
- Fehlerbehandlung wie in Ihrem Original beibehalten.
- Keine leeren Methoden.

"Zusammenfassung"

"Redundanzen:"
- Separate ParseDataType-Implementierungen eliminiert.
- Keine doppelte Initialisierung von Value.

"Optimierung:"
- Zentrale Utility-Funktion für Typ-Parsing.
- Konstruktor setzt Value wie Default.
- JSON-Handling und Datenimport schlanker.

"Fazit:"
Der Code ist so noch kompakter, wartbarer und robuster.
Wenn Sie spezielle Wünsche haben (z.B. Delimiter-Option, weitere Datentypen): gerne melden!
Was mich stört ist die Nutzung von with, deshalb hab' ich die Units noch ohne with erstellen lassen:
Zitat von Frage:
Bei uns wird die Nutzung von with kategorisch abgelehnt. Könnten Sie bitte beide Units in Versionen ohne with zur Verfügung stellen?
Zitat von Antwort:
Natürlich! Hier sind die beiden Units jeweils komplett "ohne Verwendung des with-Statements".
Ich habe alle relevanten Codeabschnitte entsprechend angepasst.

# 1. "Unit_TDataModule" (Daten- und Listentypen)
'Bereits vorher wurde in dieser Unit kein' with 'verwendet. Zur Klarheit führe ich die aktuell optimierte Version dennoch explizit auf:'
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
    constructor Create(const AName: string; ADataType: TInputType; const ADefaultValue: string);
    procedure ResetToDefault;
    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;
  end;

  TDataItemList = class(TObjectList)
  private
    function GetAsJSON: string;
    class function ParseDataType(const DataTypeStr: string): TInputType; static;
  public
    property AsJSON: string read GetAsJSON;
    procedure LoadFromStringList(AStringList: TStringList);
    procedure SaveToFile(const AFileName: string);
    procedure LoadFromFile(const AFileName: string);
  end;

implementation

{ TDataItem }

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

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

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

function TDataItemList.GetAsJSON: string;
var
  JSONArray: TJSONArray;
  DataItem: TDataItem;
  Obj: TJSONObject;
begin
  JSONArray := TJSONArray.Create;
  try
    for DataItem in Self do
    begin
      Obj := TJSONObject.Create;
      Obj.AddPair('Name', DataItem.Name);
      Obj.AddPair('DataType', GetEnumName(TypeInfo(TInputType), Ord(DataItem.DataType)));
      Obj.AddPair('Value', DataItem.Value);
      Obj.AddPair('DefaultValue', DataItem.DefaultValue);
      JSONArray.AddElement(Obj);
    end;
    Result := JSONArray.ToJSON;
  finally
    JSONArray.Free;
  end;
end;

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

    DataType := ParseDataType(LineParts[1]);
    Self.Add(TDataItem.Create(LineParts[0], DataType, LineParts[2]));
  end;
end;

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

procedure TDataItemList.LoadFromFile(const AFileName: string);
var
  JSONArray: TJSONArray;
  DataItemJSON: TJSONObject;
  JSONString: string;
  i: Integer;
  Name, DataTypeStr, Value, DefaultValue: string;
begin
  Self.Clear;

  JSONString := TFile.ReadAllText(AFileName);
  JSONArray := TJSONObject.ParseJSONValue(JSONString) as TJSONArray;
  if not Assigned(JSONArray) then
    raise Exception.Create('Invalid JSON format in file.');

  try
    for i := 0 to JSONArray.Count - 1 do
    begin
      DataItemJSON := JSONArray.Items[i] as TJSONObject;
      if not Assigned(DataItemJSON) then continue;
      Name := DataItemJSON.GetValue('Name');
      DataTypeStr := DataItemJSON.GetValue('DataType');
      DefaultValue := DataItemJSON.GetValue('DefaultValue');
      Value := DataItemJSON.GetValue('Value', DefaultValue);

      Self.Add(TDataItem.Create(Name, ParseDataType(DataTypeStr), DefaultValue));
      Self.Last.Value := Value;
    end;
  finally
    JSONArray.Free;
  end;
end;

end.
Zitat von Fortsetzung der Antwort:
# 2. "StudyDatamodule" (UI-/Form-Unit, jetzt explizit ohne with)
Delphi-Quellcode:
unit StudyDatamodule;

interface

uses
  System.SysUtils, System.Classes, Math, FMX.Types, FMX.Controls, FMX.Forms,
  Unit_TDataModule; // Annahme: Ihre eigene Unit mit TDataItemList, TDataItem, TInputType

type
  TForm1 = class(TForm)
    mmo1: TMemo;
    btnInitList: TButton;
    edtPropertyValue: TEdit;
    lblPropertyName: TLabel;
    btnUp: TButton;
    btnDown: TButton;
    edtDatatype: TEdit;
    btnListAsJSON: TButton;
    procedure FormCreate(Sender: TObject);
    procedure btnUpClick(Sender: TObject);
    procedure btnDownClick(Sender: TObject);
    procedure edtPropertyValueExit(Sender: TObject);
    procedure edtPropertyValueKeyDown(Sender: TObject; var Key: Word;
      var KeyChar: Char; Shift: TShiftState);
    procedure btnListAsJSONClick(Sender: TObject);
  private
    FDataItemList: TDataItemList;
    FItemIndex: Integer;
    procedure SetItemIndex(AIndex: Integer);
    procedure DisplayActiveItem(Index: Integer);
    procedure SaveInputToItem;
    function ValidateInput(const Value: string; DataType: TInputType): Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R '.fmx}

procedure TForm1.FormCreate(Sender: TObject);
var
  StringList: TStringList;
  DataItem: TDataItem;
begin
  StringList := TStringList.Create;
  FDataItemList := TDataItemList.Create(True);
  try
    // Demo-Daten
    StringList.Add('EnableLogging|Boolean|true');
    StringList.Add('MaxLogFileSize|Number|1048576');
    StringList.Add('LogFilePath|String|C:\Logs\app.log');
    StringList.Add('EnableAutoSave|Boolean|true');
    StringList.Add('AutoSaveInterval|Number|10');
    StringList.Add('Theme|String|dark');
    StringList.Add('ShowNotifications|Boolean|true');
    StringList.Add('MaxRetries|Number|3');
    StringList.Add('RetryDelay|Number|5');
    StringList.Add('EnableEncryption|Boolean|true');
    StringList.Add('EncryptionKey|String|default_key');
    StringList.Add('AllowGuestAccess|Boolean|false');
    StringList.Add('DefaultLanguage|String|en');
    StringList.Add('TimeoutDuration|Number|30');
    StringList.Add('EnableDebugMode|Boolean|false');

    FDataItemList.LoadFromStringList(StringList);

    // Ausgabe zur Kontrolle
    for DataItem in FDataItemList do
      mmo1.Lines.Add(Format('Name: %s, DataType: %s, DefaultValue: %s',
        [DataItem.Name, GetEnumName(TypeInfo(TInputType), Ord(DataItem.DataType)), DataItem.DefaultValue]));

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

  finally
    StringList.Free;
  end;
end;

procedure TForm1.SetItemIndex(AIndex: Integer);
begin
  if FDataItemList.Count = 0 then Exit;
  FItemIndex := EnsureRange(AIndex, 0, FDataItemList.Count - 1);
  DisplayActiveItem(FItemIndex);
end;

procedure TForm1.btnUpClick(Sender: TObject);
begin
  SetItemIndex(FItemIndex + 1);
end;

procedure TForm1.btnDownClick(Sender: TObject);
begin
  SetItemIndex(FItemIndex - 1);
end;

procedure TForm1.DisplayActiveItem(Index: Integer);
var
  DataItem: TDataItem;
  DataTypeName: string;
begin
  if (Index = FDataItemList.Count) then Exit;
  DataItem := FDataItemList.Items[Index];
  DataTypeName := GetEnumName(TypeInfo(TInputType), Ord(DataItem.DataType));
  lblPropertyName.Text := DataItem.Name;
  edtPropertyValue.Text := DataItem.Value;
  edtDatatype.Text := DataTypeName;
end;

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

procedure TForm1.edtPropertyValueKeyDown(Sender: TObject; var Key: Word;
  var KeyChar: Char; Shift: TShiftState);
var
  DataItem: TDataItem;
begin
  if (FItemIndex = FDataItemList.Count) then Exit;
  DataItem := FDataItemList.Items[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',#8]) then KeyChar := #0;
  end;
end;

procedure TForm1.SaveInputToItem;
var
  DataItem: TDataItem;
  UserInput: string;
begin
  if (FItemIndex = FDataItemList.Count) then Exit;
  DataItem := FDataItemList.Items[FItemIndex];
  UserInput := Trim(edtPropertyValue.Text);

  if not ValidateInput(UserInput, DataItem.DataType) then
  begin
    ShowMessage(Format('Invalid input for %s. Expected a %s value.',
      [DataItem.Name, GetEnumName(TypeInfo(TInputType), Ord(DataItem.DataType))]));
    edtPropertyValue.SetFocus;
    Exit;
  end;
  DataItem.Value := UserInput;
end;

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

procedure TForm1.btnListAsJSONClick(Sender: TObject);
begin
  mmo1.Lines.Add(FDataItemList.AsJSON);
end;

end.
Zitat von Fortsetzung der Antwort:
## Hinweise

- "with wurde nirgends verwendet."
- Alle Object-Properties werden nun immer explizit angesprochen.
- Die Units sind so sofort in Projekten ohne with-Verwendung einsetzbar.

Falls Sie weitere Wünsche zur Codegestaltung haben, geben Sie einfach Bescheid!
Leider hab' ich nur Delphi 7 und kann von daher nicht prüfen, ob die Überarbeitung von Perplexity.ai sinnvoll, kompilierbar und fehlerfrei ist.
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.493 Beiträge
 
Delphi 12 Athens
 
#5

AW: KI Code : Editor für Daten

  Alt Heute, 11:33
Warum nicht gleich ein Property-Editor für eine zu übergebenes Datenobjekt?
Default-Werte mit einer Clear-Methode des Objekts vorab setzen.
Die Property per RTTI bestimmen, lesen und setzen.
Damit spart man die ganzen zusätzlichen Definitionen und kann jedes Datenobjekt mit einer Clear-Methode bearbeiten.
  Mit Zitat antworten Zitat
bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.153 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: KI Code : Editor für Daten

  Alt Heute, 12:50
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?
  Mit Zitat antworten Zitat
bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.153 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: KI Code : Editor für Daten

  Alt Heute, 12:57
Ich habe mir die GUI auch mithilfe der KI und iterativem Fragen erstellen lassen. In der Anlage meine 'Working Version' und die KI-Variante.
Angehängte Grafiken
Dateityp: png AI_GUI.png (55,3 KB, 19x aufgerufen)
Dateityp: png Manual_GUI.png (43,1 KB, 18x aufgerufen)
  Mit Zitat antworten Zitat
Delphi.Narium

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

AW: KI Code : Editor für Daten

  Alt Heute, 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
Benutzerbild von Sherlock
Sherlock

Registriert seit: 10. Jan 2006
Ort: Offenbach
3.821 Beiträge
 
Delphi 12 Athens
 
#9

AW: KI Code : Editor für Daten

  Alt Heute, 14:37
Ich kann mich nur wiederholen: Interessant ist an dieser Stelle eigentlich nur der Prompt, und gegebenenfalls die Verfeinerungen, die noch formuliert wurden. Der Wall of Code ist mMn irrelevant und für die Allgemeinheit zählt nur, ob du selbst mit dem Ergebnis zufrieden bist. Vorschlag zum letzten Punkt: Pack doch alles in ein Zip (inklusive Kompilat) und jeder kann sich so viel davon ansehen, wie er mag.
Oliver
Geändert von Sherlock (Morgen um 16:78 Uhr) Grund: Weil ich es kann
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:11 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