Delphi-int.ru: портал программистов

Вход Регистрация | Забыли пароль?

События

Сегодня:
Вопросы0    Ответы0    Мини-форумы0


Последние:
Вопрос09.08, 09:39 / #6696
Ответ29.03, 23:32 / #6682
Новости8 июля 2023


Сейчас онлайн:
На сайте — 17
На IRC-канале — 2

Ссылки

Поменять местами элементы в ListView. Миссия выполнима

Уж сколько имею опыта программировании на Delphi, а с такой задачей пришлось столкнуться впервые. Метода Exchange или Swap, к своему удивлению, не нашёл.

Что мы там ещё имеем? Свойство Index у элемента только на чтение, да и, само собой, информацию об одном из элементов нужно слить в какой-то временный буфер. Возникло горячее желание создать отдельно стоящий TListItem без владельца и сделать классический треугольник как в каком-нибудь учебнике. Осторожно заглянув в исходный код, возможна ли такая картина, ужаснулся от кода деструктора:

destructor TListItem.Destroy;
begin
  FDeleting := True;
  if Owner.Owner.FLastDropTarget = Self then
    Owner.Owner.FLastDropTarget := nil;
  if ListView.HandleAllocated then ListView_DeleteItem(Handle, Index);
  FSubItems.Free;
  inherited Destroy;
end;

Дело пахло AccessViolation'ом. Собирался было воспользоваться комбоприемом Insert-копирование-Delete, но быстро взял себя в руки, так как изобретателей велосипедов у нас в стране хватает. Вспомнил, где такая задача была у одного из моих коллег, и полез в его код.

//--------------------------------------------------------------
//  Обмен между двумя Item
//--------------------------------------------------------------
procedure TSyncForm.SwapItems(Index1, Index2: Integer);
Var NewIndex: Integer;
begin
  With SyncListView do
  begin
    Items.BeginUpdate;
    Items.Add();
    NewIndex := Items.Count-1;
    try
      Items[NewIndex] := Items[Index1];
      Items[Index1]   := Items[Index2];
      Items[Index2]   := Items[NewIndex];
      Items.Delete(NewIndex);
    finally
      Items.EndUpdate;
    end;
  end;
end;

Хотел уже было перетаскивать этот код в свой проект, но как-то напрягало меня это движение «туда-сюда» — «Add-Delete>». Обратившись к поисковикам, обнаружил, что в интернете данный код является стандартом де`факто в деле обмена элементами, и был практически скопирован с одной из страниц.

Покопавшись ещё немного в исходниках VCL, решил попробовать воспользоваться низкоуровневыми функциями модуля CommCtrl. В результате у меня появилась такая процедура:

uses CommCtrl;
 
.....
 
procedure SwapItem(aList: TListView; aIndex1, aIndex2: Integer);
var
  item1, item2: TLVItem;
begin
  item1.mask := LVIF_PARAM;
  item1.iSubItem := 0;
  item2 := item1;
  item1.iItem := aIndex1;
  item2.iItem := aIndex2;
  if not ListView_GetItem(aList.Handle, item1) or
      not ListView_GetItem(aList.Handle, item2) then Exit;
  item1.iItem := aIndex2;
  item2.iItem := aIndex1;
  if not ListView_SetItem(aList.Handle, item1) or
      not ListView_SetItem(aList.Handle, item2) then
    raise EListError.CreateFmt('Error exchange items %d and %d!', [aIndex1, aIndex2]);
end;

Квазимодо, конечно, внешностью не блещет, но работу делает. Жду отзывов.

Автор: DNK

Статья добавлена: 25 июня 2013

Следующая статья: Обучающий курс. 1. Введение в Delphi »

Рейтинг статьи: нет Голосов: нет Ваша оценка:

Зарегистрируйтесь/авторизируйтесь,
чтобы оценивать статьи.


Статьи, похожие по тематике

 

Для вставки ссылки на данную статью на другом сайте используйте следующий HTML-код:

Ссылка для форумов (BBCode):

Быстрая вставка ссылки на статью в сообщениях на сайте:
{{a:56}} (буква a — латинская) — только адрес статьи (URL);
{{статья:56}} — полноценная HTML-ссылка на статью (текст ссылки — название статьи).

Поделитесь ссылкой в социальных сетях:


Комментарии читателей к данной статье

Пока нет комментариев к данной статье. Оставьте свой и он будет первым.

Оставлять комментарии к статьям могут только зарегистрированные пользователи.