Search code examples
c++c++buildervcl

How to custom sort a VCL TListBox?


I'm trying to figure out how to supply my own custom sort method to items and strings in a TListBox.

My list box stores a custom object in its Object property, and I need to use that in the custom sort.

I'm basing the below code on this post (Delphi): Is it possible to sort a TListBox using a custom sort comparator?

My custom sort function looks like this

int __fastcall SortListByValue (TStringList* sl, int item1, int item2)
{
    IniKey* k1 = (IniKey*) sl->Objects[item1];
    IniKey* k2 = (IniKey*) sl->Objects[item2];
    return k1->mValue < k2->mValue;
}

The key values are strings. Currently they can be "-", "Yes", "No" and "Pass".

And the code where it is called is like this:

void __fastcall TMainForm::sortByValueAExecute(TObject *Sender)
{
    Log(lInfo) << "Sorting list based on Values";
    TStringList* sl = new TStringList();
    sl->Assign(imagesLB->Items);
    sl->CustomSort(SortListByValue);
    imagesLB->Items->Assign(sl);
}

The above code does "something" to the list, but its not sorted.

The resulting list starts with "-" items, and all "Yes" items are consecutive. "No" and "Pass" and "-" items are then scrambled.

Any clues?


Solution

  • Your sort function is expected to return a value that is < 0, 0, or > 0, depending on the desired order of the two input parameters. But you are not doing that correctly. You are returning either 0 or 1, but never < 0, because you are returning the (implicitly converted) result of a boolean expression, which can only be false or true.

    You need to change this line:

    return k1->mValue < k2->mValue;
    

    To this instead:

    if (k1->mValue < k2->mValue) return -1;
    else if (k1->mValue > k2->mValue) return 1;
    else return 0;
    

    Alternatively, use the RTL's AnsiCompareStr() or CompareStr() function instead:

    return AnsiCompareStr(k1->mValue, k2->mValue);
    

    return CompareStr(k1->mValue, k2->mValue);