• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 806
  • Last Modified:

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
0
mwbowman
Asked:
mwbowman
  • 4
  • 4
1 Solution
 
StevenBCommented:
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?
0
 
mwbowmanAuthor Commented:

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.
 
0
 
StevenBCommented:
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
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
StevenBCommented:
...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;
0
 
mwbowmanAuthor Commented:

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
0
 
StevenBCommented:
Well, of course, the code can be split out so that you can call the same functionality from other locations rather than just the click handler. For example this version uses a button on the form to call the appropriate code:

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;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure ClickCheckHandler(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    function OptionChecked(aListBox: TCheckListBox; Option: Integer): Boolean;
    procedure DoCheckOptions(aListBox: TCheckListBox);
  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;

function TForm1.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;

procedure TForm1.DoCheckOptions(aListBox: TCheckListBox);
begin
  if OptionChecked(aListBox, OPTION_A) then
    ShowMessage('A');

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

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

procedure TForm1.ClickCheckHandler(Sender: TObject);
var
  aCheckListBox : TCheckListBox;
begin
  if Sender is TCheckListBox then
    DoCheckOptions(TCheckListBox(Sender));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoCheckOptions(CheckListBox1);
end;

end.
0
 
mwbowmanAuthor Commented:

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?
0
 
mwbowmanAuthor Commented:

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...  ;-)
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 4
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now