Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Combobox aus *.ini laden (https://www.delphipraxis.net/173569-combobox-aus-%2A-ini-laden.html)

volvox 4. Mär 2013 18:25

Combobox aus *.ini laden
 
Hallo zusammen,

ich möchte gerne den Inhalt einer Combobox in einer INI-Datei speichern und wieder laden.
Im Gegensatz zu den meisten anderen Themen hier im Forum, möchte ich alle Werte der Combobox speichern und laden.
Da der Nutzer den Inhalt der Combobox nach Bedarf ändern kann, weiß ich nie wie viele Items in derCombobox sind.


So schreibe ich in die Ini. Das klappt auch.
Delphi-Quellcode:
for i:=0 to (cbbOE.items.count -1) do   // Inhalt der Combobox in Ini schreiben
   begin
     with TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini')) do
       begin
         WriteString('Organisationseinheit', IntToStr(i), cbbOE.items[i]);
         Free;
       end;
   end;

Beim Lesen der Ini und Beschreiben der Combobox habe ich jetzt das Problem, dass ich nicht weiß wie viele Items die Combobox haben wird.
Wenn ich die Combobox standardmaäßg leer lasse, und einfach mit der Ini beschreibe, kommt eine Fehlermeldung, sinngemäß 'Maximale Anzahl an Items überschritten' und das Programm stürzt ab.

Meine Momentane, nicht sehr elegante Lösung sieht so aus:

Delphi-Quellcode:
for i:=0 to 99 do   // 
   begin
     with TIniFile.Create(ChangeFileExt(Application.ExeName, '.ini')) do
       begin
         cbbOE.items[i]:=ReadString('Organisationseinheit', IntToStr(i),'');
         Free;
       end;
   end;
Ich erzeuge mit also 100 freie Item-Plätze und beschreibe diese dann mit der Ini. Da ich aber in der Regel nur 10-30 Plätze benötige, habe ich jede Menge leere Felder in der Combobox.

Wie kann ich das eleganter lösen.

Notfalls hatte ich mit überlegt über die for schleife nach leeren Feldern zu suchen und diese dann wieder zu löschen. Gefällt mir nicht und hat programmiertechnisch nicht geklappt.

Sowas wie
Delphi-Quellcode:
if cbbOE.items[i]='' then cbbOE.Items[i].Delete;
ging natürlich nicht.

Jetzt nochmal die Frage:
Wie kann ich die Combo beschreiben ohne die maximale Anzahl der Items zu überschreiten und ohne leere Felder zu haben?


Danke im Vorraus!

zeras 4. Mär 2013 18:30

AW: Combobox aus *.ini laden
 
Beim Laden prüfst du, ob es den Eintrag in der INI gibt. Wenn nicht, dann brauchst du auch die Combobox nicht füllen. Eintragen der Einträge in der Box dann über Items.Add und vorher mit Items.Clear den Inhalt erst mal löschen. Nicht über den Index eintragen, da du ja selber gemerkt hast, dass du dann eine Exception bekommst.

Popov 4. Mär 2013 18:41

AW: Combobox aus *.ini laden
 
Ich hab mal sowas in der Art als Tipp in DF gepostet. Vielleicht bringt es was:

http://www.entwickler-ecke.de/topic_...n_21553,0.html

uligerhardt 4. Mär 2013 18:42

AW: Combobox aus *.ini laden
 
Ich würde mir mal Delphi-Referenz durchsuchenTIniFile.ReadSection und/oder Delphi-Referenz durchsuchenTIniFile.ReadSectionValues anschauen.

volvox 4. Mär 2013 18:47

AW: Combobox aus *.ini laden
 
Ja, "Add" und "Clear". Ich merke, dass ich lange nicht mit Delphi gearbeitet habe. Der Post von Popov sieht auch gut aus. Danke

Sir Rufo 4. Mär 2013 19:10

AW: Combobox aus *.ini laden
 
Weil ich es gerade hier so fertig herumliegen habe:

Eine Unit mit der man alle
Delphi-Quellcode:
published
Properties (rw) einer beliebigen Instanz, eine TCollection und TStrings in eine ini-Datei schreiben und wieder auslesen kann.

Die Handhabung ist recht einfach:
Delphi-Quellcode:
var
  MyObj : TMyObject;
  MyIni : TIniFile;
begin
  ...

  // Instanzen von MyIni und MyObj müssen natürlich vorhanden sein
 
  // schreiben
  StoreObj( MyObj, MyIni, 'MyObject' );

  // lesen
  LoadObj( MyObj, MyIni, 'MyObject' );

end;
Eine TStringList würde dann wie folgt gespeichert werden
Code:
[MyObject\Strings]
0=Zeile1
1=Zeile2
2=Zeile3
BTW: Man könnte damit auch die komplette ComboBox abspeichern ... aber dann kommt halt alles andere auch mit ;)

Delphi-Quellcode:
unit IniObjStore;

interface

uses
  Classes, IniFiles;

procedure StoreObj( const Instance : TObject; const Ini : TCustomIniFile; const Section : string );
procedure LoadObj( const Instance : TObject; const Ini : TCustomIniFile; const Section : string );

implementation

uses
  SysUtils,
  TypInfo;

const
  C_Sec_Delim = '\';

