Link to home
Start Free TrialLog in
Avatar of mwbowman
mwbowman

asked on

Dynamically Loading/interrogating ComboCheckBox Item List

Hi All,

I'm using a 3rd-party CheckComboBox component and I'm while there is no "Tag" property for each item, I'm wondering if someone knows of a way to simulate the "Tag" for referencing an item later, instead of having to address the control and item index directly.

Here's what I'm doing now...

  { Add CheckComboBox Items }
  with CheckComboBoxOptions do
  begin
    Items.Clear;
    Items.Add('Option 1');
    Items.Add('Option 2');
    Items.Add('Option 3');
  end;

  { Option #1 }
  if CheckComboBoxOptions.Checked[0] then
  begin
    // do something;
  end;

  { Option #3 }
  if CheckComboBoxOptions.Checked[2] then
  begin
    // do something;
  end;

I would like to simplify this so the following could be done instead:

  { Option #1 }
  if Option1 then
  begin
    // do something
  end;

  { Option #3 }
  if Option3 then
  begin
    // do something
  end;

Where Option1 & Option2 are the simulated "tags", which in this case would also need to be boolean variables.

The reasons for this are:

1.  I'd like to be able to associate Option1 with any CheckComboBox control without having to modify the code.

2.  It would allow me to hide items (skip the hidden ones by rebuilding the list) because I would no longer have to worry about absolute item indexes.

3.  I can't rely the strings because I may wish to change them and/or provide multi-language support in the future.

Any ideas?

Mark
Avatar of StevenB
StevenB

If the Items property of the CheckComboBox you are using is a TStrings then you can store an integer value with each Item in the TStrings.Objects property by doing something like this:

    Items.AddObject('Option 1', Pointer(1));

You can then dereference this value like this:

    i := Integer(Items.Objects[Index])

I'm not entirely sure what you're asking in your question, but possibly something along these lines might help?
Avatar of mwbowman

ASKER


StevenB

And I'm not sure if I understand you're answer.  :-)

Your initial statement "(Items.AddObject('Option 1', Pointer(1));" seems to be compatible with my CheckComboBox, or at least it doesn't cause any compiler errors and appears to operate as expected.

However I'm having trouble with your dereferencing example, as "Items" creates an "Undeclared Identifier" error.

But continueing with your idea, I would need to use "Pointer(1)" to determine the "Checked" parameter of the associated item from the list, or simply:

    { Test & Process Option #1 }
    if Pointer(1) then
    begin
        // do something
    end;

The point here is I must be able to process the "Checked" parameter without knowing which CheckComboBox control and/or item from the list it came from.
 
What I'm getting at is something like this. I don't have your CheckComboBox control, so I've used a CheckListBox, but the principle should be the same. Create a new project, drop three TCheckListBox Controls on the form and assign their OnClickCheck handlers to the ClickCheckHandler in the code below (also assign the form's OnCreate to the appropriate handler)

I might still not understand exactly what your driving at, but the principle is that the items in the lists have a unique ID that is divorced from their actual indexes. This is what I understand your simulated Tag suggestion to mean.



unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, CheckLst;

const
  OPTION_A = 1;
  OPTION_B = 2;
  OPTION_C = 3;

type
  TForm1 = class(TForm)
    CheckListBox1: TCheckListBox;
    CheckListBox2: TCheckListBox;
    CheckListBox3: TCheckListBox;
    procedure FormCreate(Sender: TObject);
    procedure ClickCheckHandler(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  CheckListBox1.Items.AddObject('Option A', Pointer(OPTION_A));
  CheckListBox1.Items.AddObject('Option B', Pointer(OPTION_B));
  CheckListBox1.Items.AddObject('Option C', Pointer(OPTION_C));
  CheckListBox2.Items.AddObject('Option C', Pointer(OPTION_C));
  CheckListBox2.Items.AddObject('Option A', Pointer(OPTION_A));
  CheckListBox3.Items.AddObject('B Option', Pointer(OPTION_B));
  CheckListBox3.Items.AddObject('A Option', Pointer(OPTION_A));
  CheckListBox3.Items.AddObject('C Option', Pointer(OPTION_C));
end;

procedure TForm1.ClickCheckHandler(Sender: TObject);

  procedure DoOption(aListBox : TCheckListBox; Index : Integer);
  var
    iOption : Integer;
  begin
    iOption := Integer(aListBox.Items.Objects[Index]);
    case iOption of
      OPTION_A : ShowMessage('A');
      OPTION_B : ShowMessage('B');
      OPTION_C : ShowMessage('C');
    end;
  end;

var
  aCheckListBox : TCheckListBox;
  i : Integer;
begin
  if Sender is TCheckListBox then
  begin
    aCheckListBox := TCheckListBox(Sender);
    for i := 0 to aCheckListBox.Items.Count -1 do
    begin
      if aCheckListBox.Checked[i] then
        DoOption(aCheckListBox, i);
    end;
  end;
end;

end.








Are we on the right track?

Steven
...or alternatively, but still essentially the same principle, you could do something like this in the click handler, which is perhaps closer to your request:

procedure TForm1.ClickCheckHandler(Sender: TObject);

  function OptionChecked(aListBox : TCheckListBox; Option : Integer) : Boolean;
  var
    i : Integer;
  begin
    Result := False;
    i := 0;
    while (i < aListBox.Items.Count) and not Result do
    begin
      if (Integer(aListBox.Items.Objects[i]) = Option) and aListBox.Checked[i] then
        Result := True;
      Inc(i);
    end;
  end;

var
  aCheckListBox : TCheckListBox;
begin
  if Sender is TCheckListBox then
  begin
    aCheckListBox := TCheckListBox(Sender);

    if OptionChecked(aCheckListBox, OPTION_A) then
      ShowMessage('A');

    if OptionChecked(aCheckListBox, OPTION_B) then
      ShowMessage('B');

    if OptionChecked(aCheckListBox, OPTION_C) then
      ShowMessage('C');
  end;
end;

StevenB

I think you may be onto something...

Although I have not tested your examples yet, the only problem I can see is that you are handling with "OptionChecked(aCheckListBox, OPTION_A)" statement within the "ClickCheckHandler" and I would need to perform this type of logic an any point in the application.

So assuming this is possible, perhaps you could provide an example using this method and I'll get that version.

Mark
ASKER CERTIFIED SOLUTION
Avatar of StevenB
StevenB

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

StevenB,

I've been a little busy and wasn't able to check your last suggestion until today.

I tried you last suggestion with my CheckComboBox and it won't work because the following raises a "Too many actual parameters" error:

    CheckListBox1.Items.AddObject('Option A', Pointer(OPTION_A));

So I tried it on a standard ComboBox and the result was the same.

Unfortunately my application must use the (Check)ComboBox control.

Any other suggestions?

StevenB

I just discovered why it didn't work!

I was trying to use:

    CheckListBox1.Items.Add('Option A', Pointer(OPTION_A));

Instead of:

    CheckListBox1.Items.AddObject('Option A', Pointer(OPTION_A));

So the problem is solved and your solution works perfectly!

Thanks for your help.

P.S.  Now if I could only find a way to delete comments from the Experts Exchange...  ;-)