views:

340

answers:

2

In Delphi I have an own class which is based on TList. It is TPetList. Every instance of TPetList can have some items of the class TPet. The instance of TPetList is displayed in a TListView component using a for loop.

TPet is based on TObject and has the following fields:

  • city
  • age
  • breed

Now I have a list of checkboxes where the user can tick the breeds he wants to see. So if he only wants to see pets of breed XYZ I want to show only entries which have the value of "breed" set to "XYZ" while the order in TPetList and TListView must remain the same.

How can I do this?

If I delete the items in TPetList and show the rest in TListView, everything's fine until the user wants to see another breed. This breed has been deleted before and can't be showed.

+3  A: 

Instead of deleting, try selecting out a new list. Something like this:

function TPetList.Filter(criteria: TPetCriteria): TPetList;
var
  i: integer;
begin
  result := TPetList.Create;
  for i := 0 to self.Count - 1 do
    if criteria.matches(self[i]) then
      result.add(self[i]);
end;

How you implement the criteria is up to you, but that's the general idea. Remember that the list this returns is a sub-view and does not own the items it contains, so don't free them when you free the filtered list.

Mason Wheeler
Oh, it was so simple :D Thank you very much, this works fine.
+1  A: 

You can store your objects in a data set. (You can use memory datasets like TClientDataSet, JVCL's TjvMemoryData or any other TDataSet descendant including full-blown RDBMS)

In this way you have solved the following problems:

  • Persistence (storage) - your RDBMS will take care of that. In the case of memory datasets you have methods like Load/SaveToFile
  • Sort - There are simple methods to do this or if you'll choose a SQL backend a simple 'SELECT * FROM PETS ORDER BY NAME' will do your job
  • Filter - you can do any reversible filtering on any field with any operator you like. In the case of memory datasets setting the Filter property to Breed="foo" and the Filtered property to 'True' is enough. In the case of RDBMSes you can achieve it in the same way and/or using a standard SQL: 'SELECT * FROM PETS WHERE BREED='foo' ORDER BY NAME. Also you can use OnFilterRecord event for that. Of course you can clear the filter, reversing the action: Setting the Filter property to 'False' - or - issuing an SQL like: 'SELECT * FROM PETS' (without the WHERE clause) etc.
  • Editing - you have dedicated controls for each data type (including grids for multi-row input). Eg. for the 'Age' field the input is restricted to numbers only. And, of course, you have the OnValidate event where you can do a test if 'Age' is between 0 and 33 (for example).

You have all the mechanism in place. Perhaps is better to go on this path rather than to reinvent the wheel.

Thanks, but my Delphi 7 doesn't know TDataSet, I don't know why.
@marco92w: Try looking in the DB unit.
Mason Wheeler
@marco92w: TDataSet is an 'hidden' class. The grandfather of all. You cannot see it. That's why I said TDataSet **descendant**. Look for TClientDataSet (if you have the Architect (? IIRC...) version) or Google for 'JEDI JVCL', install it and look for TjvMemoryData (is on the Jv Data Access page). Also, if you want to use a full-blown database engine go to Delphi 7's help and search for 'Building database applications' (or similar).