В работе понадобилось использовать контрол CListCtrl библиотеки MFC таким образом, что в нем добавляются и удаляются отдельные строки, и по смыслу данных их лучше видеть в сортированном виде. Для этого после каждого удаления и добавления нужно вызвать функцию сортировки списка элементов. Оказалось, что в библиотеке MFC, в отличие от более продвинутых, это сделать не так просто, поскольку MFC это довольно легковесный переходник на контролы Win32. Разобрался и для памяти решил оставить заметку, ну и может еще кому пригодится.
Положим, что есть объект
Функция сортировки имеет прототип
В моем случае это был действительно уникальный в рамках набора элементов код, для каждого элемента списка свой. Если такого нельзя придумать, то надо заводить массив объектов и прописывать в CListCtrl::SetItemData указатель на соответствующий.
Мне надо было отсортировать по строке записанной в первой колонке списка. Для этого надо по коду ассоциированному с элементом получить номер элемента списка и по номеру получить строку первой колонки. И собственно сам код получился таким:
Удачи и успехов)))
Положим, что есть объект
CListCtrl lwObjects;Чтобы вызвать сортировку, надо передать функции SortItems() указатель на функцию сортировки предопределенного прототипа и указатель или данные контекста сортировки.
Функция сортировки имеет прототип
int CALLBACK CompareLVItems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)И должна вернуть коды в соглашениях языка Си - либо отрицательное значение если первый элемент меньше, либо 0 если элементы равны либо положительное. Неприятность состоит в том, что если в параметр lParamSort передается наш контекст сортировки, который мы передали в функцию SortItems, то в параметры lParam1 и lParam2 передаются не указатели на элементы списка, а данные, которые были ассоциированы с этими элементами вызовом функции CListCtrl::SetItemData. Поэтому во-первых мы вынуждены использовать эту функцию и придумать некий идентифицирующий код или указатель, по которому сможем найти как эти элементы должны быть отсортированы.
В моем случае это был действительно уникальный в рамках набора элементов код, для каждого элемента списка свой. Если такого нельзя придумать, то надо заводить массив объектов и прописывать в CListCtrl::SetItemData указатель на соответствующий.
Мне надо было отсортировать по строке записанной в первой колонке списка. Для этого надо по коду ассоциированному с элементом получить номер элемента списка и по номеру получить строку первой колонки. И собственно сам код получился таким:
static int CALLBACK CompareLVItems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { // lParamSort is pointer to CListCtrl CListCtrl* pListCtrl = (CListCtrl*) lParamSort; // lParam1 and lParam2 are not pointers to items and are not item indices, // there are assisiated data, so we need to find them first, // and keep this data sort-avare LVFINDINFO info; info.flags = LVFI_PARTIAL | LVFI_PARAM; info.lParam = lParam1; int n1 = pListCtrl->FindItem(&info); info.lParam = lParam2; int n2 = pListCtrl->FindItem(&info); CString strItem1 = pListCtrl->GetItemText(n1, 0); CString strItem2 = pListCtrl->GetItemText(n2, 0); return strItem1.CompareNoCase(strItem2); }; ... lwObjects.SortItems( CompareLVItems, (DWORD_PTR)&lwObjects); ...Хотя в документации Microsoft написано что DWORD_PTR это 32 битное значение, на самом деле это устаревшие сведения и суффикс _PTR решает проблему для x64 систем. И тип DWORD_PTR и тип LPARAM переносят указатели x64 без проблем.
Удачи и успехов)))
Комментариев нет:
Отправить комментарий