c++mfcclistctrl

How to virtual List control using a map data structure'?


I have a question while studying C++ MFC.

void AnchorDlg::OnGetdispinfoListctrl(NMHDR *pNMHDR, LRESULT *pResult)
{

    NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);

    LV_ITEM* pItem = &(pDispInfo)->item;
    CString str;
    if(pItem == NULL) return;

    int nRow = pItem->iItem;
    int nCol = pItem->iSubItem;

    if(nRow<0 || nRow >= mapShip->size()) return;

    auto iter = mapShip->begin();

    if(pItem->pszText)
    {
        switch(nCol)
        {
        case 1:
            str.Format(_T("%.0f"), iter->second->mmsi);
            //str.Format(_T("%.0f"), iter->second->mmsi);
            lstrcpy(pItem->pszText, str);
            break;
        case 2:
            str.Format(_T("%.7f"), iter->second->lat);
            lstrcpy(pItem->pszText, str);
            break;
        case 3:
            str.Format(_T("%.7f"), iter->second->lng);
            lstrcpy(pItem->pszText, str);
            break;
        case 4:
            str.Format(_T("%.1f"), iter->second->sog);
            lstrcpy(pItem->pszText, str);
        case 5:
            str.Format(_T("%.1f"), iter->second->cog);
            lstrcpy(pItem->pszText, str);
        }
    }
    *pResult = 0;
}

mapShip consists of double and data objects.

I want to print out 1000 data, but only one data is printed.

I've used iter but only one data is output. Same data print repeat.

I must used map data structure.

I don't know how to use the map.


Solution

  • You don't seem to do anything with pItem->iItem (nRow), you just set it to the beginning of the list. You should instead search your data with this - requests may arrive in any random order. You don't have to iterate the list in OnGetdispinfoListctrl(), instead you should return the data to be displayed, given the iItem and iSubItem members. So consider using a more efficient structure to hold your data, if they are really too many (lists are not, because they are serial access structures, not random access ones). Also, don't copy the text into Item.pszText, instead set Item.pszText to point to your data. The if(pItem->pszText) check is not needed, neither is correct:

    void AnchorDlg::OnGetdispinfoListctrl(NMHDR *pNMHDR, LRESULT *pResult)
    {
        NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    
        LV_ITEM* pItem = &(pDispInfo)->item;
    
        // Persistent Buffer
        static CString str;
    
        if (pItem == NULL) return;
    
        int nRow = pItem->iItem;
        int nCol = pItem->iSubItem;
    
        if (nRow < 0 || nRow >= mapShip->size()) return;
    
        if (Item.mask & LVIF_TEXT) //Item/subItem text
        {
            //auto iter = mapShip->begin();
            auto pValue = SearchMyData(nRow);
    
            switch (nCol)
            {
                case 1:
                    str.Format(_T("%.0f"), pValue->mmsi);
                    break;
                case 2:
                    str.Format(_T("%.7f"), pValue->lat);
                    break;
                case 3:
                    str.Format(_T("%.7f"), pValue->lng);
                    break;
                case 4:
                    str.Format(_T("%.1f"), pValue->sog);
                    break;
                case 5:
                    str.Format(_T("%.1f"), pValue->cog);
                    break;
            }
            pItem->pszText = const_cast<LPTSTR>((LPCTSTR)str);
        }
        *pResult = 0;
    }
    

    EDIT:

    Here is a excerpt from the documentation about the LV_ITEM structure:

    pszText
    If the structure specifies item attributes, pszText is a pointer to a null-terminated string containing the item text. When responding to an LVN_GETDISPINFO notification, be sure that this pointer remains valid until after the next notification has been received.

    Also: cchTextMax
    This member is only used when the structure receives item attributes. ... It is read-only during LVN_GETDISPINFO and other LVN_ notifications.

    And the example in the LVN_GETDISPINFO documentation does exactly this, ie sets the pszText pointer rather than copies text into it.

    Also, you shouldn't get the conversion error if you are using either the multibyte (ANSI) or the wide (Unicode) version of both the LVITEM and CString, which you seem to do (you do not set them explicitly, which is OK, it defaults to T interpretation). It must be a const conflict. So, either use a const_cast:

        pItem->pszText = const_cast<LPTSTR>((LPCTSTR)str);
    

    or a char array instead:

        static TCHAR _szItem[MAX_LEN]; // Persistent buffer
        .
        .
        CString str;
        str.Format(_T("%.0f"), iter->second->mmsi));
        _tcscpy_s(_szItem, str);
        pItem->pszText = _szItem;
        break;