MFC List Control controls add cell editing and cell drop-down list items

The principle is simple:

When you click on the corresponding cell in the list, you can create an edit box or drop-down list box in the corresponding location, which is the same size as the cell, and paste it on the cell. 

Implemented as follows: Add the following variables and functions to the dialog class declaration:

Add:

int e_Item;    //Newly edited lines  
int e_SubItem; //Columns just edited  

CEdit m_Edit;  //Generate unit edit box object
bool haveeditcreate;//Logo edit box has been created
void createEdit(NM_LISTVIEW  *pEditCtrl, CEdit *createdit, int &Item, int &SubItem, bool &havecreat);//Create a cell edit box function
void distroyEdit(CListCtrl *list, CEdit* distroyedit, int &Item, int &SubItem);//Destroy the cell edit box object

CComboBox m_comBox;//Production cell drop-down list object
bool haveccomboboxcreate;//The logo drop-down list box has been created
void createCcombobox(NM_LISTVIEW  *pEditCtrl, CComboBox *createccomboboxobj, int &Item, int &SubItem, bool &havecreat);//Create a cell drop-down list box function
void distroyCcombobox(CListCtrl *list, CComboBox* distroyccomboboxobj, int &Item, int &SubItem);//Destroy cell drop-down list box

In the initialization function OnInitDialog() of the dialog box, add the initialization code as follows:

haveeditcreate = false;//Initialize the flag bit to indicate that an edit box has not been created
haveccomboboxcreate = false;//Initialize the flag bit to indicate that a drop-down list box has not been created
RECT  m_rect;
m_list.GetClientRect(&m_rect); //Get the client area of the list to easily adjust the width of each column  
m_list.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT); //Set list style, LVS_EX_GRIDLINES as grid line (only for list Ctrl with report style)
                                                                      //LVS_EX_FULLROWSELECT is selected for a list Ctrl exercising full line highlighting (only applicable to report style)
m_list.InsertColumn(0, _T("Student ID"), LVCFMT_LEFT, m_rect.right / 4);
m_list.InsertColumn(1, _T("Full name"), LVCFMT_LEFT, m_rect.right / 4);
m_list.InsertColumn(2, _T("Gender"), LVCFMT_LEFT, m_rect.right / 4);
m_list.InsertColumn(3, _T("class"), LVCFMT_LEFT, m_rect.right / 4);

m_list.InsertItem(0, _T("09090901"));//Add the first student data
m_list.SetItemText(0, 1, _T("petty thief"));
m_list.SetItemText(0, 2, _T("male"));
m_list.SetItemText(0, 3, _T("Ji Ke 0901"));

m_list.InsertItem(1, _T("09090902"));//Add a second student data
m_list.SetItemText(1, 1, _T("Xiao Wang"));
m_list.SetItemText(1, 2, _T("male"));
m_list.SetItemText(1, 3, _T("Ji Ke 0902"));

Add a click response function to the list box:

void CNephoVisionDatabaseDlg::OnNMClickListStudentdata(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    NM_LISTVIEW  *pEditCtrl = (NM_LISTVIEW *)pNMHDR;
    printf("That's ok:%d,Column:%d\n", pEditCtrl->iItem, pEditCtrl->iSubItem);
    if (pEditCtrl->iItem==-1)//Click on the non-workspace
    {
        if (haveeditcreate == true)//If you created an edit box before, destroy it.
        {
            distroyEdit(&m_list, &m_Edit, e_Item, e_SubItem);//Destroy the cell edit box object
            haveeditcreate = false;
        }
        if (haveccomboboxcreate == true)//If you created a drop-down list box before, destroy it
        {
            distroyCcombobox(&m_list, &m_comBox, e_Item, e_SubItem);
            haveccomboboxcreate = false;
        }
    }
    else if (pEditCtrl->iSubItem != 2)//If not the gender option
    {
        if (haveccomboboxcreate == true)//If you created an edit box before, destroy it.
        {
            distroyCcombobox(&m_list, &m_comBox, e_Item, e_SubItem);
            haveccomboboxcreate = false;
        }
        if (haveeditcreate == true)
        {
            if (!(e_Item == pEditCtrl->iItem && e_SubItem == pEditCtrl->iSubItem))//If the cell in the point is not created before
            {
                distroyEdit(&m_list, &m_Edit, e_Item, e_SubItem);
                haveeditcreate = false;
                createEdit(pEditCtrl, &m_Edit, e_Item, e_SubItem, haveeditcreate);//Create edit boxes
            }
            else//The cells in the point are created previously
            {
                m_Edit.SetFocus();//Set Focus 
            }
        }
        else
        {
            e_Item = pEditCtrl->iItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
            e_SubItem = pEditCtrl->iSubItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
            createEdit(pEditCtrl, &m_Edit, e_Item, e_SubItem, haveeditcreate);//Create edit boxes
        }
    }
    else//If it is a gender option, generate drop-down list items at the cell
    {
        if (haveeditcreate == true)//If you created an edit box before, destroy it.
        {
            distroyEdit(&m_list, &m_Edit, e_Item, e_SubItem);
            haveeditcreate = false;
        }
        if (haveccomboboxcreate == true)
        {
            if (!(e_Item == pEditCtrl->iItem && e_SubItem == pEditCtrl->iSubItem))//If the cell in the point is not created before
            {
                distroyCcombobox(&m_list, &m_comBox, e_Item, e_SubItem);
                haveccomboboxcreate = false;
                createCcombobox(pEditCtrl, &m_comBox, e_Item, e_SubItem, haveccomboboxcreate);//Create edit boxes
                m_comBox.AddString(L"male");
                m_comBox.AddString(L"female");
                m_comBox.ShowDropDown();//AutoDrop
            }
            else//The cells in the point are created previously
            {
                m_comBox.SetFocus();//Set Focus 
            }
        }
        else
        {
            e_Item = pEditCtrl->iItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
            e_SubItem = pEditCtrl->iSubItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
            createCcombobox(pEditCtrl, &m_comBox, e_Item, e_SubItem, haveccomboboxcreate);//Create edit boxes
            m_comBox.AddString(L"male");
            m_comBox.AddString(L"female");
            m_comBox.ShowDropDown();//AutoDrop
        }
    }
    *pResult = 0;
}

Write the implementation of creating and destroying cell edit box and drop-down list box functions:

//Create a cell edit box function 
//pEditCtrl is the list object pointer and createdit is the edit box pointer object.      
//Item creates rows for cells in the list, SubItem for columns, and havecreat creates criteria for objects

void CNephoVisionDatabaseDlg::createEdit(NM_LISTVIEW  *pEditCtrl, CEdit *createdit, int &Item, int &SubItem, bool &havecreat)   
{
    Item = pEditCtrl->iItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
    SubItem = pEditCtrl->iSubItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
    createdit->Create(ES_AUTOHSCROLL | WS_CHILD | ES_LEFT | ES_WANTRETURN,
        CRect(0, 0, 0, 0), this, IDC_EDIT_CREATEID);//Create edit box object with IDC_EDIT_CREATEID as control ID number 3000, defined at the beginning of the article
    havecreat = true;
    createdit->SetFont(this->GetFont(), FALSE);//Setting fonts, without setting up here, the words on it will feel very abrupt.
    createdit->SetParent(&m_list);//It is also important to set the list control to the parent window so that the generated Edit can be positioned correctly.
    CRect  EditRect;
    m_list.GetSubItemRect(e_Item, e_SubItem, LVIR_LABEL, EditRect);//Obtaining the Spatial Position Information of Cells
    EditRect.SetRect(EditRect.left+1, EditRect.top+1, EditRect.left + m_list.GetColumnWidth(e_SubItem)-1, EditRect.bottom-1);//+ 1 and - 1 keep edit boxes from blocking grid lines in list boxes
    CString strItem = m_list.GetItemText(e_Item, e_SubItem);//Get the corresponding cell character
    createdit->SetWindowText(strItem);//Display cell characters on the edit box
    createdit->MoveWindow(&EditRect);//Place the edit box on the corresponding cell
    createdit->ShowWindow(SW_SHOW);//Display the edit box on the cell
    createdit->SetFocus();//Set Focus 
    createdit->SetSel(-1);//Set cursor at the end of text box text
}

void CNephoVisionDatabaseDlg::distroyEdit(CListCtrl *list,CEdit* distroyedit, int &Item, int &SubItem)
{
    CString meditdata;
    distroyedit->GetWindowTextW(meditdata);
    list->SetItemText(Item, SubItem, meditdata);//Get the corresponding cell character
    distroyedit->DestroyWindow();//Destroy objects, create them and destroy them, otherwise they will report errors.
}

 //Create a cell drop-down list box function
//pEditCtrl is the list object pointer and createccombobox is the drop-down list box pointer object.
//Item creates rows for cells in the list, SubItem for columns, and havecreat creates criteria for objects

void CNephoVisionDatabaseDlg::createCcombobox(NM_LISTVIEW  *pEditCtrl, CComboBox *createccomboboxobj, int &Item, int &SubItem, bool &havecreat) 
{
    Item = pEditCtrl->iItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
    SubItem = pEditCtrl->iSubItem;//Assigning rows of cells in a point to "newly edited rows" for post-processing
    havecreat = true;
    createccomboboxobj->Create(WS_CHILD | WS_VISIBLE |  CBS_DROPDOWN | CBS_OEMCONVERT, CRect(0, 0, 0, 0), this, IDC_COMBOX_CREATEID);
    createccomboboxobj->SetFont(this->GetFont(), FALSE);//Setting fonts, without setting up here, the words on it will feel very abrupt.
    createccomboboxobj->SetParent(&m_list);//It's also important to set list control to the parent window so that the generated Ccombobox can be positioned correctly.
    CRect  EditRect;
    m_list.GetSubItemRect(e_Item, e_SubItem, LVIR_LABEL, EditRect);//Obtaining the Spatial Position Information of Cells
    EditRect.SetRect(EditRect.left + 1, EditRect.top + 1, EditRect.left + m_list.GetColumnWidth(e_SubItem) - 1, EditRect.bottom - 1);//+ 1 and - 1 keep edit boxes from blocking grid lines in list boxes
    CString strItem = m_list.GetItemText(e_Item, e_SubItem);//Get the corresponding cell character
    createccomboboxobj->SetWindowText(strItem);//Display cell characters on the edit box
    createccomboboxobj->MoveWindow(&EditRect);//Place the edit box on the corresponding cell
    createccomboboxobj->ShowWindow(SW_SHOW);//Display the edit box on the cell
}

void CNephoVisionDatabaseDlg::distroyCcombobox(CListCtrl *list, CComboBox* distroyccomboboxobj, int &Item, int &SubItem)
{
    CString meditdata;
    distroyccomboboxobj->GetWindowTextW(meditdata);
    list->SetItemText(Item, SubItem, meditdata);//Update the corresponding cell characters
    distroyccomboboxobj->DestroyWindow();//Destroy objects, create them and destroy them, otherwise they will report errors.
}

OK, so far we have realized the function of adding cell edit box and cell drop-down list box. Click on the list cell except gender column to see the following effect:

When writing in the cell edit box, you often like to press Enter. If you don't handle it, you will find a very crashing phenomenon, and the program will exit directly. This can be avoided by overloading the OnOK() function of the dialog class. It's added to the dialog class declaration

afx_msg void OnOK();

Then define why not:

void CNephoVisionDatabaseDlg::OnOK()
{
}

That way, there will be no direct exit by return.

In addition, if you want to update the relevant information in the data list when the edit box or drop-down list box loses focus, you can respond to the lost focus message of the two dynamically created controls by adding the following method: in the dialog box class declaration

afx_msg void OnKillfocusEdit();//Dynamically Generating Focus Lost Response Function for Editing Box
afx_msg void OnKillfocusCcomboBox();//Dynamic generation of drop-down list box loss of focus response function

Add to the message mapping description of the dialog class implementation

//Lost Focus Response Function with Dynamic Generation Editor Box
ON_EN_KILLFOCUS(IDC_EDIT_CREATEID, &CNephoVisionDatabaseDlg::OnKillfocusEdit)

ON_CBN_KILLFOCUS(IDC_COMBOX_CREATEID, &CNephoVisionDatabaseDlg::OnKillfocusCcomboBox)

In this way, the two controls will respond to separately defined functions when they lose focus. We just need to add processing code to the corresponding functions.

void CNephoVisionDatabaseDlg::OnKillfocusEdit()
{
    if (haveeditcreate == true)//If you created an edit box before, destroy it.
    {
        distroyEdit(&m_list, &m_Edit, e_Item, e_SubItem);//Destroy the cell edit box object
        haveeditcreate = false;
    }
    if (haveccomboboxcreate == true)//If you created a drop-down list box before, destroy it
    {
        distroyCcombobox(&m_list, &m_comBox, e_Item, e_SubItem);
        haveccomboboxcreate = false;
    }
}

void CNephoVisionDatabaseDlg::OnKillfocusCcomboBox()
{
    if (haveeditcreate == true)//If you created an edit box before, destroy it.
    {
        distroyEdit(&m_list, &m_Edit, e_Item, e_SubItem);//Destroy the cell edit box object
        haveeditcreate = false;
    }
    if (haveccomboboxcreate == true)//If you created a drop-down list box before, destroy it
    {
        distroyCcombobox(&m_list, &m_comBox, e_Item, e_SubItem);
        haveccomboboxcreate = false;
    }
}

Posted by MisterWebz on Sat, 01 Jun 2019 11:37:26 -0700