Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting ListView columns with arrows

I am using Delphi 6 and want to add the functionality of sorting a ListView, like it is done in Windows Explorer.

In a first test, I have (quick&dirty) copied a few source codes from a few sources, and done some small adjustments:

This is what I have so far (only quick&dirty for now):

uses
  CommCtrls;

var
  Descending: Boolean;
  SortedColumn: Integer;

const
  { For Windows >= XP }
  {$EXTERNALSYM HDF_SORTUP}
  HDF_SORTUP              = $0400;
  {$EXTERNALSYM HDF_SORTDOWN}
  HDF_SORTDOWN            = $0200;

procedure ShowArrowOfListViewColumn(ListView1: TListView; ColumnIdx: integer; Descending: boolean);
var
  Header: HWND;
  Item: THDItem;
begin
  Header := ListView_GetHeader(ListView1.Handle);
  ZeroMemory(@Item, SizeOf(Item));
  Item.Mask := HDI_FORMAT;
  Header_GetItem(Header, ColumnIdx, Item);
  Item.fmt := Item.fmt and not (HDF_SORTUP or HDF_SORTDOWN);//remove both flags
  if Descending then
    Item.fmt := Item.fmt or HDF_SORTDOWN
  else
    Item.fmt := Item.fmt or HDF_SORTUP;//include the sort ascending flag
  Header_SetItem(Header, ColumnIdx, Item);
end;

procedure TUD2MainForm.ListView3Compare(Sender: TObject; Item1,
  Item2: TListItem; Data: Integer; var Compare: Integer);
begin
  if SortedColumn = 0 then
    Compare := CompareText(Item1.Caption, Item2.Caption)
  else
    Compare := CompareText(Item1.SubItems[SortedColumn-1], Item2.SubItems[SortedColumn-1]);
  if Descending then Compare := -Compare;
end;

procedure TUD2MainForm.ListView3ColumnClick(Sender: TObject;
  Column: TListColumn);
begin
  TListView(Sender).SortType := stNone;
  if Column.Index<>SortedColumn then
  begin
    SortedColumn := Column.Index;
    Descending := False;
  end
  else
    Descending := not Descending;
  ShowArrowOfListViewColumn(TListView(Sender), column.Index, Descending);
  TListView(Sender).SortType := stText;
end;

The colums can be sorted up- and downwards, but I can't see arrows.

According to this question , my function ShowArrowOfListViewColumn() should have solved the problem.

Is it possible that Delphi 6 does not support this feature, or is there a problem in my code? On the other hand, ListView is IIRC a Windows control, and therefore I expect that the WinAPI renders the arrow graphics, and not the (very old) VCL.

I read at a German website that the arrow graphics have to be added manually, but the solution of that website has the requirement to change CommCtrl.pas of Delphi (because of a glitch when resizing column). But I really dislike modifing the VCL source, especially since I develop OpenSource, and I do not want that other developers change/recompile their Delphi Sources.

Note that I didn't add a XP manifest to my binary, so the app looks like Win9x.

like image 498
Daniel Marschall Avatar asked Sep 28 '15 03:09

Daniel Marschall


People also ask

How do I sort the contents of a listview column?

When you click the header, the contents of the ListView control are sorted in ascending order based on the column that you click. When you click the same column header again, that column is sorted in descending order.

How do I sort a list by column in IComparer?

When you click one of the column headers, the list is sorted in ascending order based on that column. When you click the same column header again, the column is sorted in descending order. The example in this article defines a class that inherits from the IComparer interface.

How do I add a listview to a form?

Add a ListView control to Form1. Size the form to be several inches wide by several inches tall. Paste the following code into the constructor for the form, after the call to the InitializeComponent method: ColumnHeader columnheader;// Used for creating column headers. ListViewItem listviewitem;// Used for creating listview items.

What is lvcolumn in listviewextensions?

Your utility class ListViewExtensions contains invalid (or at least confusing) information. The struct named "LVCOLUMN" is actually a HDITEM structure (as defined in CommCtrl.h for _WIN32_IE < 0x0500).


1 Answers

HDF_SORTDOWN and HDF_SORTUP require comctl32 v6. This is stated in the documentation for HDITEM:

HDF_SORTDOWN Version 6.00 and later. Draws a down-arrow on this item. This is typically used to indicate that information in the current window is sorted on this column in descending order. This flag cannot be combined with HDF_IMAGE or HDF_BITMAP.

HDF_SORTUP Version 6.00 and later. Draws an up-arrow on this item. This is typically used to indicate that information in the current window is sorted on this column in ascending order. This flag cannot be combined with HDF_IMAGE or HDF_BITMAP.

As you explained in your comments, you did not include the comctl32 v6 manifest. That explains what you observe.

Solutions include:

  • Adding the comctl32 v6 manifest, or
  • Custom drawing header arrows.
like image 169
David Heffernan Avatar answered Oct 17 '22 12:10

David Heffernan