Entwickler-Ecke

Sonstiges (Delphi) - Formularübergreifende Änderungen von Properties


Deerfield - Mi 15.10.03 15:27
Titel: Formularübergreifende Änderungen von Properties
Hab noch ein kleines Problem. Ich will ein Programm mehrsprachig machen und will die Caption-Eigenschaft der Komponenten auf mehreren Forms gleichzeitig mittels einer Schleife zur Laufzeit des Programmes ändern lassen. Mittels der TAG-Eigenschaft habe ich jeder Komponente einen eindeutigen 'Caption-Wert' innerhalb einer externen Ressourcenstring-Liste zugewiesen. Mittels sprachenspezifischen Offsets sind die Caption-Werte veränderbar, je nach eingestellter Sprache. Für die Umstellung habe ich einen Menüpunkt im Grundbild meiner Applikation eingerichtet, der quasi nur den Offset übergibt. Danach soll die Caption-Eigenschaft bei allen betreffenden Komponenten in jedem Formular geändert werden. Die Komponenten gehe ich so durch:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
begin
  with application do for i := 0 to ComponentCount-1 do begin
    for j := 0 to Components[i].ComponentCount-1 do begin
      if Components[i].Components[j].tag <> 0 then begin
        c := Components[i].Components[j];
        if (c is TLabel) then (c as TLabel).caption := GetResString((c as TLabel).tag);
        if (c is TButton) then (c as TButton).caption := GetResString((c as TButton).tag);
        if (c is TCheckbox) then (c as TCheckbox).caption := GetResString((c as TCheckbox).tag);
        if (c is TMenuitem) then (c as TMenuitem).caption := GetResString((c as TMenuitem).tag);
       { Hier stehen die weiteren Typen, die von der Sprachumwandlung betroffen sind ... z.B. Combobox }

      end;
    end;
  end;
end;


Das Problem ist nun, dass immer nur das Hauptformular geändert wird, nicht die Komponenten anderer Forms. Hat jemand ne Idee?

MfG
Deerfield


maximus - Mi 15.10.03 15:34

JA...kapsel das in eine proc:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
procedure changeLanguage(aForm:TForm);
begin 
  with application do for i := 0 to aForm.ComponentCount-1 do begin 
    for j := 0 to aForm.Components[i].ComponentCount-1 do begin 
      if aForm.Components[i].Components[j].tag <> 0 then begin 
        c := aForm.Components[i].Components[j];  /// ??? Components[i].Components[j] ???
        if (c is TLabel) then (c as TLabel).caption := GetResString((c as TLabel).tag); 
        if (c is TButton) then (c as TButton).caption := GetResString((c as TButton).tag); 
        if (c is TCheckbox) then (c as TCheckbox).caption := GetResString((c as TCheckbox).tag); 
        if (c is TMenuitem) then (c as TMenuitem).caption := GetResString((c as TMenuitem).tag); 
       { Hier stehen die weiteren Typen, die von der Sprachumwandlung betroffen sind ... z.B. Combobox } 

      end; 
    end; 
  end; 
end;


du rufst die procedure dann für jede from auf :wink:


PS: @Components[i].Components[j]: das ist doch spanisch...benutz dann doch lieber echte rekursion


Deerfield - Mi 15.10.03 16:10

