Для этого мы должны воспользоваться одним из возможных вариантов метода DoSort или DoSortEx:
procedure DoSort(Fields: array of const; Ordering: array of Boolean); virtual;
procedure DoSortEx(Fields: array of integer; Ordering: array of Boolean); overload;
procedure DoSortEx(Fields: TStrings; Ordering: array of Boolean); overload;
Метод DoSortEx доступен в FIBPlus начиная с версии Delphi 4.
Первый параметр всех трех процедур - это список полей, по которым мы хотим отсортировать данные. В случае DoSort это могут быть названия полей или номера полей. Первый вариант DoSortEx позволяет нам использовать только список с номерами полей, а второй вариант DoSortEx предполагает, что мы заполнили список Fields названиями полей. Параметр Ordering во всех трех случаях указывает направление сортировки по каждому из полей. Таким образом, мы можем отсортировать наш запрос по полю FIRST_NAME следующим образом:
DoSort(['FIRSN_NAME'], [True]);
Или: DoSortEx([1], [True]);
[True] означает, что поле сортируется по возрастанию (ASCENDING).
В сущности, использование этих методов очевидно, однако иногда возникает вопрос, связанный с динамическим формированием списков полей. Рассмотрим подробнее наш пример, который демонстрирует, как создавать параметры для DoSortEx динамически. Предполагается, что пользователь сможет нажимать на заголовки DBGridl, указывая, таким образом, поле, которое будет участвовать в сортировке. Повторное нажатие на колонку, которая уже участвует в сортировке, будет изменять порядок сортировки по этой колонке на противоположный. Сначала мы опишем вспомогательный класс для хранения информации о молях, которые будут участвовать в сортировках.
type
TOrderStringList = class(TStringList)
protected
function GetAscending(Index: Integer): boolean;
procedure SetAscending (Index: Integer; Value: boolean);
public
property Ascending[Index: Integer]: boolean read
GetAscending write SetAscending;
end;
...
{ TOrderStringList }
function TOrderStringList.GetAscending(Index: Integer):
boolean;
begin
Result := boolean(integer(Objects[Index]));
end;
procedure TOrderStringList.SetAscending(Index: Integer; Value:
boolean);
begin
Objects [ Index] := pointer (integer (Value));
end;
Очевидно, что данный класс является списком строк - названия полей, а также хранит для каждого поля, включенного в список, порядок сортировки в виде свойства Ascending. Ниже вы видите описание класса формы, а также два основных обработчика событий (OnCreate, OnDestroy). При создании формы мы создаем экземпляр класса TOrderStringList, а при ее уничтожении - удаляем.
TMainForm = class(TForm)
MainDB: TpFIBDatabase;
MainDS: TpFIBDataSet;
MainTr: TpFIBTransaction;
DataSourcel: TDataSource;
DBGridl: TDBGrid;
Buttonl: TButton;
Label2: TLabel;
procedure DBGridlTitleClick(Column: TColumn);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
SortFields: TOrderStringList;
procedure ReSort;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
SortFields := TOrderStringList.Create;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
SortFields.Free;
end;
Теперь напишем обработчик события OnTitleClick у компонента DBGridl:
procedure TMainForm. DBGndlTitleCiiCK (Column: TColumn);
const OrderScr: array [boolean] of string = ('(DESC)',
'(ASC) ') ;
var aField: string;
aFieldlndex: integer;
begin
aField := Column.FieldName;
aFieldlndex := SortFields.IndexOf(aField) ;
if aFieldlndex = -1 then begin
SortFields.Add(aField);
SortFields.Ascending[SortFields.Count - 1] := true;
Column.Field.Display-Label := Column. Field.FieldName + OrderStr[true];
end
else begin
SortFields.Ascending[aFieldlndex] := not
SortFields.Ascending[aFieldlndex];
Column.Field.Display-Label := Column.Field.FieldName +
OrderStr[SortFields.Ascending[aFieldlndex]];
end;
ReSort;
end;
Смысл обработчика состоит в следующем: при нажатии пользователем на заголовок мы проверяем, есть ли данное поле в нашем списке сортировки. Если нет, то мы добавляем его и формируем новый заголовок для колонки, который теперь будет состоять из названия поля и порядка сортировки (ASC) или (DESC). Если же поле уже было включено в сортировку, то мы лишь меняем порядок сортировки. В обоих случаях мы должны вызвать процедуру ReSort, описанную ниже:
procedure TMainForm.ReSort;
var Orders: array of boolean;
Index: Integer;
begin
if SortFields.Count = 0 then begin MainDS.CloseOpen(false);
exit;
end;
SetLength(Orders, SortFields.Count);
for Index := 0 to pred(SortFields.Count) do
Orders[Index] := SortFields.Ascending[Index];
MainDS.DoSortEx(SortFields, Orders);
end;
Данная процедура формирует списки для метода DoSortEx на основе списка SortFields и пересортировывает записи. В случае, если наш список сортировки пустой, мы должны вернуться к "стандартному" порядку записей. Для этого вызывается метод CloseOpen.
Параметр False означает, что мы не хотим автоматически получать сразу все записи от сервера.