Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Ini-Einstellung umwandeln für Komponente (https://www.delphipraxis.net/167046-ini-einstellung-umwandeln-fuer-komponente.html)

Helmi 10. Mär 2012 22:18

Ini-Einstellung umwandeln für Komponente
 
Hallo,

ich steh gerade auf dem Schlauch.

Ich hab eine Ini-Datei in der man Einstellungen für die serielle Schnittstelle machen kann.

Als Komponente nutz ich die VAComm von TMS Software.
Dort wird z. b. Stopbit als Aufzählung (Type) benutzt.

Nun möcht ich aber in der Ini-Datei eine ganz normale Eingabe wie z. B.:
Code:
[RS232]
Parity=EVEN
Stopbit=1
Leider muss ich aber dann die Eingaben "umwandeln", bevor ich die Komponente beschreiben kann.

Momentan mach ich das in einer Function und auf String basierend.
Delphi-Quellcode:
function TMaskForm.COM_Auswahl(Auswahl: TCOM_Auswahl; S: String): Variant;
begin
  //
  S := AnsiLowerCase(S);

  case Auswahl of
    COM_Databit: begin
                    If S = '4' then
                      Result := db4;

                    If S = '5' then
                      Result := db5;

                    If S = '6' then
                      Result := db6;

                    If S = '7' then
                      Result := db7;

                    If S = '8' then
                      Result := db8;
                  end;
    COM_Stopbit: begin
                    If S = '1' then
                      Result := sb1;

                    If S = '1.5' then
                      Result := sb15;

                    If S = '2' then
                      Result := sb2;
                  end;
    COM_Parity:  begin
                    If S = 'none' then
                      Result := paNone;

                    If S = 'even' then
                      Result := paEven;

                    If S = 'mark' then
                      Result := paMark;

                    If S = 'odd' then
                      Result := paOdd;

                    If S = 'space' then
                      Result := paSpace;
                  end;
  end;
end;
Nur gefällt mir das nicht wirklich!

Gibt es denn vielleicht eine andere Möglichkeit?

Was mir noch einfallen würde, das wäre die Auswahl als Index auszulesen um dann mit einem Cast auf die Auswahl die Komponente zu beschreiben.

Sir Rufo 10. Mär 2012 22:25

AW: Ini-Einstellung umwandeln für Komponente
 
Delphi-Quellcode:
const
  cDataBit : array [TDataBit?] of string = ( '4', '6', ...);
so definieren und dann die Array Werte vergleichen

himitsu 10. Mär 2012 23:21

AW: Ini-Einstellung umwandeln für Komponente
 
Über die RTTI kannst du diese ENUMs auch direkt in Strings umwandeln und zurück.

Oder du nimmst einfache Casts ala Ord, und konvertierst die ENUMs in Integer.

Furtbichler 11. Mär 2012 07:32

AW: Ini-Einstellung umwandeln für Komponente
 
Converterklassen bauen.

Delphi-Quellcode:
uses StrUtils;

Type
  TParityConverter = Class
  Private
    Class Const
      ParitySettings = Array [paEven..paSpace] Of String = ('even','mark','odd','space');
  Public
    Class Function FromString (setting : String) : TParity;
    Class Function ToString (setting : TParity) : String;
  End;

Class Function TParityConverter.FromString (setting : String) : TParity;
Var
  p : Integer;

Begin
  p := IndexText (setting, ParitySettings);
  if p=-1 then
    Raise EConvertException.CreateFmt('Unknown parity setting %s', [setting])
  else
    result := TParity(p);
End;

Class Function TParityConverter.ToString (setting : TParity) : String;
Begin
  Try
    Result := ParritySettings[Ord(setting)];
  Except
    Raise EConvertException.CreateFmt('Invalid parity (%d)',[setting]);
  End
End;

Bummi 11. Mär 2012 07:45

AW: Ini-Einstellung umwandeln für Komponente
 
wobei Sir Rufo's Ansatz mir hier am schlanksten erscheint ...

stahli 11. Mär 2012 10:46

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von himitsu (Beitrag 1155897)
Über die RTTI kannst du diese ENUMs auch direkt in Strings umwandeln und zurück.
Oder du nimmst einfache Casts ala Ord, und konvertierst die ENUMs in Integer.

So habe ich das gemacht. Das ist nicht der schnellste Weg und etwas aufwendig umzusetzen, aber es ist dann dafür universell einsetzbar für alle Propertys.
Falls jemand mal nachschauen möchte:

Delphi-Quellcode:
procedure TodProp.LoadPropValue(const od: Tod; PropName, PropValue: String);
var
  Context: TRttiContext;
  RttiType: TRttiType;
  PropInfo: TRttiProperty;
  F: Boolean;
  Attr: TCustomAttribute;
  Value: TValue;
  InstOd: TInstOd;
  _od, iod: Tod;
  _PropName: String;
  V: Integer;
begin
  if (not Assigned(od)) or (PropName = '') then
    Exit;

  _od := od;
  _PropName := PropName;
  CorrectSubOd(_od, _PropName);
  if not Assigned(_od) then
    Exit;

  Context := TRttiContext.Create;
  RttiType := Context.GetType(_od.ClassType);

  if Assigned(RttiType) then
    begin
      for PropInfo in RttiType.GetProperties do
        begin
          if PropInfo.Name <> _PropName then
            Continue;
          F := False;
          for Attr in PropInfo.GetAttributes do
            begin
              if Attr is AttrOd then
                F := True;
            end;
          if F then
            begin
              Value := TValue.Empty;
              case PropInfo.PropertyType.TypeKind of
                tkUnknown:
                  ;
                tkInteger:
                  Value := TValue.From(StrToIntDef(PropValue, 0));
                tkChar:
                  ;
                tkEnumeration: // <<<<<================================= HIER
                  if TryStrToInt(PropValue, V) then
                    Value := TValue.FromOrdinal(PropInfo.PropertyType.Handle, V)
                  else
                    Value := TValue.FromOrdinal(PropInfo.PropertyType.Handle, GetEnumValue(PropInfo.PropertyType.Handle, PropValue));
                tkFloat:
                  if PropInfo.GetValue(_od).IsType<TDateTime> then
                    Value := TValue.From(StrToDateTimeDef(PropValue, 0))
                  else if PropInfo.GetValue(_od).IsType<TTime> then
                    Value := TValue.From(StrToTimeDef(PropValue, 0))
                  else
                    Value := TValue.From(StrToFloatDef(PropValue, 0));
                tkString:
                  Value := TValue.From(PropValue);
                tkSet:
                  ;
                tkClass:
                  begin
                    iod := FoundOd(PatternToId(PropValue));
                    if (Assigned(iod)) or (AssignInstOdFlag) then
                      begin
                        Value := iod;
                      end
                    else
                      begin
                        InstOd := TInstOd.Create;
                        InstOd.od := _od;
                        InstOd.PropName := _PropName;
                        InstOd.Id := PropValue;
                        InstOdList.Add(InstOd);
                      end;
                  end;
                tkMethod:
                  ;
                tkWChar:
                  ;
                tkLString:
                  ;
                tkWString:
                  ;
                tkVariant:
                  ;
                tkArray:
                  ;
                tkRecord:
                  ;
                tkInterface:
                  ;
                tkInt64:
                  ;
                tkDynArray:
                  ;
                tkUString:
                  Value := TValue.From(PropValue);
                tkClassRef:
                  ;
                tkPointer:
                  ;
                tkProcedure:
                  ;
              end;
              if not Value.IsEmpty then
                PropInfo.SetValue(_od, Value);
            end;
        end;
    end;

  Context.Free;
end;

function TodProp.GetPropValue(const od: Tod; PropName: String): String;
var
  PropValue: String;
  Context: TRttiContext;
  RttiType: TRttiType;
  PropInfo: TRttiProperty;
  F: Boolean;
  Attr: TCustomAttribute;
  Value: TValue;
  O: TObject;
  _od: Tod;
  _PropName: String;
begin
  Result := '';

  if (not Assigned(od)) or (PropName = '') then
    Exit;

  if Lowercase(PropName) = Lowercase('odId') then
    Exit(od.odId);

  _od := od;
  _PropName := PropName;
  CorrectSubOd(_od, _PropName);
  if not Assigned(_od) then
    Exit;

  Context := TRttiContext.Create;
  RttiType := Context.GetType(_od.ClassType);

  if Assigned(RttiType) then
    begin
      for PropInfo in RttiType.GetProperties do
        begin
          if PropInfo.Name <> _PropName then
            Continue;
          F := False;
          for Attr in PropInfo.GetAttributes do
            begin
              if Attr is AttrOd then
                F := True;
            end;
          if F then
            begin
              PropValue := '';
              Value := PropInfo.GetValue(_od);
              case Value.Kind of
                tkUnknown:
                  ;
                tkInteger:
                  if Value.AsInteger = 0 then
                    PropValue := ''
                  else
                    PropValue := inttostr(Value.AsInteger);
                tkChar:
                  ;
                tkEnumeration: // <<<<<================================= HIER
                  if Value.AsOrdinal = 0 then
                    PropValue := ''
                  else
                    PropValue := GetEnumName(Value.TypeInfo, Value.AsOrdinal);
                tkFloat:
                  if Value.AsExtended = 0 then
                    PropValue := ''
                  else if Value.IsType<TDateTime> then
                    PropValue := DateTimeToStr(Value.AsExtended)
                  else if Value.IsType<TTime> then
                    PropValue := TimeToStr(Value.AsExtended)
                  else
                    PropValue := FloatToStr(Value.AsExtended);
                tkString:
                  PropValue := Value.AsString;
                tkSet:
                  ;
                tkClass:
                  begin
                    O := Value.AsObject;
                    try
                      if (O <> nil) and (O is Tod) then
                        PropValue := (O as Tod).odId;
                    except
                      PropValue := '';
                    end;
                  end;
                tkMethod:
                  ;
                tkWChar:
                  ;
                tkLString:
                  ;
                tkWString:
                  ;
                tkVariant:
                  ;
                tkArray:
                  ;
                tkRecord:
                  ;
                tkInterface:
                  ;
                tkInt64:
                  ;
                tkDynArray:
                  ;
                tkUString:
                  PropValue := Value.AsString;
                tkClassRef:
                  ;
                tkPointer:
                  ;
                tkProcedure:
                  ;
              end;
              if PropValue <> '' then
                Result := PropValue;
            end;
        end;
    end;

  Context.Free;
end;

Sir Rufo 11. Mär 2012 10:58

AW: Ini-Einstellung umwandeln für Komponente
 
ist ja nicht gerade DRY ;)