Also ich habs jetzt mal als Prozedur aufgerufen, beim OnShow Ereignis bzw. OnCreate. Der ändert immer nur die Mainform... :(

Und wie meinst du das mit der Rekursion... bin Neuling bei Delphi

MfG
Deerfield


Deerfield - Mi 15.10.03 16:16

Also ich habs jetzt mal als Prozedur aufgerufen, beim OnShow Ereignis bzw. OnCreate. Der ändert immer nur die Mainform... :(

Die ganze Unit sieht so aus:


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:
unit sprache;

interface

var actOffset:Integer;

const sp_deutsch  = 0;
      sp_englisch = 1000;

procedure Spracheinstellung(offset:Integer);

implementation

uses forms,StdCtrls, ExtCtrls,menus,sysutils,windows;

{$R language.res}

procedure Spracheinstellung(offset:Integer);
var i,j: integer;
    c  : TObject;

function GetResString(Nr: Integer): String;
var p: PChar;
begin
     actOffset := offset;
     p := StrAlloc(256);
     LoadString(Hinstance,nr+offset,p,255);
     result := p;
     StrDispose(p);
end;

begin
  with application do for i := 0 to ComponentCount-1 do begin
    for j := 0 to Components[i].ComponentCount-1 do begin
      if Components[i].Components[j].tag <> 0 then begin
        c := Components[i].Components[j];
        if (c is TLabel) then (c as TLabel).caption := GetResString((c as TLabel).tag);
        if (c is TButton) then (c as TButton).caption := GetResString((c as TButton).tag);
        if (c is TCheckbox) then (c as TCheckbox).caption := GetResString((c as TCheckbox).tag);
        if (c is TMenuitem) then (c as TMenuitem).caption := GetResString((c as TMenuitem).tag);
       { Hier stehen die weiteren Typen, die von der Sprachumwandlung betroffen sind ... z.B. Combobox }

      end;
    end;
  end;
end;


end.


Und wie meinst du das mit der Rekursion... bin Neuling bei Delphi

MfG
Deerfield


maximus - Mi 15.10.03 16:42

Oki...nochmal. Das mit der rekursion vergiss erstmal. Ich wunder mich nur warum du i und j läufst? die j-schleife ist IMHO überflüssig.

Wenn du deiner proc explizit das formular übergibst, dass geändert werden soll, dann musst du das nur für alle forms machen und zickzack fertig...


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:
procedure Spracheinstellung(offset:Integer; aForm:TForm); // <-- form übergabe
var i,j: integer; 
    c  : TObject; 

function GetResString(Nr: Integer): String; 
var p: PChar; 
begin 
     actOffset := offset; 
     p := StrAlloc(256); 
     LoadString(Hinstance,nr+offset,p,255); 
     result := p; 
     StrDispose(p); 
end; 

begin 
  with aForm do // weil du hier apllication benutzt hast nimmt er nur das mainForm
  for i := 0 to ComponentCount-1 do begin 
    //for j := 0 to Components[i].ComponentCount-1 do begin 
      if Components[i].tag <> 0 then begin 
        c := Components[i];
        if (c is TLabel) then (c as TLabel).caption := GetResString((c as TLabel).tag); 
        if (c is TButton) then (c as TButton).caption := GetResString((c as TButton).tag); 
        if (c is TCheckbox) then (c as TCheckbox).caption := GetResString((c as TCheckbox).tag); 
        if (c is TMenuitem) then (c as TMenuitem).caption := GetResString((c as TMenuitem).tag); 
       { Hier stehen die weiteren Typen, die von der Sprachumwandlung betroffen sind ... z.B. Combobox } 

      end; 
    end; 
  end; 
end;


und der aufruf könnte so aussehen:


Delphi-Quelltext
1:
2:
3:
4:
// im mainForm ...zB. onShow
...
Spracheinstellung(??, self); // fürs mainform
Spracheinstellung(??, anotherForm); // andere forms übersetzen etc...die entsprechende unit natürlich mit uses einbinden!


klarer was ich meinte?


maze2k - Mi 15.10.03 16:47

Wie willst du denn in letzteres noch ne Rekursion einbauen?


maximus - Mi 15.10.03 16:58

Wie soll er eine rekursion einbauen wollen, wenn er garnicht weiss was das ist?


maze2k - Mi 15.10.03 17:11

Rekursion war das erste was ich in meinem Studium gelernt hab, noch vor den Vorlesungen (die haben noch immer net richtig begonnen, nur Einführungen über Einführungen)...
im Vorkurs haben wir kurz Einführung in C++ gemacht und da kam gleich Rekursion (beim Berechnen der Fakultät / Fibonacci-Zahlen) :D


Deerfield - Do 16.10.03 07:07

Guten Morgen!

maximus hat folgendes geschrieben:
Oki...nochmal. Das mit der rekursion vergiss erstmal. Ich wunder mich nur warum du i und j läufst? die j-schleife ist IMHO überflüssig.

Wenn du deiner proc explizit das formular übergibst, dass geändert werden soll, dann musst du das nur für alle forms machen und zickzack fertig...

...

klarer was ich meinte?


Ok, ich habe das soweit eingearbeitet. Die Unit sprache ist nach wie vor eingebunden, nur er meckert nun beim Aufruf von


Delphi-Quelltext
1:
2:
3:
4:
procedure TMainForm.Englisch1Click(Sender: TObject);
begin
  Spracheinstellung(sp_englisch, self);
end;


Undefinierter Bezeichner: 'Spracheinstellung'

MfG
Deerfield


Deerfield - Do 16.10.03 07:18

Ok, habs! Danke an alle :o


Deerfield - Do 16.10.03 13:08

Hab wieder ne kleine Hürde. Ich will die Spaltenüberschriften einer Tabelle zur Laufzeit umstellen und habe in die Unit Sprache die Zeile


Delphi-Quelltext
1:
if (c is TListColumn) then (c as TListColumn).caption := GetResString((c as TListColumn).tag);                    


hinzugefügt. Leider werden die Spalten nicht umbenannt. Wenn ich die Caption direkt zuweise beim OnShow-Ereignis des Forms, mittels


Delphi-Quelltext
1:
Liste.Column[x].Caption := Loadstr(yyy+actOffset);                    


funktioniert es.

Hat jemand eine Idee?

MfG
Deerfield


maximus - Do 16.10.03 13:55

da steht ja auch '.Column[x].' dazwischen, was auf die einzelnen cols zugreift. Mach halt die x-schleife in deine sprach proc rein


Deerfield - Do 16.10.03 14:12

Na ich lasse doch extra alle Komponenten dieser Art in der Unit Sprache durchgehen (also quasi ne Art Schleife), aber irgendwie ändert sich nix. Das ist da komische. Bei den anderen Elementen (Labels etc.) geht es doch auch.
Nur wenn ich jedes Element direkt (also jede Spaltenüberschrift) einzeln ändere, geht es auch bei den Columns.


maximus - Do 16.10.03 14:24

Ja...aber die TListColumns sind keine komponenten, sonder nachfahren von TCollectionItem :wink: dir bleibt nix anderes übrig als die hauptcompo ( TListView oder watt ) rauszusuchen und dann eine extra schleife einzubauen, in der du durch die cols gehst.


Deerfield - Do 16.10.03 14:32

Ah okay. Vielen Dank! :D