Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сортировка в CListCtrl, путацница с LPARAM 
V
    Опции темы
Rickert
Дата 6.10.2006, 07:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: нет
Всего: 52



Вот, у меня таблица в которой порядка 3000 записей. 4 колонки в ней.
В первой колонке - номера телефонов, а во второй - имена.
Организовал стандартную сортировку. Интересный стёг наблюдаю теперь: сортировка работаёт только в одну сторону и то, не всегда. Т.е. я нажимаю на сортировку по телефонам - сортирует. Нажимаю второой раз - сортирует неправильно. Причём после этого(после второго нажатия), если начать сортировку по именам, то она опять-таки неправильно отсортирует. Я так думаю, что после сортировки надо переназначть lParam всем item'ам, ибо при дебуге видно, что она пытается сравнивать 297 с 1928 и т.п.
Но тогда появляется овпрос: как сменить lParam itemэа?

Это сообщение отредактировал(а) Rickert - 6.10.2006, 08:13


--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Earnest
Дата 6.10.2006, 08:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Нет, как раз lParam никому менять не надо: ты повелся на дурацкий пример сортировки из MSDN, где для сравнения итемы извлекаются из списка. А это глупо. lParam служит для связи с данными приложения, которые не должны меняться при сортировке. Т.е. допустим у тебя есть массив элементов, которые ты и размещаешь в списке. В lParam записываются индексы этих элементов. При сортировке ты извлекаешь элемент из своего массива, порядок которого никто не менял! И сравниваешь - по маме, по папе, по телефону... Таким образом, в качестве дополнительного параметра в функцию сортировки тебе надо передать свой массив, а не контрол.
Если твои данные организованы как список, то в lParam нужно записывать не номер, а адрес элемента, и тоже все будет нормально.
Главное помнить: нет никакого смысла записывать в lParam номер элемента в списке: он и без того известен! lParam нужен для связи с данными, хранящимися в твоем коде.


--------------------
...
PM   Вверх
Rickert
Дата 6.10.2006, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: нет
Всего: 52



Earnest, только что поменял код на запись адреса при добавлении элемента списка в таблицу:
Код

...
    while(tmp)
    {
        _item.mask = LVIF_TEXT | LVIF_PARAM;
        _item.pszText = tmp->abonentNum.GetBuffer();
        _item.iSubItem = 0;
        _item.lParam = (LPARAM)tmp;
        m_Table.InsertItem(&_item);

        m_Table.SetItemText(_item.iItem, ++(_item.iSubItem), tmp->fio.GetBuffer());

        m_Table.SetItemText(_item.iItem, ++(_item.iSubItem), tmp->date.GetBuffer());

        if (tmp->state == ACCESS)
            m_Table.SetItemText(_item.iItem, ++(_item.iSubItem), "Включён");
        else
            m_Table.SetItemText(_item.iItem, ++(_item.iSubItem), "Отключён");
        tmp = tmp->next;
    }
...

Вообще ничего не сортирует.

Это сообщение отредактировал(а) Rickert - 6.10.2006, 08:20


--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Earnest
Дата 6.10.2006, 08:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Что такое tmp?
Как ты делаешь сортировку? Суть ведь именно в этом.
Кроме того, если твои данные хранятся в массиве, адрес элемента использовать не стоит: а вдруг ты добавишь элемент? В этом случае лучше индекс.


--------------------
...
PM   Вверх
Rickert
Дата 6.10.2006, 08:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: нет
Всего: 52



Earnest, tmp - это указатель на мой класс, где храняться данные. Храняться не в массиве, а в списке.


--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Earnest
Дата 6.10.2006, 08:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



ОК, тогда покажи как сортировку реализуешь.


--------------------
...
PM   Вверх
Rickert
Дата 6.10.2006, 08:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: нет
Всего: 52



Код

...
static int CALLBACK compareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    CString str1, str2;

    str1 = m_Table.GetItemText(lParam1, sortS);
    str2 = m_Table.GetItemText(lParam2, sortS);

    return strcmp(str2.GetBuffer(), str1.GetBuffer());
}

//=======================================================================

void aTable::sortBy(UINT n, bool& myR)
{
        SortItems(compareFunc, (LPARAM) this);
}

//=======================================================================
...


Где aTable - наследник от CListCtrl. А sortBy стоит на реакцию по нажатию на одну из колонок таблицы. При этом sortS - номер нажатой колонки.

Это сообщение отредактировал(а) Rickert - 6.10.2006, 08:41


--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Earnest
Дата 6.10.2006, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Ну и какой смысл, по-твоему, имеет извлечение элемента их лист-контрола когда ты вместо номера подставляешь какой-то указатель? Конечно, лажа получается.
Чем ты читал то, что я выше писала? 
В функцию сортировки нужно передать указатель на твои данные. Хотя, в твоем случае, если в lParam у тебя указатели на элементы, и этого не надо. Можешь использовать lParamSort как-то еще, напирмер, метод сортировки передать. А сама функция должна выглядеть так:

Код

static int CALLBACK compareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    CMyItemClass *p1 = (CMyItemClass*)lParam1, 
                           *p2 = (CMyItemClass*)lParam2;

     // дальше выбирай нужные данные и сравнивай их.
}


