![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Еще по поводу Tlist. Сортировка. [D5, Win2k]
mRodion © (2004-10-08 14:37:00)Господа, огромное Вам спасибо за то, что вы есть и читаете иногда даже полный бред нас новичков...
А вопрос у меня такой:
ИспользуяTlistстрою свой список:
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1097067854&n=0
Хочу реализовать сортировку. Для этого методу Sort списка типаTlistя должен передать в качестве параметра функцию типа
TListSortCompare = function (Item1, Item2: Pointer): Integer;
Почему-то в качестве параметра нельзя передать такую функцию описанную в самом классе, реализующим список (например, в качествеprivateметода классаTMyClassв примере по ссылке выше).
Приходится описывать эту функцию вне класса:
TMyClass = class
private
FMyList:TList
public
procedureAdd (Item:TMyListItem);
procedureDelete (Index:integer);
propertyItems[Index:integer]:TMyListItem readGetItem
end;
functionCompareMyItems (Item1, Item2: Pointer): Integer;
Но тогда если пользователь захочет использовать две копии моего списка, то обе копии будут использовать одну и ту же функцию сравненияCompareMyItems?
Если да, то это не удобно, поскольку в каждой копии класса может быть свой тип сортировки (например по разным полям), и результат сравнения элементов для разных списков может быть разным.
Что делать в этом случае? Можно ли как-нибуть передать в качестве параметра функциюCompareMyItemsописанную внутри класса?
Надеюсь, ясен вопрос, а то что-то слишком длинный получился...
Суслик (2004-10-08 17:38:00) [1]
> но с потоками я уже эксперементирую :)
с ними не надо экспериментровать.
их надо плотно изучать.
поверь моему опыту: когда я прочел разные книги я понял насколья я мало понимал в потоках раньше, хотя считал себя великим экспериментаротом.
Суслик (2004-10-08 17:36:00) [2]
> А если я обрамлю изменение WhoStartsSort с помощью критических
> секций, это поможет в многопоточных использованиях данной
> конструкции?
В общем-то да...
Но в ракурсе действительно профессиональной разработки многопоточных приложений, заточенных на производительность, может быть не все так просто и однозначно. Крит. секция, это первое, что приходит в голову. Но бывают намного более тонкие методы взаимодействия потоков.
mRodion (2004-10-08 17:34:00) [3]Спасибо за поддержку, но с потоками я уже эксперементирую :)
mRodion (2004-10-08 17:33:00) [4]А если я обрамлю изменение WhoStartsSort с помощью критических секций, это поможет в многопоточных использованиях данной конструкции?
procedure tmylist.sort();
begin
SortCriticalSection.Enter;
WhoStartsSort := self;
fList.Sort();
SortCriticalSection.Leave;
end;
Суслик (2004-10-08 17:26:00) [5]
> использоваться в отдельных потоках...
Когда у это случится у тебя будет столько проблем, что ты про TMyList напрочь забудешь. А когда вспомнишь, твой уровень, очевидно, будет выше (с большинством проблем уже справился), так, что проблем реализовать многопоточный TMyList у тебя не будет.
:)
mRodion (2004-10-08 17:23:00) [6]Спасибо. Похоже в однопоточном случае это поможет.
Правда теперь меня будет мучить вопрос, как сделать это и для многопоточного варианта. Потому что в скором времени эти мои списки будут использоваться в отдельных потоках...
Суслик (2004-10-08 17:13:00) [7]
> Правильно понял?
точно.
mRodion (2004-10-08 17:11:00) [8]2Суслик © (08.10.04 16:57) [13]
О! А это идея!
А переменную WhoStartsSort сделать типа TMyList!
Правильно понял?
Суслик (2004-10-08 17:09:00) [9]
> только не знаю заранее все типы сортировок.
Если ты не знаешь все возможные типы сортировки заранее, то у тебя нет иного выбора кроме как предоставить возможность клиенту задавать процедуру сортировки.
Об этом я тебе сказал с самого начала.
Ты хочешь невозможного - типа я (автор класса) ничего не знаю, но хочу сделать пользователю так здорово, чтобы он ничего не задавал, т.е. по сути тоже ничего не знал, но получал, что хотел. Ерунда какая-то: кто-то должен знать, иначе кирдык.
mRodion (2004-10-08 17:07:00) [10]ну так я именно это и пытаюсь сделать.
только не знаю заранее все типы сортировок.
Reindeer Moss Eater (2004-10-08 17:00:00) [11]Тогда свойством твоего класса надо делать не ссылку на процедуру сортировки, а тип сортировки.
А саму реализацию разных типов рисовать в модуле класса.
mRodion (2004-10-08 16:58:00) [12]2Суслик © (08.10.04 16:11) [11]
Ваш пример хорош и красив, но иногда заранее не знаешь, какой порядок сортировки предпочитает пользователь.
Один раз он захочет сортировать сначала по комментариям, потом по датам записей. А потом захочет другую сортировку: по комментариями, а потом по размеру файла, например.
Если есть такие данные:
коммент дата размер
ком1 1 12
ком2 3 10
ком2 1 15
ком1 1 6
И пользователь хочет первый тип сортировки, он может с помощью метода QuickSort получить такой список:
коммент дата размер
ком1 1 12
ком1 1 6
ком2 1 15
ком2 3 10
При этом видим, что размер не в порядке возрастания. Тогда пользователь может захотеть отсортировать вторым способом. Тогда может получить следующий список:
коммент дата размер
ком1 1 6
ком1 1 12
ком2 3 10
ком2 1 15
И когда пользовательских полей не 3, а 30, то я не берусь заранне предсказать все типы сортировок, которые могут понадобиться пользователю. Отсюда и пришла идея разрешить пользователю программы в самом интерфейсе задавать именно порядок сортировки. Почти как в excel'е.
Суслик (2004-10-08 16:57:00) [13]
> как мне в такой ситуации в реализации функции CompareMyItems
> добраться до поля SortOrderList моего класса?
через глобальную переменную ПОД implementation.
например так
procedure tmylist.sort();
begin
WhoStartsSort := self;
fList.Sort();
end;
Переменную WhoStartsSort использовать в процедуре сравнения.
С учетом того, что у тебя приложение однопоточное усе будет ок.
mRodion (2004-10-08 16:46:00) [14]Понял, о чем вы толкуете, только мне нужно немножко не это.
Может быть, я просто других элементарных вещей не понимаю?
Хочу, чтобы функция CompareListItems работала примерно по такому принципу: пользователь задает порядок сортировки у каждого экземпляра класса с помощью одного поля класса (сортировать сначала по одному полю, потом по другому и т.д.). Т.о. создается список из полей сортировки, называемый SortOrderList. Этот список и есть то, что раньше я называл простым словом FSortType.
Соответственно, функция CompareListItems должна знать заданный порядок сортировки. Ее реализацию я вижу примерно такой:
function CompareListItems (Item1, Item2: Pointer): Integer;
var
pdbitem1, pdbitem2:PTMyItem;
i:integer;
begin
pdbitem1 := item1;
pdbitem2 := item2;
result := 0;
i:=0;
if SortOrderList.Count <= 0 then exit;
while ((i<SortOrderList.Count) and (result = 0)) do begin
case SortOrderList.Items[i] of
udFilename :begin
if pdbitem1^.FileName < pdbitem2^.FileName then result := -1
else if pdbitem1^.FileName > pdbitem2^.FileName then result := 1
else result := 0;
end;
udDeviceName:begin
if pdbitem1^.DeviceName < pdbitem2^.DeviceName then result := -1
else if pdbitem1^.DeviceName > pdbitem2^.DeviceName then result := 1
else result := 0;
end;
udDateTime : begin
if pdbitem1^.Time < pdbitem2^.Time then result := -1
else if pdbitem1^.Time > pdbitem2^.Time then result := 1
else result := 0;
end;
udComment:begin
if pdbitem1^.Comment < pdbitem2^.Comment then result := -1
else if pdbitem1^.Comment > pdbitem2^.Comment then result := 1
else result := 0;
end;
end;
inc (i);
end;
end;
Так вот у меня в такой конфигурации одна проблема: я не знаю, как мне добраться до поля SortOrderList моего класса TMyList.
Если быть точным, то описание моего класса-списка выглядит примерно таким:
TMyClass = class
private
FMyList:TList
public
SortOrderList:TSortOrderList;
procedure Add (Item:TMyListItem);
procedure Delete (Index:integer);
property Items[Index:integer]:TMyListItem read GetItem
end;
function CompareMyItems (Item1, Item2: Pointer): Integer;
Попробую задать вопрос так:
как мне в такой ситуации в реализации функции CompareMyItems добраться до поля SortOrderList моего класса?
Суслик (2004-10-08 16:11:00) [15]
> , как узнать тип сортировки в моем в конкретном экземпляре
> класса.
не нужно узнавать.
Насколько я понимаю из твоего примера у тебя сортировок определенное количество видов. Т.е. у тебя TMyList не просто список, я список для определенных целей. Иначе я пример твоего не понимаю.
Тогда все просто - у тебя есть перечислимый признак SortType, где
procedure TMylist.fSetSortType(value: ...)
begin
case Value of
ByName: fSortProc := SortProcByName;
ByComment: fSortProc := SortPRocByComment;
...
end;
end;
где SortProcByName и SortProcByName подimplementation.
в дальнейшем при вызове метода Sort у TList ему передается fSortProc.
Reindeer Moss Eater (2004-10-08 16:08:00) [16]implementation
....
function SortFunction (...):integer;
begin
.....
end;
end.
Reindeer Moss Eater (2004-10-08 16:07:00) [17]как в таком случае нужно определять функцию fCompFunc в разделе implementation.
Её не обязательно определять там.
Её может определить пользователь твоего класса там где захочет.
mRodion (2004-10-08 16:05:00) [18]2Суслик © (08.10.04 14:45) [2]:
Моя идея в том, чтобы сделать свой класс списка, тип сортировки в котором задается отдельным свойством. Я хочу вообще оградить пользователя моего списка от задания каких-бы то ни было функций сортировки. Только свойством.
type
TSortType = (stSortByFilename, stSortByDate, stSortByComment);
TMyList = class
private
FMyList:TList;
FSortType:TSortType;
// e.t.c
public
procedureSort;
// e.t.c
end;
Это для того, чтобы пользователь, используя мой TMyList, мог сделать следующиее:
var
List1:TMyList;
List2:TMyList:
begin
List1 := TMyList.Create;
List2 := TMyList.Create;
//заполнение списков
List1.SortType := stSortByFilename;
List1.Sort;
List2.SortType := stSortByComment;
List2.Sort;
end;
Если в реализации методаTMyList.Sortя буду вызывать функциюCompareMyItems(см. мой вопрос), которая вынесена за пределы описания класса, то у меня стоит вопрос, как узнать тип сортировки в моем в конкретном экземпляре класса.
Если бы эта функция могла определаться внутриTMyList, то я смог бы получить простой доступ к полюFSortTypeи провести соответствующее сравнение. Очень похоже на то, что совет Reindeer Moss Eater © (08.10.04 15:06) [4]- это то, что мне нужно. Только я не понимаю, как в таком случае нужно определять функциюfCompFuncв разделеimplementation.
Суслик (2004-10-08 15:25:00) [19]
> [5] Skier © (08.10.04 15:20)
не, так не выйдет... :)) Поторопился я :)
вызывать метод будет будет tlist. Он же не будет ничего передавать в качестве self. Так, что лажа будет.
ЗЫ. Может я что-то не понял, что было предложено. Поясни тогда свою мысль.
Суслик (2004-10-08 15:22:00) [20]
> хм...а если так TMethod(AObjectProc).Code ?
можно и так, только надо будет первым (кажется) параметром передавать указатель на объект. Можно nil передавать.
Только тогда от клиента, передавшего метод объекта в качестве функции сравнения для tlist, нужно заручится гарантией, что он не будет в этом методе пользоваться self'ом.