![]() |
einen Datensatzmitgliedsnamen dynamisch zuweisen
(to assign a record member name dynamically)
Guten Tag, Ich suche Hilfe, um diesen Code zu vereinfachen und die aus der INI-Datei gelesenen Werte einer Variablen vom Typ "Datensatz" zuzuweisen, wobei sich der Elementname vom Schlüsselnamen in der INI-Datei unterscheidet. Ich habe nicht herausgefunden, wie ich den Mitgliedsnamen dynamisch zuweisen kann, da es zwei Gruppen (A und B) mit denselben Schlüsselnamen in der Datei, aber unterschiedlichen Namen im Datensatz gibt.
Code:
(English: Good morning,
// ini file contains pairs key_name=value , the record contains abbreviated key name
if pars[0] = 'first_frame' then k := 'first_'+group else if pars[0] = 'end_frame' then k := 'last_'+group else if pars[0] = 'first_filename' then k := 'start_name_'+group else if pars[0] = 'path' then k := 'path_'+group else if pars[0] = 'check_if_files_exist' then k := 'check_files_exist_'+group; if group = 'A' then begin if k = 'path_A' then ini.basic.path_A := pars[1] else if k = 'first_A' then ini.basic.first_A := pars[1] else if k = 'last_A' then ini.basic.last_A := pars[1] else if k = 'start_name_A' then ini.basic.start_name_A := pars[1] else if k = 'check_files_exist_A' then ini.basic.check_files_exist_A := true; end else if group = 'B' then begin if k = 'path_B' then ini.basic.path_B := pars[1] else if k = 'first_B' then ini.basic.first_B := pars[1] else if k = 'last_B' then ini.basic.last_B := pars[1] else if k = 'start_name_B' then ini.basic.start_name_B := pars[1] else if k = 'check_files_exist_B' then ini.basic.check_files_exist_B := true; end; end; I'm looking for help to simplify this code, assigning the values read from ini file to a variable of type Record, where the member name is different from the name of the key in the ini file. I haven't figured out how can I assign the member name dynamically because there are two groups (A and B) with the same key names in the file but different names in the record.) Deklaration:
Code:
basic.ini
type TBasicSettings = record
is_scroll_vertical: boolean; scroll_type=vertical is_image_direction_up: boolean; is_search_colors_HSL: boolean; path_A: string; path_B: string; check_files_exist_A: boolean; check_files_exist_B: boolean; RAM_disk: string; RAM_free: LongWord; start_name_A: string;first_filename first_A: string;first_frame last_A: string;end_frame= start_name_B: string;first_filename first_B: string;first_frame last_B: string;end_frame fps: byte; scroll_max_shift: integer; end; [GENERAL]
Code:
[GENERAL]
scroll_type=vertical image_direction=up search_colors_in=HSL H_max_difference_deg=10% S_max_difference_per=20% L_max_difference_per=10% ;V_max_difference_per=10% padding_left=22 padding_right=25 padding_top=0 padding_bottom=0 detect_max_character_count_on_screen=3 arrow_1_count=2 arrow_2_count=1 arrow_3_count=1 image_1_count=1 skip_detections_on_screen_when_frame_position_is_determined=1 group_to_copy_image_data_from=A text_copy_color_direction=BA RAM_disk=A: RAM_disk_free_space=1GB |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Nicht zu beantworten mit den gegebenen Infos. Zeig die Deklaration des Records und einen repäsentstiven Teil des Ini-Files.
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Die Datenstruktur ändern
und gleiche Teile zusammenfassen? (und dann nachfolgend den größten Teil ignorieren)
Delphi-Quellcode:
// nicht
ini.basic.path_A := pars[1] ini.basic.path_B := pars[1] // sondern ini.basic.A.path := pars[1] ini.basic.B.path := pars[1] // für Objekte statt Records ... bei Records andersrum, also erst den Temp-Record füllen und dann zuweisen if pars[0] = 'B' then X := ini.basic.B; X.path := pars[1];
Delphi-Quellcode:
wozu nochmal die group extra vergleichen, wenn die schon in K enthalten ist?
//if pars[0] = 'first_frame' then k := 'first_'+group
//else if pars[0] = 'end_frame' then k := 'last_'+group //else if pars[0] = 'first_filename' then k := 'start_name_'+group //else if pars[0] = 'path' then k := 'path_'+group //else if pars[0] = 'check_if_files_exist' then k := 'check_files_exist_'+group //else ; // was ist k, wenn nichts trifft? // wozu den ersten Teil umbennen? // sowas würde sich nur lohnen, wenn du anschließend mit diesen Namen via RTTI nach den Feldern suchen tätest. TRTTIContext.Create.GetType(TIniBasicRecordIrgendwas).GetField(k).SetValue(ini.basic, pars[1]); // abgesehn vom check_if_files_exist // es gibt auch Funktionen/Klassen/Frameworks, z.B. für INI/XML/JSON zu Record/Klasse, auch inkl. Umbenennen von SpeicherName zu FeldName k := pars[0] + group; if group = 'A' then begin if k = 'path_A' then ini.basic.path_A := pars[1] else if k = 'first_frame_A' then ini.basic.first_A := pars[1] else if k = 'end_frame_A' then ini.basic.last_A := pars[1] else if k = 'first_filename_A' then ini.basic.start_name_A := pars[1] else if k = 'check_if_files_exist_A' then ini.basic.check_files_exist_A := true; end else if group = 'B' then begin if k = 'path_B' then ini.basic.path_B := pars[1] else if k = 'first_frame_B' then ini.basic.first_B := pars[1] else if k = 'end_frame_B' then ini.basic.last_B := pars[1] else if k = 'first_filename_B' then ini.basic.start_name_B := pars[1] else if k = 'check_if_files_exist_B' then ini.basic.check_files_exist_B := true; end; end; // ein end zuviel?
Delphi-Quellcode:
bzw.
k := pars[0] + group;
if k = 'path_A' then ini.basic.path_A := pars[1] else if k = 'first_A' then ini.basic.first_A := pars[1] else if k = 'last_A' then ini.basic.last_A := pars[1] else if k = 'start_name_A' then ini.basic.start_name_A := pars[1] else if k = 'check_files_exist_A' then ini.basic.check_files_exist_A := true else if k = 'path_B' then ini.basic.path_B := pars[1] else if k = 'first_B' then ini.basic.first_B := pars[1] else if k = 'last_B' then ini.basic.last_B := pars[1] else if k = 'start_name_B' then ini.basic.start_name_B := pars[1] else if k = 'check_files_exist_B' then ini.basic.check_files_exist_B := true;
Delphi-Quellcode:
case IndexText(pars[0] + group, ['path_A', 'first_A', 'last_A' , 'start_name_A' , 'check_files_exist_A' , 'path_B' , 'first_B' , 'last_B' , 'start_name_B', 'check_files_exist_B']) oF
0: ini.basic.path_A := pars[1]; 1: ini.basic.first_A := pars[1]; 2: ini.basic.last_A := pars[1]; 3: ini.basic.start_name_A := pars[1]; 4: ini.basic.check_files_exist_A := true; 5: ini.basic.path_B := pars[1]; 6: ini.basic.first_B := pars[1]; 7: ini.basic.last_B := pars[1]; 8: ini.basic.start_name_B := pars[1]; 9: ini.basic.check_files_exist_B := true; end; oder wozu unnötig umbenennen (Group anhängen), wenn die Groups eh getrennt behandelt werden?
Delphi-Quellcode:
bzw.
//if pars[0] = 'first_frame' then k := 'first'
//else if pars[0] = 'end_frame' then k := 'last' //else if pars[0] = 'first_filename' then k := 'start_name' //else if pars[0] = 'path' then k := 'path' //else if pars[0] = 'check_if_files_exist' then k := 'check_files_exist'; if group = 'A' then begin if pars[0] = 'path' then ini.basic.path_A := pars[1] else if pars[0] = 'first_frame' then ini.basic.first_A := pars[1] else if pars[0] = 'end_frame' then ini.basic.last_A := pars[1] else if pars[0] = 'first_filename' then ini.basic.start_name_A := pars[1] else if pars[0] = 'check_if_files_exist' then ini.basic.check_files_exist_A := true; end else if group = 'B' then begin if k = 'path' then ini.basic.path_B := pars[1] else if pars[0] = 'first_frame' then ini.basic.first_B := pars[1] else if pars[0] = 'end_frame' then ini.basic.last_B := pars[1] else if pars[0] = 'first_filename' then ini.basic.start_name_B := pars[1] else if pars[0] = 'check_if_files_exist' then ini.basic.check_files_exist_B := true; end;
Delphi-Quellcode:
i := IndexText(pars[0] + group, ['path', 'first', 'last', 'start_name', 'check_files_exist']);
case group of 'A': case i oF 0: ini.basic.path_A := pars[1]; 1: ini.basic.first_A := pars[1]; 2: ini.basic.last_A := pars[1]; 3: ini.basic.start_name_A := pars[1]; 4: ini.basic.check_files_exist_A := true; end; 'B': case i oF 0: ini.basic.path_B := pars[1]; 1: ini.basic.first_B := pars[1]; 2: ini.basic.last_B := pars[1]; 3: ini.basic.start_name_B := pars[1]; 4: ini.basic.check_files_exist_B := true; end; end; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Danke, aber
"IndexText" Problem in der D7 [Error]: Undeclared identifier: 'IndexText'. |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
![]() Diese Funktionen gibt es bestimmt mindestens seit 2009 2006, also kurz nach D7, aber vielleicht auch schon im Delphi 7, wenn man die passende Unit einbindet? :angle: Aktuell ist es in der System.StrUtils bzw. StrUtils ... aber mit der Zeit wurden auch Units umbenannt, bzw. Funktion in andere Units verschoben. ![]() ![]() Die gucken einfach nur in einem Array, ob/wo das da drin steht. CASE kann ja leider im Delphi nur Ordinal und keine Strings, so wie nahezu jede andere Sprache :cry: |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Delphi 7 kennt aber AnsiIndexText (in der Unit StrUtils zu finden).
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Viele Danke, daher habe ich den Code ein wenig geändert, um die Leistung zu steigern:
Code:
Es ist eine schöne Lösung.
if group = 'A' then
case AnsiIndexText(pars[0]+'_A', ['path_A', 'first_frame_A', 'end_frame_A' , 'first_filename_A' , 'check_if_files_exist_A']) oF 0: ini.basic.A.path := pars[1]; 1: ini.basic.A.first := pars[1]; 2: ini.basic.A.last := pars[1]; 3: ini.basic.A.start_name := pars[1]; 4: ini.basic.A.check_files_exist := true; end else if group = 'B' then case AnsiIndexText(pars[0]+'_B', ['path_B' , 'first_frame_B' , 'end_frame_B' , 'first_filename_B', 'check_if_files_exist_B']) oF 0: ini.basic.B.path := pars[1]; 1: ini.basic.B.first := pars[1]; 2: ini.basic.B.last := pars[1]; 3: ini.basic.B.start_name := pars[1]; 4: ini.basic.B.check_files_exist := true; end; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Delphi-Quellcode:
(pars[0]+'_B', ['path_B' , 'first_frame_B' , ...
Delphi-Quellcode:
:stupid:
(pars[0], ['path' , 'first_frame' , ...
Schneller ist es nur bedingt ... eher fast gleich schnell oder vielleicht eine Millisekunde langsamer (ein Funktionsaufruf, aber gleich viele String-Vergleiche), aber es macht den Code kürzer und ohne die viele IF....THEN dazwischen auch etwas übersichlicher. Hier die
Delphi-Quellcode:
als Konstante oder mit
123:
Delphi-Quellcode:
, erspart sich, da der Kommentar/Name bereits als
{Name}123:
Delphi-Quellcode:
dran steht.
.path :=
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
Den letzten Satz verstehe ich nicht. Aber eine Millisekunde langsamer wäre viel. Hatten Sie nicht eine Mikrosekunde im Sinn? |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Ginge es eventuell auch so?
Delphi-Quellcode:
var
ini : TBasicSettings; begin case group of 'A' : ini := ini.basic.A; 'B' : ini := ini.basic.B; end; case AnsiIndexText(pars[0], ['path', 'first_frame', 'end_frame', 'first_filename', 'check_if_files_exist']) of // Wenn pars[0] immer in Kleinbuchstaben vorliegt, ginge auch // case AnsiIndexStr(pars[0], ['path', 'first_frame', 'end_frame', 'first_filename', 'check_if_files_exist']) of // das spart dann auch noch die Verpflichtung, // beim Vergleich nicht zwischen Groß- und Kleinschreibung zu unterscheiden. 0: ini.path := pars[1]; 1: ini.first := pars[1]; 2: ini.last := pars[1]; 3: ini.start_name := pars[1]; 4: ini.check_files_exist := true; end; end; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Nein, die ini ist ein Wrapper - sie enthält viele Einstellungen zu Suchfarben, Text, Bildern usw. Das würde sie verlieren.
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Der Funktionsaufruf ist nur einen "Hauch" langsamer ('ne Hand voll CPU-Takte),
dagegen beim case-insensitven braucht der eine Parameter nur einmal kleingemacht werden, anstatt mehrmal je Zeile/IF.
Delphi-Quellcode:
Letztes wie die vielen IFs
// turborennschnecke
if TArray.BinarySearch(['a', 'b', 'c'], AnsiLowerCase(S)) // kleingeschrieben und sortiert // und natürlich ist ein if AnsiIndexStr(AnsiLowerCase(S), ['a', 'b', 'c']) // Suchwerte direkt kleingeschrieben // schneller/optimaler als ein if AnsiIndexText(S, ['A', 'B', 'C']) // und noch schneller als if AnsiIndexStr(AnsiLowerCase(S), [AnsiLowerCase('A'), AnsiLowerCase('B'), AnsiLowerCase('C')]) // fast gleichschnell wie K := AnsiLowerCase(S); if K = AnsiLowerCase('A') if K = AnsiLowerCase('B') if K = AnsiLowerCase('C') // aber schneller als if AnsiLowerCase(S) = AnsiLowerCase('A') if AnsiLowerCase(S) = AnsiLowerCase('B') if AnsiLowerCase(S) = AnsiLowerCase('C') // und die bummelschnecke die RTTI (siehe vorher) ist am Kürzesten, aber dafür ist "langsam" etwas untertrieben ... aber eben einfach ... dagegen aber auch vom Compiler nicht validierbar, weil erst zur Laufzeit und die ersten Beiden ... halt wie der Code schöner Lesbar ist. Kommt halt drauf an, wie man es sieht ... lieber 'nen Hauch langsamer, aber dafür einfach/lesbar, oder eben nur schnell.
Delphi-Quellcode:
AnsiIndexStr(AnsiLowerCase(S), ['FirstFilename', 'CheckIfFilesExist', ...])
Delphi-Quellcode:
AnsiIndexText(S, ['firstfilename', 'checkiffilesexist', ...])
Wobei schnell, da nimmt man dann ein Directory, bzw. eine "sortierte" Liste/Array und macht dann eine binäre Suche ( ![]()
Delphi-Quellcode:
Vorteil von IndexText vs. SameText/LowerCase ist, dass das
// AnsiIndexStr ist wie
if S = 'A' then ... else if S = 'B' then ... else if S = 'C' then ... if AnsiSameStr(S, 'A' then ... else if AnsiSameStr(S, 'B') then ... else if AnsiSameStr(S, 'C') then ... // AnsiIndexText ist wie if AnsiLowerCase(S) = AnsiLowerCase('A') then ... else if AnsiLowerCase(S) = AnsiLowerCase('B') then ... else if AnsiLowerCase(S) = AnsiLowerCase('C') then ... if AnsiSameText(S, 'A') then ... else if AnsiSameText(S, 'B') then ... else if AnsiSameText(S, 'C') then ...
Delphi-Quellcode:
nur einmal, anstatt in jeder Zeile neu angepasst wird.
S
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Ich bin mit der jetzigen Lösung zufrieden.
Code:
Ich denke, es ist nur eine Schande, dass ich etwas nicht mit Stil verwenden kann
if group = 'A' then
case AnsiIndexText(pars[0], ['path', 'first_frame', 'end_frame' , 'first_filename' , 'check_if_files_exist']) oF 0: ini.basic.A.path := pars[1]; 1: ini.basic.A.first := pars[1]; 2: ini.basic.A.last := pars[1]; 3: ini.basic.A.start_name := pars[1]; 4: ini.basic.A.check_files_exist := true; end else if group = 'B' then case AnsiIndexText(pars[0], ['path' , 'first_frame' , 'end_frame' , 'first_filename', 'check_if_files_exist']) oF 0: ini.basic.B.path := pars[1]; 1: ini.basic.B.first := pars[1]; 2: ini.basic.B.last := pars[1]; 3: ini.basic.B.start_name := pars[1]; 4: ini.basic.B.check_files_exist := true; end;
Code:
ini.basic[group].check_files_exist
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
Delphi-Quellcode:
Zum Auslesen kein Problem ... beim Zuweisen mit Records muß man "bissl" aufpassen/rumpfuschen.
record // oder class
A: TIrgendwas; B: TIrgendwas; C: TIrgendwas; property basic[S: string]: TIrgendwas read ... write ...; // die Getter/Setter nicht vergessen end; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
![]() |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
![]() ![]() in älteren Delphis ging eine Überladung nicht (mehrere Array-Property), aber wenn, dann gingen sie nur als Default-Property, und in noch älteren Delphi ging es nur in Klassen aber noch nicht in Records. Und die string-like Array-Operatoren gab es im Delphi 7 auch noch lange nicht.
Delphi-Quellcode:
var X, Y: array of Integer;
X := [4, 5, 6]; Y := [7]; // SetLength(Y, 1); Y[0] := 7; X := X + Y; X := X + [1, 2, 3]; Insert(9, X, 2); // [4, 5, 9, 6, 7, 1, 2, 3] ![]() ![]() ![]() |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Ich bin im Abschnitt "Indexspezifizierer" (Index Specifiers) verloren. Warum verwenden sie im Folgenden keine Klammern []? "property Left: Longint index 0 read GetCoordinate "
![]() |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Das ist was Anderes.
Über "diesen" Index kann man für mehrere Property den selben Getter/Setter verwenden.
Delphi-Quellcode:
Man kann den Index einfach einfach nur zur Verwendung der Erkennung welches Irgendwas# gemeint ist nutzen,
property IrgendwasA: TSonstwas index 1 read GetItgendwas ...
property IrgendwasB: TSonstwas index 2 read GetItgendwas ... property IrgendwasC: TSonstwas index 3 read GetItgendwas ... oder man kann diese 32 Bit auch verwende, u darin was zu Kodieren. z.B. Property für den Zugriff auf einen/mehrere Bits (Bismaske) und darin codieren welche/wieviele Bits jeweils gemeint sind. Oder man kann auch jeden anderen Ordinalen Typen dort angeben (z.B. Konstanten/Enums)
Delphi-Quellcode:
z.B. im Getter/Setter mit Index "rechnen",
const cA = 1; // = Ord('A');
property IrgendwasA: TSonstwas index cA read GetItgendwas ... property IrgendwasB: TSonstwas index cB read GetItgendwas ... type TIrgendwasEnum = (iwA, iwB); property IrgendwasA: TSonstwas index Ord(iwA) read GetItgendwas ... property IrgendwasB: TSonstwas index Ord(iwB) read GetItgendwas ... das als Index für eine Array/Liste-Variable verwenden oder für ein
Delphi-Quellcode:
bzw.
CASE index OF
Delphi-Quellcode:
oder ...
CASE TIrgendwasEnum(index) OF
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
a) Lokale Variablen mit schönen Namen verwenden und pars[0] bzw pars[1] zuweisen. b) Prozedur machen für den doppelten Code und übergeben von ini.basic.A oder ini.basic.B. Dann spart man sich den doppelten Code. Dann der Aufruf: Mach(group, 'A', pars[0], pars[1], ini.basic.A); Mach(group, 'B', pars[0], pars[1], ini.basic.B); |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Array-Property, das ist sowas, wie bei TList/TStrings/TStringList ... halt wie beim Array.
Delphi-Quellcode:
Default-Property, sind jene, welche "implizit" genutzt werden können.
property Strings[Index: Integer]: string read GetString write SetStrings;
SL.Strings[index] SL.Value[Name]
Delphi-Quellcode:
dagegen die Default-Value bzw. Default-Property-Value
property Strings[Index: Integer]: string read GetString write SetStrings; default;
SL.Strings[index] // direkt SL[index] // default
Delphi-Quellcode:
property Cool: Boolean read GetCool write SetCool default True;
Die Klasse Instanz neu erstelt, da ist der Wert True ... bzw. eigentlich heißt es, dass "True" nicht in der DFM gespeichert wird, also nur "False" steht drin. (stimmen beide Aussagen aber nicht überein, dann hast du ein Problem, beim Laden einer DFM ... also aufpassen, wenn du Klassen baust)
Delphi-Quellcode:
property StringEx: string index 123 read GetString write SetStrings;
SL.StringEx // Index nur intern, z.B. zur Haldung von Kontroll-Daten und/oder um für mehrere Property nur "einen" Getter/Setter zu nutzen // aber so fällt bestmmt auf, dass diese beiden "Index" nicht das Gleiche sind property StringEx[Index2: Integer]: string index 123 read GetString write SetStrings; // der Getter und Setter sieht hier erstmal gleich aus property A: string index 1 read GetABC write SetABC; property B: string index 2 read GetABC write SetABC; property C: string index 3 read GetABC write SetABC; property X[Index: Integer]: string read GetABC write SetABC; procedure GetABC(Index: Integer): string; begin //Assert((Index => 1) and (Index <= 3), 'peng'); case Index of 1: Result := 'Aaa'; 2: Result := 'Bbb'; 3: Result := 'Ccc'; else raise Exception.Create('peng'); end; end; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Ich habe versucht, dem Beispiel in
![]()
Code:
[Error] constants_ini.pas(47): ':' expected but identifier 'TBasicGroupSettings' found
TBasicGroupSettings = record
path: string; check_files_exist: boolean; start_name: string; // first_filename first: string; // first_filename last: string; // end_frame end; // ini.basic has some general settings too type TBasicSettings = class is_scroll_vertical: boolean; is_image_direction_up: boolean; is_search_colors_HSL: boolean; check_files_exist_A: boolean; check_files_exist_B: boolean; RAM_disk: string; RAM_free: LongWord; // v MB A: TBasicGroupSettings; B: TBasicGroupSettings; fps: byte; scroll_max_shift: integer; property basic[G:String] TBasicGroupSettings read Get_A write Set_A; end;
Code:
property basic[G:String] TBasicGroupSettings read Get_A write Set_A;
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Die Hilfe ist kaputt ... bei der automatischen Übersetzung sind ein paar Zeichen verloren gegangen.
Zitat:
Delphi-Quellcode:
und dann in TBasicSettings.Create die beiden Instanzen erstellen.
BasicGroupSettings = class
Und natürlich im TBasicSettings.Destroy wieder freigeben, oder Beides als
Delphi-Quellcode:
, beim Erstellen das den Owner auf Self und automatisch freigeben lassen.
= class(TComponent)
Zitat:
Delphi-Quellcode:
// bei einem RECORD landet "first" nur im Result von Get_A, aber wird nicht automatisch in Set_A zurückgeschrieben.
basicsetting.basic['A'].first := 'abc'; // daher .... als CLASS gäbe es dieses Problem nicht // eventuell vorher auslesen: temp := basicsetting.basic['A']; temp.first := 'abc'; basicsetting.basic['A'] := temp; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Dann habe ich versucht, es mit einem Array zu tun, aber dort sagt es mir inkompatible Typen hinter dem Wort write.
Code:
type TBasicSettings = class
private fGroups: array[0..1] of TBasicGroupSettings; function getA(Index: byte): TBasicGroupSettings; function getB(Index: byte): TBasicGroupSettings; procedure setA(Index: byte; O: TBasicGroupSettings); procedure setB(Index: byte; O: TBasicGroupSettings); public is_scroll_vertical: boolean; // scroll_type=vertical is_image_direction_up: boolean; // image_direction is_search_colors_HSL: boolean; check_files_exist_A: boolean; check_files_exist_B: boolean; RAM_disk: string; RAM_free: LongWord; // v MB start_name_A: string; // A: TBasicGroupSettings; // B: TBasicGroupSettings; fps: byte; scroll_max_shift: integer; // property basic[G:String] TBasicGroupSettings read Get_A write Set_A; property A: TBasicGroupSettings Index 0 read GetA write SetA; property B: TBasicGroupSettings Index 1 read GetB write SetB; end; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
In Delphi 7 gibt es diese Möglichkeiten noch nicht.
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Zitat:
![]()
Code:
Das habe ich in Beitrag 15# nicht gesehen.
7.Property Name[Index : IndexType] : BaseType read Getter {default;}
Sie erklären auch das Standardwort, das mir unklar war. "Default allows the Getter and Setter method calls to be replaced as in the following example:"
Code:
:
myValue := MyClass.Getter(23);
// can be replaced by : myValue := MyCLass[23]; |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Array-Property gingen in D7, aber Einiges davon funktioniert oftmals nur, wenn es auch als Default deklariert ist, sonst nicht.
Darum ist es in der StringList auch so
Delphi-Quellcode:
weil es so nicht ging
property Value[Name: String]: String ...
property ValueByIndex[Index: Integer]: String ...
Delphi-Quellcode:
seit den class-operators hatte ich mir dann so beholfen
property Value[Name: String]: String ...
property Value[Index: Integer]: String ...
Delphi-Quellcode:
ja, hier wäre auch Variant möglich , aber alles da oben stellt sicher, dass "nur" Integer oder String rein geht (Float, Boolean und Anderes wird direkt vom Compiler bemängelt)
type
TIndexName = record Index: Integer; Name: string; class operator Implicit(Value: Integer): TIndexName; class operator Implicit(Value: String): TIndexName; end; property Value[Name: TIndexName]: String ...; default;
Delphi-Quellcode:
property Value[Name: Variant]: String ...; default;
um sowas machen zu können
Delphi-Quellcode:
xyz.Value[123]
xyz.Value['abc'] xyz[123] xyz['abc'] |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Also habe ich verschiedene Dinge ausprobiert, aber alles falsch ...
property A: TBasicGroupSettings Index 0 read GetA write SetA;default; property B: TBasicGroupSettings Index 1 read GetB write SetB;default; property group[Index: byte]: TBasicGroupSettings read GetB write SetB;default; Denn dort muss String vorhanden sein, nicht Objekt. Das Objekt, das ich manuell in den Getter- und Setter-Implementierungscode implementieren muss. |
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Wo ist da ein "String"?
Und was ist "Falsch"?
Delphi-Quellcode:
gibt es ausschließlich für Array-Property.
; default;
Delphi-Quellcode:
, bzw.
default EineOrdinaleKonstante;
Delphi-Quellcode:
, gibt es dagegen nur für einfache Property.
stored TrueOderFalseOderFunktion;
String: Meinst du sowas?
Delphi-Quellcode:
property Value[GroupABC: Char; Value: string]: string read GetValue write SetValue;
xxx.Value['A', 'start_name'] := 'abc'; xxx['A', 'start_name'] := 'abc'; // wenn mit "default" PS:
Delphi-Quellcode:
läßt der Compiler erstmal durch, aber dann beim Setter/Getter knallt es, weil
property group[Index: Byte = 0]: TBasicGroupSettings read GetB write SetB;
Delphi-Quellcode:
zwar noch geht,
procedure GetB(Index: Byte = 0): TBasicGroupSettings);
es aber hier
Delphi-Quellcode:
leider nicht.
procedure SetB(Index: Byte = 0; Value: TBasicGroupSettings {= nil});
|
AW: einen Datensatzmitgliedsnamen dynamisch zuweisen
Deklaration und Implementierung nur zu Testzwecken ist fertig. Aber das Programm hat jetzt viele Fehler im Anwendungsteil. Ich kann es also nicht als Ganzes kompilieren.
Code:
Jetzt ist die Frage, wie ich das Ganze modifizieren kann, damit ich den Code im Anwendungsteil ändern kann, zum Beispiel gibt es so eine Funktion:
type TBasicSettings = class // the ini.basic
private fGroups: array[0..1] of TBasicGroupSettings; function getA_(G:String): String; procedure setA_(G:String; V: String); function getA(Index: Integer): String; procedure setA(Index: Integer; V: String); function getAA(Index: Integer): String; procedure setAA(Index: Integer; V: String); public AA: TBasicGroupSettings; BB: TBasicGroupSettings; property basic[G:String]: String read GetA_ write SetA_; property A: String Index 0 read GetA write SetA; property B: String Index 1 read GetA write SetA; property group[Index: Integer]: String read GetA write SetA;default; constructor Create; end; type TSettings = record basic: TBasicSettings; // the ini end; implementation constructor TBasicSettings.Create; begin end; function TBasicSettings.getA_(G:String): String; begin Result := 'test'; end; procedure TBasicSettings.setA_(G:String; V: String); begin G := V; end; function TBasicSettings.getA(Index: Integer): String; begin Result := 'test'; end; procedure TBasicSettings.setA(Index: Integer; V: String); begin Index := 0; end; function TBasicSettings.getAA(Index: Integer): String; begin Result := fGroups[0].path; end; procedure TBasicSettings.setAA(Index: Integer; V: String); begin Index := 0; end;
Code:
// definition part - This must be edited to work correctly with newly created properties
procedure get_prefix_and_zeros_count(ini: TSettings; var prefix: string; var count: byte); var i: byte; begin with ini.bVal.A do prefix := copy(start,1,length(start)-length(ini.basic.A.first)); i:=length(prefix); count := 0; repeat if prefix[i]='0' then inc(count); dec(i); until (prefix[i]<>'0') or (i=1); prefix := copy(prefix, 1, length(prefix)-count); end;
Code:
Ich persönlich denke, es wäre am besten, es so anzugehen:
// application part - This must be edited to work correctly with newly created properties
get_prefix_and_zeros_count(ini, ini.bVal.A.prefix, ini.bVal.A.maxZeros2Add); get_prefix_and_zeros_count(ini, ini.bVal.B.prefix, ini.bVal.B.maxZeros2Add);
Code:
get_prefix_and_zeros_count('A');
get_prefix_and_zeros_count('B');
Code:
Aber ist eine Zuordnung auf diese Weise überhaupt möglich?
// definition part changed
procedure get_prefix_and_zeros_count(g: string); var count, i: byte; begin // ini.bVal(g).maxZeros2Add is count of zeros with ini.bVal(g) do begin prefix := copy(start,1,length(start)-length(ini.basic(g).first)); i:=length(prefix); count := 0; repeat if prefix[i]='0' then inc(count); dec(i); until (prefix[i]<>'0') or (i=1); ini.bVal(g, count); prefix := copy(prefix, 1, length(prefix)-count); end; end;
Code:
Also sollte ich es nicht wiederholen, damit es so geht?
ini.bVal(g).prefix :=
Code:
ini.bVal.A.prefix :=
Code:
oder eher
ini.bVal.B.prefix :=
Code:
bVal ist Basic ähnlich, hat aber abgeleitete und berechnete Werte, während Basic die Einstellungen aus der INI-Datei hat.
ini.bVal[g].prefix :=
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:44 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