Einzelnen Beitrag anzeigen

bernhard_LA

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

KI Code : Editor für Daten

  Alt 30. Jul 2025, 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