Recent

Author Topic: Any better idea to set TTICheckGroup?  (Read 957 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1594
Any better idea to set TTICheckGroup?
« on: April 29, 2024, 01:01:23 pm »
I have set up a TTICheckGroup in following way.

Code: Pascal  [Select][+][-]
  1. interface
  2. type
  3.  
  4.   TColor = (red, blue, green);
  5.   TColors = set of TColor;
  6.  
  7.   TfrmMain = class(TForm)
  8.     TICheckGroup1: TTICheckGroup;
  9.     procedure FormShow(Sender: TObject);
  10.  
  11.   private
  12.     IColors: integer;
  13.     function getColors: TColors;
  14.     procedure setColors(AValue: TColors);
  15.  
  16.   published
  17.      property Colors : TColors read getColors write setColors;
  18.   public
  19.  
  20.   end;
  21.  
  22. implementation
  23.  
  24. {$R *.lfm}
  25.  
  26. procedure TfrmMain.FormShow(Sender: TObject);
  27. begin
  28.   TICheckGroup1.Link.TIObject := Self;
  29.   TICheckGroup1.Link.TIPropertyName := Colors;
  30. end;
  31.  
  32. function PowerOf2 (n:integer) : integer;
  33. var
  34.    ti: integer;
  35. begin
  36.    Result := 1;
  37.    for ti := 1 to n do Result *= 2;
  38. end;
  39.  
  40. function TfrmMain.getColors: TColors;
  41. var
  42.    tc: TColor;
  43. begin
  44.    Result := [];
  45.    for tc := Low(TColor) to High(TColor) do
  46.       if (PowerOf2(Ord(tc)) and IColors) <> 0 then Result += [tc];
  47. end;
  48.  
  49. procedure TfrmMain.setColors(AValue: TColors);
  50. var
  51.    tc: TColor;
  52.    ts: string = '';
  53. begin
  54.    IColors := 0;
  55.    for tc := Low(TColor) to High(TColor) do begin
  56.      if TC in AValue
  57.         then IColors := IColors or PowerOf2(Ord(tc));
  58.    end;
  59. end;
  60.  

The purpose is to save the set result (i.e. IColors) as an integer. This seems to work fine. But do you have any better idea, like declaring Colors as integer, etc.?

egsuh

  • Hero Member
  • *****
  • Posts: 1594
Re: Any better idea to set TTICheckGroup?
« Reply #1 on: April 30, 2024, 03:21:27 am »
I did some further experiments with this. I found following codes succeed.

Code: Pascal  [Select][+][-]
  1. type
  2.   TColor = (red, blue, green, c4, c5, c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,
  3.             c17,c18,c19,c20,c21,c22,c23,c24,c25,c26,c27,c28,c29,c30,
  4.             c31,c32);
  5.   TColors = set of TColor;
  6.  
  7.   TfrmMain = class(TForm)
  8.     TICheckGroup1: TTICheckGroup;
  9.  
  10.   private
  11.     IColors: integer;
  12.     function getColors: TColors;
  13.     procedure setColors(AValue: TColors);
  14.  
  15.   published
  16.      property Colors : TColors read getColors write setColors;
  17. end;
  18.  
  19.   //........................................
  20. implementation
  21.  
  22. function TfrmMain.getColors: TColors;
  23. begin
  24.    Result := TColors(IColors);
  25. end;
  26.  
  27. procedure TfrmMain.setColors(AValue: TColors);
  28. begin
  29.    IColors := Integer(AValue);
  30. end;

Sizes of both TColors and integer are 4, on my system. So they look typecast-able to each other.  But why isn't the size of integer 8 on 64bit machine (and OS)?

Once the number of TColor's element become over 32, i.e. when I add c33, then error message: property Colors:TColors  is not publishable.

Any caveats or comments?


alpine

  • Hero Member
  • *****
  • Posts: 1379
Re: Any better idea to set TTICheckGroup?
« Reply #2 on: April 30, 2024, 08:18:31 am »
I'm using sets to bitpack flags, usually for communication purposes. I do the following:
Code: Pascal  [Select][+][-]
  1. type
  2.   TSetBits32 = Set of 0..31; // Use TSetBits32(LongWord) => Set
  3.   TOrdBits32 = LongWord;     // Use TOrdBits32(TSetBits32) => LongWord
  4.  
  5.   TMyClass = class
  6.   private
  7.     FFlags: LongWord;
  8.     function GetFlagByIndex(AIndex: Integer): Boolean;
  9.     procedure SetFlagByIndex(AIndex: Integer; AValue: Boolean);
  10.   public
  11.     property Flag0: Boolean index 0 read GetFlagByIndex write SetFlagByIndex;
  12.     property Flag1: Boolean index 1 read GetFlagByIndex write SetFlagByIndex;
  13.     {...}
  14.   end;
  15.  
  16. function TMyClass.GetFlagByIndex(AIndex: Integer): Boolean;
  17. begin
  18.   Result := (AIndex in TSetBits32(FFlags));
  19. end;
  20.  
  21. procedure TMyClass.SetFlagByIndex(AIndex: Integer; AValue: Boolean);
  22. begin
  23.   if AValue
  24.     then Include(TSetBits32(FFlags), AIndex)
  25.     else Exclude(TSetBits32(FFlags), AIndex);
  26. end;
  27.  

That way I can publish individually every bit that I want, keeping them bit-packed when I want to transfer them on the wire.
You can declare FFlags as an array of TSetBits32 and subscribe like (AIndex mod 32) in FFlags[AIndex div 32] with bigger number of bits if you want.

EDIT: Sorry, but I've completely missed the TTICheckGroup part. Still drinking my first coffee. But anyway , you can use TTIPropertyGrid in that case :)
« Last Edit: April 30, 2024, 08:46:44 am by alpine »
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

egsuh

  • Hero Member
  • *****
  • Posts: 1594
Re: Any better idea to set TTICheckGroup?
« Reply #3 on: April 30, 2024, 08:44:56 am »
@alpine

Yours is an interesting example as well. Typecasting integer (or longword) to set type is interesting.

 

TinyPortal © 2005-2018