Results 1 to 9 of 9

Thread: Hoe een property goed te gebruiken?

  1. #1

    Hoe een property goed te gebruiken?

    Code:
    TBasicGroupSettings = record
      path: string;
      check_files_exist: boolean;
      start_name: string;
      first: string;
      last: string;
    end;
    Nu mijn proefles...
    Code:
    type TBasicSettings = class
      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
      RAM_disk: string;
      RAM_free: LongWord; // v MB
      start_name_A: string; // first_filename
      AA: TBasicGroupSettings;
      BB: TBasicGroupSettings;
      fps: byte;
      scroll_max_shift: integer;
      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;
    Dit is klasse die ik volledig opnieuw wil ontwerpen:
    Code:
    type TSettings = record
      // ini: TBasicSettings;
      basic: TBasicSettings; // general
      general: TGeneralSettings; // general
      bVal: TDerivedBasicValues; // derived basic values
      gVal: TDerivedGeneralValues; // derived general values
      cValA: TDerivedColorValues; // derived color values for group A
      cValB: TDerivedColorValues; // derived color values for group B
      colA: TSearchColorsSettings; // converted colors TColor definition for group A
      colB: TSearchColorsSettings; // converted colors TColor definition for group B
      searchblurDistanceA:TPrecisionSettings;
      searchblurDistanceB:TPrecisionSettings;
      iaDiA: TDirectionsSettings; // image/arrow dimentions/directions
      iaDiB: TDirectionsSettings; // image/arrow dimentions/directions
    end;
    var ini: TSettings;
    dus in ini.basic is er de klasse TBasicSettings.

    Mijn probleembeschrijving...
    Ik wil toegang krijgen tot de eigenschappen van ini.basic group A of group B van het type TBasicGroupSettings.
    voor het lezen van ini.basic.A.path of ini.basic.B.path ... Dus ik veronderstel dat ik dynamische toegang heb tot A of B.

    Voor zover ik het nu heb, zou ik (met enige kleine aanpassing) de A o B-groep kunnen lezen, maar ik moet toegang krijgen tot alle eigenschappen van de groep.

    En ook voor het schrijven. Ik zou het als volgt willen benaderen:
    ini.basic(group).path := '...'; ini.basic(group).first := '...';
    Is het mogelijk om dat te doen in Delphi 7?

    Hetzelfde met de volgende typen. in ini.bVal zijn waarden die zijn opgeslagen na verwerking van het ini-bestand. Dus ik zou willen lezen en schrijven als ini.bVal(group).prefix of ini.bVal(group).prefix:='000'

    bVal is zo gedefinieerd:
    Code:
    type TDerivedBasicGroupValues = record
      first: integer; // the converted value
      last: integer; // the converted value
      start: string;  // stripped start_name
      prefix: string;
      maxZeros2Add: byte;
    end;
    type TDerivedBasicValues = record // FROM BASIC SETTINGS
      // Derived values:
      A: TDerivedBasicGroupValues;
      B: TDerivedBasicGroupValues;
      working_area_dim: integer; // working area dimentions
    end;
    Het begrijpen van deze dingen is best moeilijk voor mij. Ik was op de pagina aan het kijken
    http://www.delphibasics.co.uk/RTL.asp?Name=Property
    en daar zijn de basisprincipes goed en eenvoudig uitgelegd, maar ik begrijp nog steeds niet hoe ik dit complexere gebruik voor Delphi 7 moet aanpakken, als dat mogelijk is.
    Last edited by chlopik; 07-Jul-22 at 18:10.

  2. #2
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    Ik zie records, ik zie een class (zonder indenting en zonder implementatie), ik zie Engelse tekst tussen een heleboel Nederlands, maar ik snap totaal niet wat je nu wilt.

    Kun je niet in Jip en Janneke taal uitleggen wat je bedoeld of wat je wilt bewerkstelligen?
    (Het mag ook alleen in het Engels als dat makkelijker voor je is, maar niet twee talen door elkaar)
    Last edited by VideoRipper; 07-Jul-22 at 18:07.
    TMemoryLeak.Create(Nil);

  3. #3
    OK, I prefer English.

    I need to create Getter and Setter ... but I don't know how to do it and if is it even possible in Delphi 7. There are two groups of settings called A and B, which have the same properties.
    E.g TBasicGroupSettings. The access Path to read should be ini.basic.A.path and ini.basic.B.path ... I want to access the A and B dynamically. I have a variable group:='A' or just g:='A'. So when I want to get the variable dynamically it would be good to read it like ini.basic('A').path. And if I need to change the value I would like to write it like ini.basic('A').path := 'the path to files'; Is this possible in D7?

    Which of the property declaration of TBasicSettings = class should I use for this purpose and how to implement it?

  4. #4
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    I'm still not sure about the context, but I'll give it a go.

    When you change your records into a class, you can assign then when they're a property (otherwise you'll get an "Left side cannot be assigned to" error):
    Delphi Code:
    1. unit UBasicSettings;
    2.  
    3. interface
    4.  
    5. type
    6.   TBasicGroupSettings = class
    7.   private
    8.     Fpath: string;
    9.     Fcheck_files_exist: boolean;
    10.     Fstart_name: string;
    11.     Ffirst: string;
    12.     Flast: string;
    13.   public
    14.     property path: string read Fpath write Fpath;
    15.     property check_files_exist: boolean read Fcheck_files_exist write Fcheck_files_exist;
    16.     property start_name: string read Fstart_name write Fstart_name;
    17.     property first: string read Ffirst write Ffirst;
    18.     property last: string read Flast write Flast;
    19.   end;
    20.  
    21.   TBasicSettings = class
    22.   private
    23.     FGroups: array of TBasicGroupSettings;
    24.     FGroupA: TBasicGroupSettings;
    25.     FGroupB: TBasicGroupSettings;
    26.     function GetGroups(Index: Integer): TBasicGroupSettings;
    27.   public
    28.     constructor Create;
    29.     destructor Destroy; override;
    30.  
    31.     property Groups[Index: Integer]: TBasicGroupSettings read GetGroups;
    32.     property GroupA: TBasicGroupSettings read FGroupA;
    33.     property GroupB: TBasicGroupSettings read FGroupB;
    34. end;
    35.  
    36. implementation
    37.  
    38. uses
    39.   SysUtils;
    40.  
    41. const
    42.   NumOfGroups = 2;
    43.  
    44. { TBasicSettings }
    45.  
    46. function TBasicSettings.GetGroups(Index: Integer): TBasicGroupSettings;
    47. begin
    48.   if (Index >= 0) and
    49.      (Index < Length(FGroups)) then
    50.     Result := FGroups[Index]
    51.   else
    52.     raise Exception.CreateFmt('Group %d does not exist', [Index]);
    53. end;
    54.  
    55. constructor TBasicSettings.Create;
    56. var
    57.   I: Integer;
    58. begin
    59.   inherited Create;
    60.  
    61.   SetLength(FGroups, NumOfGroups);
    62.   for I := 0 to Pred(Length(FGroups)) do
    63.     FGroups[I] := TBasicGroupSettings.Create;
    64.  
    65.   FGroupA := TBasicGroupSettings.Create;
    66.   FGroupB := TBasicGroupSettings.Create;
    67. end;
    68.  
    69. destructor TBasicSettings.Destroy;
    70. var
    71.   I: Integer;
    72. begin
    73.   FGroupB.Free;
    74.   FGroupA.Free;
    75.  
    76.   for I := 0 to Pred(Length(FGroups)) do
    77.     FGroups[I].Free;
    78.  
    79.   inherited Destroy;
    80. end;
    81.  
    82. end.
    In my code, variables inside a class (they're actually called "Fields") can never be accessed directly, but only by using their public or published getters and setters.
    It it is actually possible to make those fields public (though it's not a proper way of doing things with classes), just like in your record example version.

    Calling code (a form with a button and a memo):
    Delphi Code:
    1. uses
    2.   UBasicSettings;
    3.  
    4. procedure TfrmMain.Button1Click(Sender: TObject);
    5. var
    6.   Settings: TBasicSettings;
    7. begin
    8.   Settings := TBasicSettings.Create;
    9.   try
    10.     Settings.Groups[0].path := 'This is the path to Settings.Groups[0].path';
    11.     Settings.Groups[1].path := 'This is the path to Settings.Groups[1].path';
    12. //    Settings.Groups[2].path := 'This is the path to Settings.Groups[2].path'; // This will result in an exception, since item 2 doesn't exist
    13.  
    14.     Settings.GroupA.path := 'This is the path to Settings.GroupA.path';
    15.     Settings.GroupB.path := 'This is the path to Settings.GroupB.path';
    16.  
    17.     Memo1.Lines.BeginUpdate;
    18.     try
    19.       Memo1.Lines.Clear;
    20.       Memo1.Lines.Add(Settings.Groups[0].path);
    21.       Memo1.Lines.Add(Settings.Groups[1].path);
    22.  
    23.       Memo1.Lines.Add(Settings.GroupA.path);
    24.       Memo1.Lines.Add(Settings.GroupB.path);
    25.     finally
    26.       Memo1.Lines.EndUpdate;
    27.     end;
    28.   finally
    29.     Settings.Free;
    30.   end;
    31. end;
    Am I on the right track?
    Last edited by VideoRipper; 07-Jul-22 at 19:07.
    TMemoryLeak.Create(Nil);

  5. #5
    Thank you a lot. So the only way is to create new class and define all properties to be written. I hoped this is not neccesary, because there are many properties in the next types or classes. It will be long code. Maybe I should separate it to more files to make it more clear...

  6. #6
    I have prepared all files/units based on your code, but I have question.
    Now I have wrapper:
    Code:
    type TSettings = record
      basic: TBasicSettings; // general
      general: TGeneralSettings; // general
      bVal: TDerivedBasicSettings; // derived basic values
      gVal: TDerivedGeneralValues; // derived general values
      cVal: TDerivedColorValues; // derived color values for group A
      col: TSearchColorsSettings; // converted colors TColor definition for group B
      searchblurDistance:TPrecisionSettings;
      iaDi: TDirectionsSettings; // image/arrow dimentions/directions
    end;
    Do I need to change this for class and add constructor
    Code:
    ini.basic: TBasicSettings.create;
    etc.
    and destructor for
    Code:
    ini.basic.destroy; // or ini.basic.free;
    ?

  7. #7
    Fornicatorus Formicidae VideoRipper's Avatar
    Join Date
    Mar 2005
    Location
    Vicus Saltus Orientalem
    Posts
    5,708
    A record doesn't have a constructor and destructor mechanism like a class has, so when you have a class inside a record, you have to instantiate (and free) it from outside the record (but you don't really want that):
    Delphi Code:
    1. var
    2.   Settings: TSettings;
    3. begin
    4.   Settings.basic := TBasicSettings.Create;
    5.   try
    6.     // Do stuff with Settings and Settings.basic
    7.   finally
    8.     Settings.basic.free;
    9.   end;
    10. end;
    You never want to deal with the management of internal fields/variables, so you'd also have to use classes for those as well:
    Delphi Code:
    1. type
    2.   TSettings = class
    3.   private
    4.     Fbasic: TBasicSettings; // general
    5.   public
    6.     constructor Create;
    7.     destructor Destroy; override;
    8.  
    9.     property basic: TBasicSettings read Fbasic;
    10.   end;
    11.  
    12. implementation
    13.  
    14. constructor TSettings.Create;
    15. begin
    16.   inherited Create;
    17.  
    18.   Fbasic := TBasicSettings.Create; // We always create the classes we own in our own (TSettings-) class
    19. end;
    20.  
    21. destructor Destroy;
    22. begin
    23.   Fbasic.Free; // Always call free in the destructor of our own (TSettings-) class / never call Destroy; it will be called automatically by the "Free" method
    24.  
    25.   inherited Destroy;
    26. end;
    Using the TSettings class and its owned property "basic" is done in the same way:
    Delphi Code:
    1. procedure DoMyThing;
    2. var
    3.   S: TSettings;
    4. begin
    5.   S := TSettings.Create; // This will create an instance of TSettings, which in turn will create all classes inside TSettings, including the basic (TBasicSettings) class and everything inside that
    6.   try
    7.     S.basic.GroupA.path := 'This is the path to "S.basic.GroupA.path"';
    8.     // Do other stuff
    9.   finally
    10.     S.Free; // This will free all instances created earlier, inside TSettings, TBasicSettings and TBasicGroupSettings
    11.   end;
    12. end;
    Now we've only taken a look at the memory management (creating/destroying) of classes inside another class, but you can also do other things, like setting classes and variables to their initial state at creation.

    The entire idea behind classes is that a class is always responsible for it's own fields: creation, destruction, turning a value on or off under certain conditions, you name it; any outside calling code should never need to know anything about the inner workings of a class it initializes, other than how to call its methods and access its properties; it should simply appear as a black box.

    This all is basic object oriented programming ("OOP") stuff; you might want to have a look at some resources on-line.
    Last edited by VideoRipper; 08-Jul-22 at 11:11.
    TMemoryLeak.Create(Nil);

  8. #8
    Thank you. So I have finished the declarations. The fields are 6 classes and two records (records are for general purposes, while classes are for containing of two groups of settings).

    Code:
    constructor TSettings.Create;
    begin
      Fbasic := TBasicSettings.Create; // general
      FbVal  := TDerivedBasicSettings.Create; // derived basic values
      FcVal  := TDerivedValuesWrapper.Create; // derived color values for group A
      Fcol   := TSearchColorsSettings.Create; // converted colors TColor definition for group B
      FsearchblurDistance:=TPrecisionSettings.Create;
      FiaDi := TDirectionsSettings.Create; // image/arrow dimentions/directions
    end;
    
    destructor TSettings.Destroy;
    begin
      Fbasic.Free; // general
      // Fgeneral.Free; // general is record
      FbVal.Free; // derived basic values
      // FgVal.Free; // derived general values
      FcVal.Free; // derived color values for group A
      Fcol.Free; // converted colors TColor definition for group B
      FsearchblurDistance.Free;
      FiaDi.Free;
    end;

  9. #9
    I have one more problem. When I change design I cannot assign left value.

    Code:
    ini.cVal.A.hex.arrow_1:=pars[1];
    I think I need to prepare Setter but don't know how.

    Something like
    Code:
    function SetGroups(Index: Integer; Obj: TDerivedValuesRecordWrapper);
    ?
    ini.cVal.A. <-- to get access here to the descendants?

    My redesigned unit:
    Code:
    unit iniDerivedColorValues;
    
    interface
    
    uses Graphics;
    
    type TENUM_Direction = (NO_DIRECTION_SPECIFIED, DIRECTION_DOWN, DIRECTION_UP, DIRECTION_LEFT, DIRECTION_RIGHT);
    
    type
      TValueHexColorStrings = record
        image_1: String; // image_1_hex image_1_color @ZMENIT TYP
        text: String; // text_hex text_color_defaut
        background: String; // background_hex background_color
        arrow_1: String; // arrow_1_hex arrow_1_color
        arrow_2: String; // arrow_2_hex arrow_2_color
        arrow_3: String; // arrow_3_hex arrow_3_color
        heading: String; // heading_color_hex heading_color_default
        heading_2: String; // heading_2_color_hex heading_2_color_default
      end;
      TValueWordColor = record
        i1: Word; // image_1_hex image_1_color @ZMENIT TYP
        hex:  Word; // text_hex text_color_defaut
        b:  Word; // background_hex background_color
        a1: Word; // arrow_1_hex arrow_1_color
        a2: Word; // arrow_2_hex arrow_2_color
        a3: Word; // arrow_3_hex arrow_3_color
        h:  Word; // heading_color_hex heading_color_default
        h2: Word; // heading_2_color_hex heading_2_color_default
      end;
      TValueByteColor = record
        i1: Byte; // image_1_hex image_1_color @ZMENIT TYP
        t:  Byte; // text_hex text_color_defaut
        b:  Byte; // background_hex background_color
        a1: Byte; // arrow_1_hex arrow_1_color
        a2: Byte; // arrow_2_hex arrow_2_color
        a3: Byte; // arrow_3_hex arrow_3_color
        h:  Byte; // heading_color_hex heading_color_default
        h2: Byte; // heading_2_color_hex heading_2_color_default
      end;
      TValueTColorColor = record
        i1: TColor; // image_1_hex image_1_color @ZMENIT TYP
        t: TColor; // text_hex text_color_defaut
        b: TColor; // background_hex background_color
        a1: TColor; // arrow_1_hex arrow_1_color
        a2: TColor; // arrow_2_hex arrow_2_color
        a3: TColor; // arrow_3_hex arrow_3_color
        h: TColor; // heading_color_hex heading_color_default
        h2: TColor; // heading_2_color_hex heading_2_color_default
      end;
      // Records wrapper
      TDerivedValuesRecordWrapper = record
        hex: TValueHexColorStrings;
        c: TValueTColorColor;
        h: TValueWordColor;
        s: TValueByteColor;
        v: TValueByteColor;
      end;
    
      TDerivedValuesWrapper = class
      private
        FGroups: array of TDerivedValuesRecordWrapper;
        FGroupA: TDerivedValuesRecordWrapper;
        FGroupB: TDerivedValuesRecordWrapper;
        function GetGroups(Index: Integer): TDerivedValuesRecordWrapper;
        function SetGroups(Index: Integer; Obj: TDerivedValuesRecordWrapper);
      public
        constructor Create;
        destructor Destroy; override;
        property Groups[Index: Integer]: TDerivedValuesRecordWrapper read GetGroups;
        property A: TDerivedValuesRecordWrapper read FGroupA;
        property B: TDerivedValuesRecordWrapper read FGroupB;
      end;
    
    implementation
    
    uses SysUtils;
    
    const
      NumOfGroups = 2;
    
    { TDerivedColorValues }
    
    function TDerivedValuesWrapper.GetGroups(Index: Integer): TDerivedValuesRecordWrapper;
    begin
      if (Index >= 0) and
         (Index < Length(FGroups)) then
        Result := FGroups[Index]
      else
        raise Exception.CreateFmt('Group %d does not exist', [Index]);
    end;
    
    constructor TDerivedValuesWrapper.Create;
    var
      I: Integer;
    begin
      inherited Create;
    end;
    
    destructor TDerivedValuesWrapper.Destroy;
    begin
      inherited Destroy;
    end;
    
    
    end.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •