Entwickler-Ecke

Open Source Units - Unit zum einfachen Verändern der Sprache zur Laufzeit


AXMD - Sa 19.03.05 20:04
Titel: Unit zum einfachen Verändern der Sprache zur Laufzeit
Moin :)!

Im Zuge der Entwicklung des [url=http://www.dustsigns.de.vu]DSTP2[/url] wurde eine Unit zum Ändern der Sprache während der Laufzeit des Programms fällig - und zwar am besten eine, die minimalen Aufwand seitens der Wartung benötigt.

Hier einmal der Quelltext der Unit:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
{************************************************}
{*                                              *}
{* Dust Signs Language Manager                  *}
{* [Filename: dslangmgr, Type: Unit]            *}
{*                                              *}
{* Version: 1.00.000 State: Pre-Alpha           *}
{*                                              *}
{* Main programmer: Dust Signs                  *}
{* Programmers: Dust Signs                      *}
{*                                              *}
{* File created: 21.02.2005 19:25               *}
{* Last modified: 22.02.2005 20:57              *}
{*                                              *}
{* Changelog:                                   *}
{* ----------                                   *}
{* 21.02.2005-22.02.2005 [Dust Signs]: Start    *}
{*                                              *}
{* Used as DSTP Terminplaner Core Unit #009     *}
{*                                              *}
{************************************************}
{* 2do                                          *}
{*     None                                     *}
{************************************************}

Unit dslangmgr;

Interface

Uses
    SysUtils,
    Classes,
    Forms,
    TypInfo; //To proof existence of properties

//Internal structures for parsed file entry
Type
    TFileEntryComponent = Record
        ComponentName: String;
        Caption: String;
    End;

    TFileEntryComponent2 = Record
        Index: Integer;
        Caption: String;
    End;

Function LoadLanguageFile(AFilename: String; AForm: TForm): Integer; overload;
Function LoadLanguageFile(AFilename: StringVar AnArray: Array Of String): Integer; overload;

Implementation

//* AssignCaption
//************************************************
//* Assigns a caption to a component
//* Parameters:
//    - Form where component is placed
//    - Componentname
//    - Caption to be assigned
//* Returns: true if successful, false if an error occured

Function AssignCaption(AForm: TForm; ComponentName, ACaption: String): Boolean;
Var
    p: PPropInfo;
Begin
    Result := false;
    If AForm.FindComponent(ComponentName) = Nil Then //Does component exist?
        exit;
    Try
        //Property 'Caption' exists?
        p := GetPropInfo(AForm.FindComponent(ComponentName).ClassInfo, 'Caption');
        If (p <> NilAnd (p^.SetProc <> NilThen //Set caption
            SetStrProp(AForm.FindComponent(ComponentName), 'Caption', ACaption)
        Else
        Begin //Set 'Text' property
            p := GetPropInfo(AForm.FindComponent(ComponentName).ClassInfo, 'Text');
            If (p <> NilAnd (p^.SetProc <> NilThen //Set caption
                SetStrProp(AForm.FindComponent(ComponentName), 'Text', ACaption)
            Else
            Begin
                Result := false; //Neither 'Caption' nor 'Text' property exists
                exit;
            End;
        End;
        Result := true;
    Except
        Result := false;
    End;
End;

//* ParseFileEntry
//************************************************
//* Parses one entry of a language file
//* Parameters:
//    - Entry to parse
//    - var: parsed result
//* Returns: true if successful, false if an error occured

Function ParseFileEntry(FileEntry: StringVar Components: TFileEntryComponent): Boolean;
//Example:
//  MyTestLabel1:Hello world
//  Name:Caption
Begin
    Try
        Components.ComponentName := Copy(FileEntry, 1, Pos(':', FileEntry) - 1);
        Delete(FileEntry, 1, Pos(':', FileEntry));
        Components.Caption := FileEntry;
        Result := true;
    Except
        Result := false;
    End;
End;

//* ParseFileEntry2
//************************************************
//* Parses one entry of a language file
//* Parameters:
//    - Entry to parse
//    - var: parsed result
//* Returns: true if successful, false if an error occured

Function ParseFileEntry2(FileEntry: StringVar Components: TFileEntryComponent2): Boolean;
//Example:
//  1:Hello world
//  Index:Caption
Begin
    Try
        Components.Index := StrToInt(Copy(FileEntry, 1, Pos(':', FileEntry) - 1));
        Delete(FileEntry, 1, Pos(':', FileEntry));
        Components.Caption := FileEntry;
        Result := true;
    Except
        Result := false;
    End;
End;

//* LoadLanguageFile
//************************************************
//* Loads a language file into a form's components
//* Parameters:
//    - Path of the language file
//    - Form where components are
//* Returns: 0 if successful, -1 if unexpected error, else: error count

Function LoadLanguageFile(AFilename: String; AForm: TForm): Integer; Overload;
Var
    list: TStringList; //Temporary list
    i: Integer; //Loop dummy
    components: TFileEntryComponent; //Temp: parsed components of current entry
Begin
    Result := 0;
    Try
        Try
            list := TStringList.Create;
            list.LoadFromFile(AFilename);
            For i := 0 To list.Count - 1 Do
            Begin
                If list[i] = '' Then
                    continue; //Skip empty lines
                If Copy(list[i], 11) = '!' Then
                    continue; //Skip comment lines (which start with "!")
                If Not (ParseFileEntry(list[i], components)) Then
                Begin
                    Inc(Result); //One more error
                    continue;
                End;
                If Not (AssignCaption(AForm, components.ComponentName, components.Caption)) Then
                Begin
                    Inc(Result); //One more error
                    continue;
                End;
            End;
        Except
            Result := -1;
        End;
    Finally
        list.Free;
    End;
End;

//* LoadLanguageFile
//************************************************
//* Loads a language file into an array
//* Parameters:
//    - Path of the language file
//    - Destination array
//* Returns: 0 if successful, -1 if unexpected error, else: error count

Function LoadLanguageFile(AFilename: StringVar AnArray: Array Of String): Integer; Overload;
Var
    list: TStringList; //Temporary list
    i: Integer; //Loop dummy
    components: TFileEntryComponent2; //Temp: parsed components of current entry
Begin
    Result := 0;
    Try
        Try
            list := TStringList.Create;
            list.LoadFromFile(AFilename);
            For i := 0 To list.Count - 1 Do
            Begin
                If list[i] = '' Then
                    continue; //Skip empty lines
                If Copy(list[i], 11) = '!' Then
                    continue; //Skip comment lines (which start with "!")
                If Not (ParseFileEntry2(list[i], components)) Then
                Begin
                    Inc(Result); //One more error
                    continue;
                End;
                AnArray[components.Index] := components.Caption;
            End;
        Except
            Result := -1;
        End;
    Finally
        list.Free;
    End;
End;

End.


Zur Verwendung hier zwei Beispiele:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
//* LoadLanguageFiles
//************************************************
//* Loads mainform language files
//* Parameters:
//    - Language to load (p.e. 'eng' for english)

Procedure LoadLanguageFiles(Language: String);
Var
    TempErr: Integer; //Error variable (temp);
Begin
    With MainForm Do
    Begin
        TempErr := LoadLanguageFile('lang\mainform.' + Language + '.lang', MainForm); //Form
        If TempErr <> 0 Then
            ShowMessage('An error occured while loading language files (Code: ' + IntToStr(TempErr) + ')');
        TempErr := LoadLanguageFile('lang\messages.' + Language + '.lang', MessageArray); //Messages
        If TempErr <> 0 Then
            ShowMessage('An error occured while loading language files (Code: ' + IntToStr(TempErr) + ')');
    End;
End;


wobei MessageArray wiefolgt deklariert ist: MessageArray: Array[0..M_COUNT - 1Of String//Messages (language-specific)

Natürlich müsst ihr dazu Languagefiles erstellen. Hier zwei Beispiele:


Quelltext
1:
2:
3:
4:
!Hallo, ich bin ein Kommentar ;)

Label1:Hello world
Label2:Ich bin Label 2


Hier z.B. zwei Label; das hinter dem Doppelpunkt ist der Text, der zugewiesen wird.


Quelltext
1:
2:
3:
4:
!Beispiel für ein Array

0:Ich bin Item #0
1:Hallo Welt :)


Hier das selbe, nur, dass die Zahlen den jeweiligen Indizes im Array entsprechen.

Die Unit ist Open Source, der Header muss allerdings bleiben wie er ist; eine Erwähnung in irgendeiner Form wäre nett, wenn jemand die Unit verwendet :)

AXMD

//EDIT: Beispiele zwecks Verständlichkeit verbessert ;)
//EDIT2: Immer diese Tippfehler ^^


Christian S. - Sa 19.03.05 20:25

Irgendwie stehe ich gerade ein wenig auf dem Schlauch, wie ich die Unit denn nun benutze, will heißen, wie bekomme ich die Texte in die Komponenten? :gruebel:


Karlson - Sa 19.03.05 20:50

Mit der Languagefile.
Ich hab kurz rübergeschaut, und as far as i see (gibts die abkürzung AFAIS schon? :lol: ) liest er einfach alle captions der componenten aus, überprüft ob sie in der Languagefileliste sind und tauscht dann ggf. die Caption aus.


AXMD - Sa 19.03.05 20:51

Das macht die Unit für dich. Beispiel: du hast Label2 auf deiner Form, das den Text "Englisch" bekommen soll.

Hier mal die Datei (ich nenn sie mal bla.lang) dafür:


Quelltext
1:
Label2:Englisch                    


Und dann einfach laden (z.B.):


Delphi-Quelltext
1:
TempErr := LoadLanguageFile('bla.lang', Form1 {deine Form});                    


So einfach geht's ;)

AXMD


AXMD - Sa 19.03.05 20:59

user profile iconKarlson hat folgendes geschrieben:
Mit der Languagefile.
Ich hab kurz rübergeschaut, und as far as i see (gibts die abkürzung AFAIS schon? :lol: ) liest er einfach alle captions der componenten aus, überprüft ob sie in der Languagefileliste sind und tauscht dann ggf. die Caption aus.


So änhlich ;): ich gehe die Datei zeilenweise durch, überprüfe, ob die Komponente existiert und eine der Eigenschaften Caption oder Text hat; ist das der Fall, wird der jeweiligen Eigenschaft der Text hinter dem Doppelpunkt zugeweisen ;)

AXMD


retnyg - Sa 19.03.05 21:07

aha, und wie ginge das nun wenn ich ein file für englisch, deutsch, französisch und italienisch habe ?
dann wirds wohl nicht mehr funktionieren. wie wäre es wenn du über den komponentennamen (edit1) vorgehst ?


AXMD - Sa 19.03.05 21:08

user profile iconretnyg hat folgendes geschrieben:
aha, und wie ginge das nun wenn ich ein file für englisch, deutsch, französisch und italienisch habe ?

Einfach je nach Einstellung ein anderes File laden ;) (siehe erster Beitrag). Nenn die Files z.B. englisch.lang und deutsch.lang und mach if Programmsprache = 'Deutsch' then LoadLanguageFile('\deutsch.lang', Form1);
user profile iconretnyg hat folgendes geschrieben:
wie wäre es wenn du über den komponentennamen (edit1) vorgehst ?

Tu ich doch :gruebel:

AXMD


retnyg - Sa 19.03.05 21:12

bei deinem programm ist also z.b. __Start der name eines controls ?


AXMD - Sa 19.03.05 21:14

user profile iconretnyg hat folgendes geschrieben:
bei deinem programm ist also z.b. __Start der name eines controls ?


So ist es; Benennung ist bei mir nach Menütiefe; zwei Unterstriche bedeuten also zweite Ebene, sprich kein Hauptmenüpunkt, sondern eins weiter unten:


Quelltext
1:
2:
Datei
  Neu <- Das wäre z.B. __Neu


Alles klar ;)

AXMD

//EDIT: ersten Beitrag bearbeitet um Verständlichkeit zu erhöhen ;) Hab statt meinen MenuItems Labels genommen ;)


bayou - Mo 15.12.08 19:04

Hi,
das Thema ist zwar schon etwas älter aber genau was ich gesucht habe.
Dein Programm funktioniert super, leider habe ich ein Problem.
Wie kann ich den Items von RadioGroup umbenenen?
Gibt es eine Möglichkeit dein Programm so zu erweitern das auch diese Umbenannt werden?

Wäre für eine Antwort echt super Dankbar.
Jürgen


jaenicke - Mo 15.12.08 19:13

Im Grunde müsste (wenn ich das beim schnellen Überfliegen richtig gesehen habe) nur in AssignCaption neben den Properties auch geprüft werden, ob es eine RadioGroup ist.
Wenn ja, müsstest du aus dem Wert aus der Languagedatei (ACaption) irgendwie mehrere Items auslesen (z.B. getrennt durch Semikola) und zuweisen.


AXMD - Mo 15.12.08 19:14

Hallo!

jaenicke hat eigentlich schon das vorweggenommen, was ich auch gerade sagen wollte ;)

AXMD


bayou - Mo 15.12.08 19:19

könntet Ihr mir dabei helfen?
Bin immer noch Anfänger, komme zu selten dazu mit Delphi zu arbeiten.
Ist schon 1 Jahr her wo ich das letzte mal was gemacht habe.

Vielen Dank im vorraus
Jürgen


jaenicke - Mo 15.12.08 19:29

Hmm, ganz schnell hingeschrieben (geht sicher auch besser):

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
Function AssignCaption(AForm: TForm; ComponentName, ACaption: String): Boolean;
Var
    p: PPropInfo;
    i: Integer;
    RadioGroup: TRadioGroup;
Begin
    Result := false;
    If AForm.FindComponent(ComponentName) = Nil Then //Does component exist?
        exit;
    if AForm.FindComponent(ComponentName) is TRadioGroup then
    begin
        RadioGroup := TRadioGroup(AForm.FindComponent(ComponentName));
        for i := 0 to RadioGroup.Items.Count - 1 do
        begin
            if Pos(';', ACaption) = 0 then
              RadioGroup.Items[i] := ACaption
            else
              RadioGroup.Items[i] := Copy(ACaption, 1, Pos(';', ACaption) - 1);
            Delete(ACaption, 1, Pos(';', ACaption));
        end;
        Result := True;
        Exit;
    end;
    ... usw.
Ungetestet und es ginge vermutlich auch performanter (z.B. könnte man in der gesamten Routine eigentlich das Ergebnis von FindComponent zwischenspeichern ;-)), aber es sollte seinen Zweck erfüllen. Die Items werden getrennt durch Semikola in der Datei erwartet.