Leg dir doch eine interne Procedure an, die lesen und schreiben kann mit einem zusätzlichen Parameter (lesend/schreibend). Mit deinen vorhandenen procedures rufst du dann nur noch diese interne auf und schon ist es DRY und KISS ;)

Helmi 11. Mär 2012 11:54

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Sir Rufo (Beitrag 1155892)
Delphi-Quellcode:
const
  cDataBit : array [TDataBit?] of string = ( '4', '6', ...);

Ich steh irgenwie auf dem Schlauch.

Die Idee mit dem Array ist gut.

Ich habs folgendermaßen gemacht:
Delphi-Quellcode:
cDataBit: array [0..4] of string = ('4', '5', '6', '7', '8');
und frag dann so ab:
Delphi-Quellcode:
for i := low(cDataBit) to high(cDataBit) do
  If cDataBit[i] = S then
    begin
      Result := TVaDatabits(i);
      break;
    end;
Ich wollt eigentlich Sir Rufo´s Idee übernehmen und den Typ ins Array übernehmen, also so:
Delphi-Quellcode:
cDataBit: array [TVaDataBits] of string = ('4', '5', '6', '7', '8');
.


Nur dann erhalte ich bei der for-Schleife:
Delphi-Quellcode:
for i := low(cDataBit) to high(cDataBit) do
.
folgende Fehlermeldung:
Zitat:

[DCC Fehler] Main.pas(444): E2010 Inkompatible Typen: 'Integer' und 'TVaDatabits'
TVaDataBits ist so deklariert:
Delphi-Quellcode:
TVaDatabits = (db4, db5, db6, db7, db8);

Bummi 11. Mär 2012 12:25

AW: Ini-Einstellung umwandeln für Komponente
 
@Helmi

der Zugriff bei Sir Rufos's Variante ist viel einfacher
Delphi-Quellcode:
Const
c:Array[TPrintScale] of String=('None', 'Proportional', 'PrintToFit') ;
procedure TForm1.Button1Click(Sender: TObject);
begin
    Caption := c[poPrintToFit];
end;

Helmi 11. Mär 2012 12:46

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Bummi (Beitrag 1155979)
@Helmi

der Zugriff bei Sir Rufos's Variante ist viel einfacher
Delphi-Quellcode:
Const
c:Array[TPrintScale] of String=('None', 'Proportional', 'PrintToFit') ;
procedure TForm1.Button1Click(Sender: TObject);
begin
    Caption := c[poPrintToFit];
end;

Ich glaube da gibt´s ein Missverständnis.

Ich habe einen String, den ich als Auswahl nutzen möchte, nicht anders rum.

Furtbichler 11. Mär 2012 12:48

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Bummi (Beitrag 1155926)
wobei Sir Rufo's Ansatz mir hier am schlanksten erscheint ...

Nun ja, der eine schreibt eine Zeile, der andere eine Klasse. Der Eine schreibt nur eine Richtung (Enum=>String), der andere beide Richtungen. Klar, das es bei dem einen schlanker erscheint.

Noch schlanker geht es so:

Delphi-Quellcode:
//Schreiben
MyIni.WriteInteger ('COM','Parity',Ord(MyComport.Parity));

//Lesen
MyComPort.Parity := TParity(MyIni.ReadInteger ('COM','Parity',0));

Helmi 11. Mär 2012 12:59

AW: Ini-Einstellung umwandeln für Komponente
 
so würd ich aber nur den Index der Auswahl in der Ini-Datei haben
Ich möchte aber in der Ini-Datei angeben, z. B. Parity=Even und dann
im Code auf die Com-Komponente
Delphi-Quellcode:
Parity := paEven
schreiben

