2016-12-09 6 views
1

У меня есть подкласс CMFCListCtrl, который поддерживает сортировку, чтение документации я должен реализовать виртуальный метод:Странное поведение при сортировке CMFCListCtrl

virtual int OnCompareItems(LPARAM lParam1, LPARAM lParam2, int nColumn); 

где lParam1 и lParam2 являются PARAMS некоторого вида, указанный при создании элемента управления списком.

Поскольку мне нужно алфавитный то я вставил свои строки таким образом:

item.mask = LVIF_COLFMT | LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT; 
for (nI = 0; nI ....) 
{ 
    // UMASK, ITEM IDX, TEXT, STATE 1, STATE 2, IMAGE IDX, LPARAM 
    m_lstMateriali.InsertItem(item.mask, nI, _T(" "), 0, 0, SelezionaIcona(itIM->m_bSelez, itIM->m_eStatus), nI); 
    strQnt.Format(_T("%d"), itIM->m_nIdBolla); 
    m_lstMateriali.SetItemText(nI, 1, strQnt); 
    m_lstMateriali.SetItemText(nI, 2, itIM->m_strCodMater); 
    m_lstMateriali.SetItemText(nI, 3, itIM->m_strDescrMater); 
    m_lstMateriali.SetItemText(nI, 4, itIM->m_strColore); 
    strQnt.Format(_T("%d"), itIM->m_nDaTag); 
    m_lstMateriali.SetItemText(nI, 5, strQnt); 
    m_lstMateriali.SetItemData(nI, nI); 
} 

На данный момент, мой Подкласс метод сортировки:

virtual int OnCompareItems(LPARAM lParam1, LPARAM lParam2, int nColumn) 
{ 
    int  nCol_1;    ///< 
    int  nCol_2;    ///< 
    CString strCol_1;   ///< 
    CString strCol_2;   ///< 

    strCol_1 = GetItemText(lParam1, nColumn); 
    strCol_2 = GetItemText(lParam2, nColumn); 
    switch (nColumn) 
    { 
    case 2: 
     return strCol_1.Compare(strCol_2); 
    } 
} 

сильно работает. Но теперь, из-за сортировки, мои LPARAM не являются более правильными, так как они представляют номер строки. Затем я обработал уведомление заголовка щелчка, которое происходит после сортировки:

void CEliCUTK2SceltaMaterialiDlg::OnHdnItemclickLstSmListapezzi(NMHDR * pNMHDR, LRESULT * pResult) 
{ 
    int   nNumRig; 
    CString  strCodMat; 
    LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR); 
    LVITEM  item; 

    nNumRig = m_lstMateriali.GetItemCount(); 
    memset(&item, 0, sizeof(LVITEM)); 
    item.mask = LVIF_PARAM; 
    for (int nI = 0; nI < nNumRig; nI++) 
    { 
     item.iItem = nI; 
     item.lParam = nI; 
     m_lstMateriali.SetItem(&item); // (1) 
     strCodMat = m_lstMateriali.GetItemText(nI, 2); 
     // bla bla about item data 
    } 
    *pResult = 0; 
} 

это может быть наихудшей практика, но сейчас он работает довольно хорошо: я поставил новую LPARAMs в соответствии с новой строки номера. Я также взял текст до и после пункта (1), чтобы проверить, обновил ли я правильную строку , и все кажется прекрасным: сначала я получил старый параметр param и первый параметр.

Что теперь: я щелкнул еще раз в заголовке строки, чтобы сортировать нисходящий и что я получаю? Все скривилось. я решил проверить некоторые вещи, и я добавил следующий код:

void CEliCUTK2SceltaMaterialiDlg::OnLvnItemchangedLstSmListapezzi(NMHDR * pNMHDR, LRESULT * pResult) 
{ 
    int    nSot, nTip; 
    CString   strID; 
    DWORD_PTR  dwID; 
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR); 
    LVITEM   item; 

    if (pNMLV->uNewState == 3) 
    { 
     dwID = m_lstMateriali.GetItemData(pNMLV->iItem); 
     memset(&item, 0, sizeof(LVITEM)); 
     item.mask = LVIF_PARAM; 
     item.iItem = pNMLV->iItem; 
     m_lstMateriali.GetItem(&item); 
     strID.Format(_T("PARAM: %ld."), item.lParam); 
     AfxMessageBox(strID); 
    } 
    *pResult = 0; 
} 

перезапустил программу сортировки списка снова и нажав первую строки (после проверки еще раз, что новая LPARAMs правильно) I получил сообщение:

PARAM: 10. 

в то время как я должен получить:

PARAM: 0. 

10 - старая позиция. Есть что-то, чего я где-то не хватает?

ответ

0

Проблема решена: это было в

// bla bla about item data 

где я обновить данные с членом:

SetItemData(int, DWORD_PTR); 

согласно https://msdn.microsoft.com/it-it/library/936147y4.aspx ItemData фактически LPARAM значение, указанное в структуре LVITEM.

1

В общем, то, что вы хотите сохранить в lParam, - это то, что позволит вам вернуться к данным, которые вы использовали для заполнения списка, или указателю на структуру, которая содержит данные для сравнения. Вставка индекса будет работать, если у вас есть параллельный CList или std :: list collection (или CArray или std :: vector), который не изменяет его порядок в течение жизни CListCtrl.

После сортировки или во время ввода элемент 10 в списке может содержать lParam из 2 в вашем примере. Вы хотите использовать «2» для индексации в исходный источник данных (CList, CArray, набор записей или что-то еще ...), а затем получить данные там и использовать сравнение по исходным данным. Поскольку при сортировке индексы в lParam не будут такими же, как индекс в CListCtrl (или CMFCListCtrl).

Вы можете выделить структуру всех данных, необходимых для сравнения, и сохранить их в элементе lParam. (В некоторых классах MFC вы используете SetItemDataPtr). Для очистки данных обработайте сообщение LVN_DELETEITEM.

+0

Ну, это то, что я сделал в другом классе, подобном этому. В любом случае: вы говорите мне, что, как только я установлю lParam, нет способа изменить его, если я не удалю элемент и не верну его обратно? – IssamTP

+0

Вы можете изменить его и сделать все, что захотите. Однако я не думаю, что вы должны его изменить. Я думаю, что вы должны установить его один раз и как-то ссылаться на исходные данные, а затем в вашей функции сравнения использовать lParam для ссылки на исходные данные, а затем вернуть значение, основанное на сравнении с исходными данными. –

+0

Хорошо, вот и все, но потом, если я могу изменить его (лучшая или худшая практика, я не против), почему я получил ее сброс до 10, если я установил ее в 0? – IssamTP

 Смежные вопросы

  • Нет связанных вопросов^_^