bayou - Mo 15.12.08 22:30

1000 Dank, es funktioniert super.
Ich werde jetzt erst mal ein wenig Testen um das ganze richtig zu verstehen.

nochmals Danke für Eure Hilfe


bayou - Di 16.12.08 01:14

Könntet Ihr mir noch bitte einen Tip geben wie ich es mit den Caption der Form händeln muss?
Bin seit einiger Zeit dran und bekomme es nicht hin.

Vielen Dank


jaenicke - Di 16.12.08 01:34

Nun ja, AForm.Name ist ja der Name deiner Form, wenn der Parameter ComponentName damit übereinstimmt, dann weise den Wert AForm.Caption zu.


bayou - Di 16.12.08 08:09

OK, danke, ich versuche es mal.


ssb-blume - Di 16.12.08 09:32

Frage:

Was macht der Anwender mit dem Programm, wenn er die Sprache wechseln will und
der Programmierer diese Sprache (noch) nicht berücksichtigt hat?


jaenicke - Di 16.12.08 09:38

Das kommt ja darauf an wie du das dann programmierst. Du kannst ja alle Sprachdateien suchen, die vorhanden sind, so dass man auch eigene erstellen kann, du kannst die theoretisch aber natürlich auch fest einprogrammieren.

Aber das hat mit der eigentlichen Unit ja nix zu tun, das liegt ja an deiner Programmierung, wenn du die Unit verwendest. :nixweiss:


bayou - Di 16.12.08 09:55

Nur mal so nebenbei.
Ich gehe einen Ordner (languages) im Pfad des Programmes durch und lese alle Sprachedateien (.lang) in ein Menü.
Dies soll der Anwender auswählen können und bei Programmende wird diese .lang Datei in die Programm Ini gespeichert, damit beim nächsten öffnen diese wieder geladen wird.

@jaenicke
im Moment stehe ich noch etwas auf dem Schlauch wie ich deinen Vorschlag umsetzen muss.
Könntest dur mir noch einen weiteren Tip geben?

Vielen Dank


jaenicke - Di 16.12.08 09:59

:roll: Ich habs doch schon fast exakt geschrieben wie die Abfrage sein muss.

Delphi-Quelltext
1:
2:
3:
4:
    if AForm.Name = ComponentName then
        AForm.Caption := ACaption
    else if AForm.FindComponent(ComponentName) is TRadioGroup then
    ...


bayou - Di 16.12.08 10:09

Danke für deine Antwort.

Und in der .lang Datei würde dann

Form1:Testform

als Caption für "Form1" abgerufen werden oder?
Bei mir funktioniert es nämlich nicht.


jaenicke - Di 16.12.08 10:11

Ich habs nicht ausprobiert, du kannst ja nen Haltepunkt da setzen und schauen was passiert. Ich hätte vermutet, dass es so richtig ist.


bayou - Di 16.12.08 10:15

ich habe mal einen Haltepunkt auf

Delphi-Quelltext
1:
  AForm.Caption := ACaption                    

gesetzt und da läuft er munter drüber.


jaenicke - Di 16.12.08 10:17

Ich meinte eher auf die if-Abfrage, denn wenn du in der Sprachdatei die Zeile als erstes schreibst kommt das Programm ja als erstes dort an. ;-)


bayou - Di 16.12.08 10:17

Habe ich auch.
Dort wurde gestoppt.
Es geht auch erst weiter wenn der Haltepunkt entfernt wurde.


bayou - Di 16.12.08 13:13

ich denke es hat etwas mit folgender funktion zu tun.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function ParseFileEntry(FileEntry: Stringvar Components: TFileEntryComponent): Boolean;
//Example:
//  MyTestLabel1:Hello world
//  Name:Caption
begin
    try
  Components.ComponentName := Copy(FileEntry, 1, Pos(':', FileEntry) - 1);
  Delete(FileEntry, 1, Pos(':', FileEntry));
  Components.Caption := FileEntry;
  Result := true;
    except
  Result := false;
    end;
end;

da hier auch nur die Komponenten angesprochen werden (wenn ich das richtig verstehe)


jaenicke - Di 16.12.08 13:27

Das dient nur zum Parsen soweit ich das sehe.

Ok ok, ich werde es mal wirklich ansehen und testen statt den Quelltext nur zu überfliegen. (Ich hatte gedacht das würde genügen.) ;-)


alzaimar - Di 16.12.08 14:03

Nette Idee, aber Spaltenübersichriften bei Grids sowie Support für TreeViews, Listviews usw. und Drittkomponenten fehlt, oder hab ich was übersehen?


jaenicke - Di 16.12.08 14:07

Das kann man ja anpassen, user profile iconAXMD hat die Unit ja für sein Projekt entwickelt und nicht als allumfassende Lösung...


bayou - Di 16.12.08 14:10

1000 Dank


jaenicke - Di 16.12.08 14:51

user profile iconbayou hat folgendes geschrieben Zum zitierten Posting springen:
Und in der .lang Datei würde dann

