Search code examples
visual-c++mfcclistctrl

Loading CSV file into a CLISTCTRL


I can not speak English very well. Speech may be awkward using a translator.

Question

Save the contents of CLISTCTRL as a .csv file in C++. I want to load the saved contents again with CLISTCTRL! The problem is When loaded during execution, indices 0 to 10 are displayed normally. Duplicate output occurs from the 11th index to the 10th index, and characters are truncated. I would appreciate it if you could let me know what is wrong with the code below and what needs to be corrected!

Excel file

enter image description here

List control after insering elements

enter image description here

struct DATA 
{
    CString strName;
    CString strEmail;
    CString strTel;
    CString strGroup;
};

//Code to initialize CLISTCTRL
//CLISTCTRL control name = L_viewctrl

    FILE* file = NULL;
    DATA* indexData = new DATA;

    USES_CONVERSION;

    fopen_s(&file, path_str, "r");
    if (file)
    {
        char szContent[2048];

        memset(szContent, NULL, sizeof(szContent));

        CString strRstring;
        int nFileline(0);
        int nSubString(0);
        while (fgets(szContent, 2048, file))
        {
            //File Read
            CString strFile;
            strFile = szContent;

            bool bfileLineRet = TRUE;
            while (bfileLineRet)
            {
                AfxExtractSubString(strRstring, strFile, nSubString++, ',');
                if (nSubString == 2)indexData->strName = strRstring;

                if (nSubString == 3)indexData->strEmail = strRstring;

                if (nSubString == 4)indexData->strTel = strRstring;

                if (nSubString == 5) 
                {
                    indexData->strGroup = strRstring;
                    nSubString = 0;
                    bfileLineRet = FALSE;
                }
            }

            //LIST INDEX DATA SET;
            UpdateData(TRUE);
            CString strCount;
            strCount.Format(_T("%d"), nFileline);
            L_viewctrl.InsertItem(nFileline, strCount);
            L_viewctrl.SetItem(nFileline, 1, LVIF_TEXT, indexData->strName, 0, 0, 0, 0);
            L_viewctrl.SetItem(nFileline, 2, LVIF_TEXT, indexData->strEmail, 0, 0, 0, 0);
            L_viewctrl.SetItem(nFileline, 3, LVIF_TEXT, indexData->strTel, 0, 0, 0, 0);
            L_viewctrl.SetItem(nFileline, 4, LVIF_TEXT, indexData->strGroup, 0, 0, 0, 0);
            nFileline++;
        }
    }
    fclose(file);

I tried loading a csv file into LISTCTRL and printing the values. I wanted to read the csv file normally and output it to LISTCTRL, but Reading and printing the csv file was successful. However, it was output normally up to the 10th index, but after that, the output at the 10th index was overwritten.


Solution

  • The problem is your list is sorted alphabetically. You call InsertItem(nFileline,... and then you assume the position of the item you've just inserted is nFileline, but it is not because the items are inserted according to alphabetic sorting. For example item "10" is inserted after item "1" (you can see this clearly on the image you posted).

    You can correct the problem by using the value returned by InsertItem which is the index in the list where the item has actually been inserted.

    Something like:

    ...
    int index = L_viewctrl.InsertItem(nFileline, strCount);
    L_viewctrl.SetItem(index, 1, LVIF_TEXT, indexData->strName, 0, 0, 0, 0);
    L_viewctrl.SetItem(index, 2, LVIF_TEXT, indexData->strEmail, 0, 0, 0, 0);
    ...
    

    Additionally you may set the "Sort" property of the List control to "None". You probably don't want sorting at all as you probably want to have the same order in the list control than in the CSV file.


    By the way: you will stumble on another problem: the items you insert will be lost forever. You need to use CListCtrl::SetItemData in order to store the pointer to your data in each item of the list, something like.

    ...
    int index = L_viewctrl.InsertItem(nFileline, strCount);
    L_viewctrl.SetItemData(index, (DWORD_PTR)indexData);
    ...
    

    Otherwise you won't be able to access the data once you have inserted all items into the list. If you don't need the actual data, because you only want to display the list control, you still need to delete it. Each thing allocated via new must be deleted with delete.

    Also don't forget to delete the allocated data eventually.