在代码中设置cxTreeList按多列排序

本文介绍了cxTreeList组件在Delphi中的使用技巧,特别是如何实现多列排序功能。通过修改源码并调整SortOrder属性,可以实现在不丢失其他列排序的情况下设置新的排序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为cxTreeList比cxGrid更简单易用,所以在一些需要显示非数据绑定列表的场合,我通常都会选择使用cxTreeList。
cxTreeList和cxGrid一样,都支持多列排序,只需将OptionsBehavior.MultiSort属性设置成True就可以了。
在运行期设置多列排序很简单,按住Shift键依次点击表头,就会按照点击的顺序进行多列排序。

上面的效果就是按住Shift键依次点击『年级』、『班级』、『姓名』得到的。

可是想要在代码中实现同样的效果却遇到了问题,ExpressQuantumGrid的帮助Sorting Data有一段Demo,代码如下:

ContractedBlock.gifExpandedBlockStart.gifCode
1  tvCustomers.BeginUpdate;
2  tvCustomers.DataController.ClearSorting(True);
3  tvCustomersState.SortOrder := soDescending;
4  tvCustomersCity.SortOrder := soAscending;
5  tvCustomersLastName.SortOrder := soAscending;
6  tvCustomers.EndUpdate;


按照上面的Demo去依次设置cxTreeList,却发现设置后只有最后一列正确设置为排序状态。当设置第二个列的排序状态时,会自动清除第一个列的排序设置。Column有一个SortIndex属性,原本是用来标识列的排序顺序的,可是当设置列的SortOrder时,其他列的SortOrder会自动设置为soNone,SortIndex也为自动设置为-1。
研究了一下cxTreeListColumn的源码,发现设置SortOrder会执行SetSortOrder,而SetSortOrder会调用ChangeSortOrder,最终会调用TcxCustomTreeList.ColumnSortOrderChanged。

ContractedBlock.gifExpandedBlockStart.gifCode
 1// cxTL.pas(997)
 2    property SortOrder: TcxDataSortOrder read FSortOrder write SetSortOrder default soNone;
 3
 4// cxTL.pas(8138)
 5procedure TcxTreeListColumn.SetSortOrder(AValue: TcxDataSortOrder);
 6begin
 7  ChangeSortOrder(AValue, []); // 这里的 AShift = []
 8end;
 9
10// cxTL.pas(7721)
11procedure TcxTreeListColumn.ChangeSortOrder(
12  ASortOrder: TcxDataSortOrder; AShift: TShiftState);
13begin
14  if not Options.Sorting or not CanSort then
15    ASortOrder := FSortOrder;
16  if ASortOrder <> FSortOrder then
17  begin
18    FSortOrder := ASortOrder;
19    TreeList.ColumnSortOrderChanged(Self, AShift); 
20    TreeList.Modified;
21  end;
22end;
23
24// cxTL.pas(21508)
25procedure TcxCustomTreeList.ColumnSortOrderChanged(
26  AColumn: TcxTreeListColumn; AShift: TShiftState);
27var
28  AIndex: Integer;
29begin
30  BeginUpdate;
31  try
32    if ssCtrl in AShift then
33      AColumn.CancelSorting
34    else
35    begin
36      if not IsLoading and (not OptionsBehavior.MultiSort or not (ssShift in AShift)) then // AShift 是 []
37      begin
38        for AIndex := 0 to ColumnCount - 1 do // 这里导致所有的列取消排序
39          if Columns[AIndex] <> AColumn then
40            Columns[AIndex].CancelSorting; 
41      end;
42      if FSortedColumns.IndexOf(AColumn) < 0 then
43      begin
44        AIndex := FSortedColumns.Add(AColumn);
45        if not IsLoading then
46          AColumn.FSortIndex := AIndex;
47      end;
48    end;
49    FChanges := FChanges + [tcData, tcSortOrder];
50  finally
51    EndUpdate;
52  end;
53end;

在上面代码的第7行,我们可以看出AShift参数传入的是[],因此在上面代码的第36行会执行清除所有列排序的操作。

原因是找到了,问题就好办了,只需要在设置SortOrder的时候将AShift参数设置为[ssShift]就可以了,可是ChangeSortOrder是protected的,无法直接调用。
怎么办?这个是老把戏了。

ContractedBlock.gifExpandedBlockStart.gifCode
 1type
 2  TAccesscxTreeListColumn = class(TcxTreeListColumn);
 3
 4procedure TMainForm.FormCreate(Sender: TObject);
 5begin
 6  tlStudent.BeginUpdate;
 7  try
 8    tlStudent.ClearSorting;
 9    tlStudentGrade.SortOrder := soAscending;
10    TAccesscxTreeListColumn(tlStudentClass).ChangeSortOrder(soAscending, [ssShift]);
11    TAccesscxTreeListColumn(tlStudentName).ChangeSortOrder(soAscending, [ssShift]);
12  finally
13    tlStudent.EndUpdate;
14  end;
15end;

 

转载于:https://www.cnblogs.com/xinnia/archive/2009/09/05/cxTreeListMultiSort.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值