Form1:Testform

als Caption für "Form1" abgerufen werden oder?
Bei mir funktioniert es nämlich nicht.
Ich hab nochmal überlegt woran das liegen könnte. Kann es sein, dass du die Überprüfung ob die Komponente existiert noch davor hattest? Das ist natürlich nicht der Fall. Richtig wäre es deshalb so komplett eingebaut: (ungetestet)

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
Function AssignCaption(AForm: TForm; ComponentName, ACaption: String): Boolean;
Var
    p: PPropInfo;
    i: Integer;
    RadioGroup: TRadioGroup;
Begin
    Result := false;
    if AForm.Name = ComponentName then
    begin
        AForm.Caption := ACaption;
        Result := True;
        Exit;
    end
    else if AForm.FindComponent(ComponentName) = Nil Then //Does component exist?
        exit
    else if AForm.FindComponent(ComponentName) is TRadioGroup then
    begin
        RadioGroup := TRadioGroup(AForm.FindComponent(ComponentName));
        for i := 0 to RadioGroup.Items.Count - 1 do
        begin
            if Pos(';', ACaption) = 0 then
              RadioGroup.Items[i] := ACaption
            else
              RadioGroup.Items[i] := Copy(ACaption, 1, Pos(';', ACaption) - 1);
            Delete(ACaption, 1, Pos(';', ACaption));
        end;
        Result := True;
        Exit;
    end;
    Try


bayou - Di 16.12.08 16:41

Spitze, es geht.
Vielen vielen Dank
Da wäre ich nie drauf gekommen.


bayou - Mi 17.12.08 10:38

Ich habe es noch etwas ergänzt damit man auch den Titel der RadioGroup bekommt.
Sollte kein Titel genutzt werden bleibt der erste Eintrag frei

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
    else if AForm.FindComponent(ComponentName) is TRadioGroup then
    begin
  RadioGroup := TRadioGroup(AForm.FindComponent(ComponentName));
     RadioGroup.Caption := Copy(ACaption, 1, Pos(';', ACaption) - 1);
     Delete(ACaption, 1, Pos(';', ACaption));
  for i := 0 to RadioGroup.Items.Count - 1 do
        begin  
      if Pos(';', ACaption) = 0 then
        RadioGroup.Items[i] := ACaption
      else
        RadioGroup.Items[i] := Copy(ACaption, 1, Pos(';', ACaption) - 1);
      Delete(ACaption, 1, Pos(';', ACaption));
        end;  
        Result := True;  
        Exit;  
    end;

für StringGrid konnte ich diese Lösung anpassen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
    else if AForm.FindComponent(ComponentName) is TStringGrid then
    begin
  StringGrid := TStringGrid(AForm.FindComponent(ComponentName));
  for i := 0 to StringGrid.ColCount - 1 do
  begin
      if Pos(';', ACaption) = 0 then
        StringGrid.Cells[i, 0] := ACaption
      else
        StringGrid.Cells[i, 0] := Copy(ACaption, 1, Pos(';', ACaption) - 1);
      Delete(ACaption, 1, Pos(';', ACaption));
  end;
  Result := True;
  Exit;
    end

auch hier wird der erste Eintrag einfach frei gelassen wenn in der 1. Spalte nichts stehen soll.
StringGrid1:;Spalte2;Spalte3

Bitte sagte mir wenn ich Fehler darin haben sollte.

Nochmals vielen Dankfür die Hilfe


MDX - Sa 28.03.09 21:25

Wie kann man das für ne Combobox nutzen???


jaenicke - Sa 28.03.09 21:50

Ich sag mal so: Ob es sinnvoll ist, ist die Frage, aber generell kannst du natürlich auch die Werte einer ComboBox reinschreiben. Du musst das ja nur entsprechend anpassen.

Je umfangreicher das wird, desto besser wäre eine professionellere Lösung, da gibts ja einige Möglichkeiten. Von den delphiinternen bis zu String Ressource Managern und externen Multilanguage-Tools.