procedure StoreObj( const Instance : TObject; const Ini : TCustomIniFile; const Section : string );
  procedure EraseSection;
  var
    LSubSections : TStrings;
    LIdx :        Integer;
  begin
    LSubSections := TStringList.Create;
    try
      Ini.ReadSubSections( Section, LSubSections, True );
      for LIdx := 0 to Pred( LSubSections.Count ) do
        Ini.EraseSection( Section + C_Sec_Delim + LSubSections[LIdx] );
    finally
      LSubSections.Free;
    end;
    Ini.EraseSection( Section );
  end;

var
  LPropName, LPropValue : string;
  LPropInfo :            PPropInfo;
  LPropCount :           Integer;
  LPropList :            PPropList;
  LPropType :            PPTypeInfo;
  LIdx :                 Integer;
  LObj :                 TObject;
  LItem :                TCollectionItem;
begin
  EraseSection;

  if not Assigned( Instance )
  then
    Exit;

  // TCollection-Handling
  if Instance is TCollection
  then
    for LItem in ( Instance as TCollection ) do
      // recursive call
      StoreObj( LItem, Ini, Section + C_Sec_Delim + IntToStr( LItem.Index ) );

  if Instance is TStrings
  then
    with ( Instance as TStrings ) do
      for LIdx := 0 to Pred( Count ) do
        Ini.WriteString( Section + C_Sec_Delim + 'Strings', IntToStr( LIdx ), Strings[LIdx] );

  // examine all published properties
  LPropCount := GetPropList( PTypeInfo( Instance.ClassInfo ), LPropList );
  if LPropCount > 0
  then
    try

      for LIdx := 0 to Pred( LPropCount ) do
        begin
          LPropInfo := LPropList^[LIdx];
          LPropType := LPropInfo^.PropType;

          if LPropType^.Kind = tkMethod
          then
            Continue;

          // WriteOnly-Property
          if ( LPropInfo.GetProc = nil )
          then
            Continue;

          LPropName := string( LPropInfo.Name );

          case LPropType^.Kind of
            tkClass :
              begin

                LObj := GetObjectProp( Instance, LPropName );
                // recursive call
                StoreObj( LObj, Ini, Section + C_Sec_Delim + LPropName );

              end;
            tkInteger, tkChar, tkEnumeration, tkFloat, tkString, tkSet, tkWChar, tkLString, tkWString, tkInt64, tkUString :
              begin

                // ReadOnly-Property
                if ( LPropInfo.SetProc = nil )
                then
                  Continue;

                LPropValue := GetPropValue( Instance, LPropName );
                Ini.WriteString( Section, LPropName, LPropValue );
              end;
          end;

        end;

    finally
      FreeMem( LPropList );
    end;

end;

procedure LoadObj( const Instance : TObject; const Ini : TCustomIniFile; const Section : string );
var
  LPropName, LPropValue : string;
  LPropInfo :            PPropInfo;
  LPropCount :           Integer;
  LPropList :            PPropList;
  LPropType :            PPTypeInfo;
  LIdx :                 Integer;
  LObj :                 TObject;
begin
  if not Assigned( Instance )
  then
    Exit;

  // TCollection-Handling
  if Instance is TCollection
  then
    with Instance as TCollection do
      begin
        Clear;
        LIdx := 0;
        while Ini.SectionExists( Section + C_Sec_Delim + IntToStr( LIdx ) ) do
          begin
            // recursive call
            LoadObj( Add, Ini, Section + C_Sec_Delim + IntToStr( LIdx ) );
            Inc( LIdx );
          end;
      end;

  if Instance is TStrings
  then
    with Instance as TStrings do
      begin
        BeginUpdate;
        try
          Clear;
          LIdx := 0;

          while Ini.ValueExists( Section + C_Sec_Delim + 'Strings', IntToStr( LIdx ) ) do
            begin
              Add( Ini.ReadString( Section + C_Sec_Delim + 'Strings', IntToStr( LIdx ) ) );
              Inc( LIdx );
            end;
        finally
          EndUpdate;
        end;
      end;

  // examine all published properties
  LPropCount := GetPropList( PTypeInfo( Instance.ClassInfo ), LPropList );
  if LPropCount > 0
  then
    try

      for LIdx := 0 to Pred( LPropCount ) do
        begin
          LPropInfo := LPropList^[LIdx];
          LPropType := LPropInfo^.PropType;

          if LPropType^.Kind = tkMethod
          then
            Continue;

          LPropName := string( LPropInfo.Name );

          case LPropType^.Kind of
            tkClass :
              begin

                LObj := GetObjectProp( Instance, LPropName );
                // recursive call
                LoadObj( LObj, Ini, Section + C_Sec_Delim + LPropName );

              end;
            tkInteger, tkChar, tkEnumeration, tkFloat, tkString, tkSet, tkWChar, tkLString, tkWString, tkInt64, tkUString :
              begin

                // ReadOnly-Property
                if LPropInfo.SetProc = nil
                then
                  Continue;

                LPropValue := GetPropValue( Instance, LPropName );
                LPropValue := Ini.ReadString( Section, LPropName, LPropValue );
                SetPropValue( Instance, LPropName, LPropValue );
              end;
          end;

        end;

    finally
      FreeMem( LPropList );
    end;

end;

end.


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