А если тебя устраивает сортировка по видимому содержимому колонок, то по моему вообще ничего делать не надо. Это встроено в лист-контрол. Клик по заголовку должен сам сортировать элементы без всякого твоего участия. SortItems предназначена для тех случаев, когда стандартная сортировка тебя не устраивает.
Но если это не так (а я точно не помню), то для сортировки по номерам элементов используй LVM_SORTITEMSEX. Вроде такой MFC-обертки нет. Там все похоже, только в параметрах функции сортировки передаеются именно номера элементов, и с ними можно делать GetItemText


--------------------
...
PM   Вверх
Rickert
Дата 9.10.2006, 03:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: нет
Всего: 52



Что-то ты понамудрила.
Цитата(Earnest @  6.10.2006,  12:37 Найти цитируемый пост)
Ну и какой смысл, по-твоему, имеет извлечение элемента их лист-контрола когда ты вместо номера подставляешь какой-то указатель? Конечно, лажа получается.

Сама же писала:
Цитата

Если твои данные организованы как список, то в lParam нужно записывать не номер, а адрес элемента, и тоже все будет нормально.

Цитата(Earnest @  6.10.2006,  12:37 Найти цитируемый пост)
А если тебя устраивает сортировка по видимому содержимому колонок, то по моему вообще ничего делать не надо. Это встроено в лист-контрол. Клик по заголовку должен сам сортировать элементы без всякого твоего участия. SortItems предназначена для тех случаев, когда стандартная сортировка тебя не устраивает.

Да, она меня устраивает! Но как её включить? Если просто в свойствах CListCtrl'а проставить Sort, например Ascending, то нифига подобного - никакой реакции на клики по колонкам.

Ты можешь мне толком объяснить: вот есть у меня вызов функции:
Код

...
static int CALLBACK compareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    CString str1, str2;

    str1 = m_Table.GetItemText(lParam1, columnM);
    str2 = m_Table.GetItemText(lParam2, columnM);

    return strcmp(str2.GetBuffer(), str1.GetBuffer());
}
...
void aTable::sortBy()
{
        SortItems(compareFunc, (LPARAM) this);
}
...

aTable - это наследник CListCtrl. SortBy срабатывает по нажатию на одну из колонок CListCtrl.
Вопрос 1: как нужно заполнять список: в качестве lParam что должно выступать, если я хоче сравнивать содержимое строк одной колонки?

Это сообщение отредактировал(а) Rickert - 9.10.2006, 04:38


--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Earnest
Дата 9.10.2006, 10:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Код

m_Table.GetItemText(lParam1, columnM);

Здесь предполагается, что lParam1 - это номер элемента в контроле!
А у тебя там адрес... А если и номер, то он только первый раз правильный.
Еще раз повторяю, у тебя 2 варианта:
1) Если используешь LVM_SORTITEMS (CListCtrl::SortItems), то в качестве аргументов в функцию сортировки передаются user-data соответствующих элементов. Ты должен по этим данным извлечь элементы (не из контрола!, а из данных приложения). Если lParam - это адрес элемента, значит, достаточно просто преобразовать: CMyItem* pItem = (CMyItem*)lParam, где CMyItem - это тип твоего элемента (то что ты передавал как tmp). Скажем, CMyItem имеет след. структуру:
Код

struct CMyItem
{
   CString m_strA;
   CString m_strB; 
  ...
};
и каждая строка пишется в соотв. колонку контрола. 
В функции сравнения ты пишешь (допустим, сортируем по колонке A):
Код

   CMyItem* pi1 = (CMyItem*)lPar1;
   CMyItem* pi2 = (CMyItem*)lPar2;
   return pi1->m_strA.CompareNoCase (pi2->m_strA);

Теперь понятно?

2) Можно использовать другое сообщение для сортировки: LVM_SORTITEMSEX:
Тогда в функцию сравнения передаются текущие номера элементов, и тогда можно делать как ты, т.е. извлекать текст итема из контрола. 

Т.е. первый способ удобен тогда, когда сравниваются не строки. В твоем случае проще использовать второй, хотя и нет соответствующей MFC-функции.

   


--------------------
...
PM   Вверх
Rickert
Дата 10.10.2006, 03:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ситхи не пройдут!
****


Профиль
Группа: Комодератор
Сообщений: 3356
Регистрация: 11.7.2006
Где: Лакрима

Репутация: нет
Всего: 52



Earnest, но в таком случае вариант сортировки только по убыванию. Хм... Ладно, будем считать вопрос решённым. Спасибо!


--------------------
Ни что не внушает сна крепче, чем день приисполненный трудов!
PM MAIL WWW Skype GTalk   Вверх
Earnest
Дата 10.10.2006, 07:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(Rickert @  10.10.2006,  04:50 Найти цитируемый пост)
но в таком случае вариант сортировки только по убыванию

Ну ты даешь! Поменяй АргУменты местами, и все...
Код

return pi2->m_strA.CompareNoCase (pi1->m_strA);




--------------------
...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0533 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.