stahli 11. Mär 2012 13:06

AW: Ini-Einstellung umwandeln für Komponente
 
Warum willst Du denn nicht einfach
Delphi-Quellcode:
Parity=paEven
in Deine Ini schreiben und auf die ganze "Übersetzung" verzichten.
So macht es ja die IDE auch in ihren Formular-Dateien.

Bummi 11. Mär 2012 13:07

AW: Ini-Einstellung umwandeln für Komponente
 
@Furtbichler
wobei es dann nicht mehr bei allem lesbar ist und die RTTI-Variante näher dran wäre.
Delphi-Quellcode:
Function GetIndexOf(Const Find:String;a:Array of String;Highest:Integer;Default:Integer=0):Integer;
var
  I: Integer;
begin
   Result := Default;
   for I := 0 to Highest do
     if a[i] = Find then Result := i;
end;


 ps := TPrintScale(GetIndexOf('None',c,Ord(poPrintToFit),Ord(poProportional)));

Helmi 11. Mär 2012 13:13

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Bummi (Beitrag 1155995)
Delphi-Quellcode:
Function GetIndexOf(Const Find:String;a:Array of String;Highest:Integer;Default:Integer=0):Integer;
var
  I: Integer;
begin
   Result := Default;
   for I := 0 to Highest do
     if a[i] = Find then Result := i;
end;


 ps := TPrintScale(GetIndexOf('None',c,Ord(poPrintToFit),Ord(poProportional)));

So mach ich es jetzt!

Zitat:

Zitat von stahli (Beitrag 1155994)
Warum willst Du denn nicht einfach
Delphi-Quellcode:
Parity=paEven
in Deine Ini schreiben und auf die ganze "Übersetzung" verzichten.
So macht es ja die IDE auch in ihren Formular-Dateien.

Und wie soll ich von deim String "paEven" den ich aus der Ini lese auf den Index von TVaParity kommen, z. B.?

himitsu 11. Mär 2012 13:20

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Helmi (Beitrag 1155997)
Und wie soll ich von deim String "paEven" den ich aus der Ini lese auf den Index von TVaParity kommen, z. B.?

Delphi-Quellcode:
Const
  c:Array[TPrintScale] of String=('None', 'Proportional', 'PrintToFit') ;
Entweder du gehts dein Array durch und schaust wo sich der String versteckt.

Oder, wenn man den ENUM über die RTTI in einen String umgewandelt hat, dann wandelt man den String über die RTTI wieder in den Enum (Integer+Cast) zurück.

Helmi 11. Mär 2012 13:29

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von himitsu (Beitrag 1155999)
Zitat:

Zitat von Helmi (Beitrag 1155997)
Und wie soll ich von deim String "paEven" den ich aus der Ini lese auf den Index von TVaParity kommen, z. B.?

Delphi-Quellcode:
Const
  c:Array[TPrintScale] of String=('None', 'Proportional', 'PrintToFit') ;
Entweder du gehts dein Array durch und schaust wo sich der String versteckt.

Ich glaub ich hab ein Déjà-vu und zwar mit Post 8 dieses Threads.

Zitat:

Zitat von himitsu (Beitrag 1155999)
Oder, wenn man den ENUM über die RTTI in einen String umgewandelt hat, dann wandelt man den String über die RTTI wieder in den Enum (Integer+Cast) zurück.

Das klingt interessant - mal schauen wie das funktioniert...

Furtbichler 11. Mär 2012 13:30

AW: Ini-Einstellung umwandeln für Komponente
 
Zum Mitschreiben:
Delphi-Quellcode:
 
uses TypInfo;

MyCom.Parity := TParity(GetEnumValue(TypeInfo(TParity),myParityStringFromINI));
MyIni.WriteString('COM','Parity', GetEnumName(TypeInfo(TParity), Integer(MyCOM.Parity)) ;

stahli 11. Mär 2012 13:54

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Helmi (Beitrag 1156003)
Das klingt interessant - mal schauen wie das funktioniert...

Genau wie Furtbichler es zeigt. :-)

Meine (aufwendigere) Methode funktioniert dagegen mit allen Enum-Objektpropertys und ermittelt den richtigen Typ dynamisch.
Wenn Du den Typ selbst kennst, ist es natürlich schneller und einfacher, den Typ direkt festzulegen.

Helmi 11. Mär 2012 14:18

AW: Ini-Einstellung umwandeln für Komponente
 
Zitat:

Zitat von Furtbichler (Beitrag 1156004)
Delphi-Quellcode:
 
uses TypInfo;

MyCom.Parity := TParity(GetEnumValue(TypeInfo(TParity),myParityStringFromINI));
MyIni.WriteString('COM','Parity', GetEnumName(TypeInfo(TParity), Integer(MyCOM.Parity)) ;

Dank dir!

Und Dank euch allen!


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:26 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