4

In Delphi 7, I'm using a TCheckListBox. I want it to use a TStringList rather than a TStrings, so I can set Duplicates to dupIgnore, and Sorted to TRUE.

Can I just do this:

Form1 = class(TObject
    CheckListBox1: TCheckListBox;  // created by the IDE
end;

procedure TForm1.FormCreate
begin
   CheckListBox1.Items.Free;
   CheckListBox1.Items := TStringList.Create;
   CheckListBox1.Items.Sorted := TRUE;
   CheckListBox1.Items.Duplicates := dupIgnore;
end;

Is this safe? Any caveats or suggestions?

EDIT: Removed declaration for MyStringList and added .Items to the last two assignment lines.

EDIT 2: Trying to compile the above, it looks like I'd have to cast the two final lines like this:

        TStringList(CheckListBox1.Items).Sorted := TRUE;
        TStringList(CheckListBox1.Items).Duplicates := dupIgnore;

Although I might be able to get this to run, I'm asking the question because just getting it to run doesn't mean it will always run or is safe.

RobertFrank
  • 7,332
  • 11
  • 53
  • 99
  • What is the purpose of `MyStringList`? – Andreas Rejbrand Dec 11 '11 at 16:58
  • I removed the MyStringList declaration, which was ununused. – RobertFrank Dec 11 '11 at 17:07
  • 2
    I dont think it's a good idea. The `TStrings` created by `TCheckListBox` are actually of type `"TListBoxStrings"` which overrides Put, Get etc methods. the `Sorted` property works fine without the use of TStringList. – kobik Dec 11 '11 at 17:14
  • @kobik, what is `TListBoxStrings` ? As I know, [`TCheckListBox.Items`](http://docwiki.embarcadero.com/VCL/en/CheckLst.TCheckListBox.Items) is declared as [`TStrings`](http://docwiki.embarcadero.com/VCL/en/StdCtrls.TCustomListBox.Items) – TLama Dec 11 '11 at 17:17
  • 1
    yes, but they are created as `FItems := TListBoxStrings.Create;` in `constructor TCustomListBox.Create(AOwner: TComponent);` – kobik Dec 11 '11 at 17:18
  • Time for a list view in virtual mode – David Heffernan Dec 11 '11 at 19:06

1 Answers1

9

You don't control what class TCheckListBox uses to store its items. Assigning the Items property a value only assigns its items to the internal storage.

Also, you shouldn't call Items.Free;. TCheckListBox depends on its internal instance of TListBoxStrings.

To answer your edits in your question: Don't hard-cast the Items property to TStringList, either. The typecast is wrong (the instance exposed by Items is not a TStringList) and will only cause problems.

Edit, to suggest a workaround for what you seem to try to achieve: To keep the checklistbox sorted, you can set its Sorted property to True. To avoid duplicates, you can check the list before adding an item in code.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
  • 1
    You can use an external `TStringList` for storage. In this case, you'll have to create it as virtual, and retrieve the data on need. Note that there is an issue with huge number of items - see http://stackoverflow.com/questions/7144966/how-to-get-rid-of-tlistbox-vertical-scroll-limit – Arnaud Bouchez Dec 11 '11 at 18:35
  • I've taken your advice and pre-sorted my data in a TStringList before adding to the TCheckListbox. But, could you clarify why my approach didn't work. I thought that the whole point of OO was that, here: TStringList was a descendant of TStrings, so I'd be able to substitute a TStringList – RobertFrank Dec 11 '11 at 22:59
  • 1
    If B inherits from A then B is A but A may not be B. (E.g. a dog is an animal but an animal may not be a dog.) In your case, `Items` is declared as `TStrings` so you can safely assume that it's actually a `TStrings` descendant, not more. Assuming `TStringList` is assuming too much, and in this case it's wrong (`Items` does not actually point to a `TStringList` instance). – Ondrej Kelle Dec 11 '11 at 23:07
  • @Robert - From an OO point of view you can substitute any `TStrings` descendant for `Items`. From a practical point of view you can't, because `FItems` is private to the class (unless you resort to horrible hacks). In any case, `TCheckListBox` depends on the functionality provided by its items class: `TListBoxStrings` (another `TStrings` descendant). For instance, TListBoxStrings sends a `LB_ADDSTRING` to the underlying api control after adding an item. TStringList does not do that, it has no notion of an owning ListBox. For this reason a StringList won't serve to your purpose. – Sertac Akyuz Dec 12 '11 at 00:10