MFC 列表控件

发布于 2024-08-11 03:01:34 字数 125 浏览 10 评论 0原文

在 MFC 中,我可以通过将“编辑标签”设置为 true 来编辑列表控件中项目的文本,但仅限于第一列。现在,当我单击第一个列项来更改其文本时,我可以更改其文本,但是当我按 Enter 时,其文本不会更新,为什么以及如何编辑其他列的文本?

In MFC, I can edit the text of items in the list control but only for the first column by setting the Edit Labels to true. Now when I click the first column item to change its text, I'm able to change its text but when I hit Enter, its text isn't updated, why and how do I edit text for other columns?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

云醉月微眠 2024-08-18 03:01:34

我们在列表控件的单元格位置上创建 CEdit 控件(当我们双击列表控件时)
当我们按下 Enter 键时,它会更新该值。
在此示例中,当我们 dbclick 列表控件时,我们仅修改 1 个子项(第二个)
您可以创建许多 CEdit 控件并对所有子项执行此操作。
列表控件 SingleSelection = true

//.h
// Global variables in dialog
private:
    //..
    const static int        ID_TXTCTRL_TOMODIFY = 1001;
    bool                    m_IsEnterPressed;
    CEdit *                 m_pTxtCtrlToModify;

    //..
protected:
    //..
    BOOL PreTranslateMessage(MSG* pMsg);
    virtual BOOL OnInitDialog();
    //..

public:
    //..
    afx_msg void OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnEnKillFocusCtrlToModify();
    //..

//------------------------------------------------------------------
// .cpp


BEGIN_MESSAGE_MAP(DlgMFC, CDialogEx)
    //..
    ON_NOTIFY(NM_DBLCLK, IDC_LIST, &DlgMFC::OnNMDblclkList)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, &DlgMFC::OnLvnItemchangedList)
    ON_EN_KILLFOCUS(ID_TXTCTRL_TOMODIFY, &DlgMFC::OnEnKillFocusCtrlToModify)
    //..
END_MESSAGE_MAP()

BOOL DlgMFC::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here

    m_pTxtCtrlToModify = NULL;
    m_IsEnterPressed = false;

    //
    return TRUE;  // return TRUE  unless you set the focus to a control
}

// in this function we let to modify only 1 subitem (the 2nd),
// you can create many CEdit controls an do it with all the subitems



    // We create CEdit Control
void DlgMFC::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)
{
    //LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    //*pResult = 0;


    POSITION p = m_CtrlList.GetFirstSelectedItemPosition();
    int index, id;
    if(p)   
    {
            index   = m_CtrlList    .GetNextSelectedItem(p);       

            CRect rect, rect_ListControl; // rect wiil be cell position in m_CtrlList, rect_ListControl will be m_CtrlList's position in dialog
            if( m_CtrlList.GetSubItemRect(index, 2, LVIR_BOUNDS, rect)) // 2 is subitem number
            {
                if(m_pTxtCtrlToModify != NULL)
                    delete m_pTxtCtrlToModify;
                m_pTxtCtrlToModify = new CEdit(); // Do not forget to delete it at the end of your program (you can use OnClose())


                m_CtrlList.GetWindowRect(&rect_ListControl);
                this->ScreenToClient(&rect);

                rect.left += rect_ListControl.left + 2; // 2 is just a correction
                rect.right += rect_ListControl.left + 2;
                rect.top  += rect_ListControl.top + 2;
                rect.bottom += rect_ListControl.top + 2;

                m_pTxtCtrlToModify->Create(ES_CENTER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, rect, this, ID_TXTCTRL_TOMODIFY);
                m_pTxtCtrlToModify->SetFocus();
                m_pTxtCtrlToModify->SetWindowTextW(m_CtrlList.GetItemText(index, 2)); // 2 is subitem number

            }

    }
}


// If Selection changes, we delete that CEdit
void DlgMFC::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    *pResult = 0;

    if(m_pTxtCtrlToModify != NULL)
    {
        delete m_pTxtCtrlToModify;
        m_pTxtCtrlToModify = NULL;
    }
}


// Do not let the dialog to be closed when we press enter
BOOL DlgMFC::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->message == WM_KEYDOWN)
    {
        if ((pMsg->wParam == VK_RETURN) || (pMsg->wParam == VK_ESCAPE))
        {
            pMsg->wParam = VK_TAB;
            m_IsEnterPressed = true;
        }
    }
    return CDialog::PreTranslateMessage(pMsg);
}


//If we pressed enter, we update it and delete CEdit control 
void DlgMFC::OnEnKillFocusCtrlToModify()
{
    // we will update only when we press enter
    if(m_IsEnterPressed == true)
    {       
        m_IsEnterPressed = false;

        // UPDATE here your Database or just ListControl or both ...
        // Example: We update the same m_CtrlList's cell
        POSITION p = m_CtrlList.GetFirstSelectedItemPosition();
        int index;
        if(p)   
        {
            CString str;
            m_pTxtCtrlToModify->GetWindowTextW(str);
            index   = m_CtrlList    .GetNextSelectedItem(p);
            m_CtrlList.SetItemText(index,2,str); // 2 is subitem number
        }


        // Delete CEdit control
        if(m_pTxtCtrlToModify != NULL)
        {
            delete m_pTxtCtrlToModify;
            m_pTxtCtrlToModify = NULL;
        }

        m_CtrlList.SetFocus();
    }
}

希望对您有所帮助。
谢谢

We create CEdit control on the List control's cell's position (when we double click on List Control)
and when we press enter it updates the value.
In this example we modify only 1 subitem (the 2nd), when we dbclick on List Control
you can create many CEdit controls an do it with all the subitems.
List Control SingleSelection = true

//.h
// Global variables in dialog
private:
    //..
    const static int        ID_TXTCTRL_TOMODIFY = 1001;
    bool                    m_IsEnterPressed;
    CEdit *                 m_pTxtCtrlToModify;

    //..
protected:
    //..
    BOOL PreTranslateMessage(MSG* pMsg);
    virtual BOOL OnInitDialog();
    //..

public:
    //..
    afx_msg void OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnEnKillFocusCtrlToModify();
    //..

//------------------------------------------------------------------
// .cpp


BEGIN_MESSAGE_MAP(DlgMFC, CDialogEx)
    //..
    ON_NOTIFY(NM_DBLCLK, IDC_LIST, &DlgMFC::OnNMDblclkList)
    ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, &DlgMFC::OnLvnItemchangedList)
    ON_EN_KILLFOCUS(ID_TXTCTRL_TOMODIFY, &DlgMFC::OnEnKillFocusCtrlToModify)
    //..
END_MESSAGE_MAP()

BOOL DlgMFC::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);         // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon

    // TODO: Add extra initialization here

    m_pTxtCtrlToModify = NULL;
    m_IsEnterPressed = false;

    //
    return TRUE;  // return TRUE  unless you set the focus to a control
}

// in this function we let to modify only 1 subitem (the 2nd),
// you can create many CEdit controls an do it with all the subitems



    // We create CEdit Control
void DlgMFC::OnNMDblclkList(NMHDR *pNMHDR, LRESULT *pResult)
{
    //LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    //*pResult = 0;


    POSITION p = m_CtrlList.GetFirstSelectedItemPosition();
    int index, id;
    if(p)   
    {
            index   = m_CtrlList    .GetNextSelectedItem(p);       

            CRect rect, rect_ListControl; // rect wiil be cell position in m_CtrlList, rect_ListControl will be m_CtrlList's position in dialog
            if( m_CtrlList.GetSubItemRect(index, 2, LVIR_BOUNDS, rect)) // 2 is subitem number
            {
                if(m_pTxtCtrlToModify != NULL)
                    delete m_pTxtCtrlToModify;
                m_pTxtCtrlToModify = new CEdit(); // Do not forget to delete it at the end of your program (you can use OnClose())


                m_CtrlList.GetWindowRect(&rect_ListControl);
                this->ScreenToClient(&rect);

                rect.left += rect_ListControl.left + 2; // 2 is just a correction
                rect.right += rect_ListControl.left + 2;
                rect.top  += rect_ListControl.top + 2;
                rect.bottom += rect_ListControl.top + 2;

                m_pTxtCtrlToModify->Create(ES_CENTER | WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, rect, this, ID_TXTCTRL_TOMODIFY);
                m_pTxtCtrlToModify->SetFocus();
                m_pTxtCtrlToModify->SetWindowTextW(m_CtrlList.GetItemText(index, 2)); // 2 is subitem number

            }

    }
}


// If Selection changes, we delete that CEdit
void DlgMFC::OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
    *pResult = 0;

    if(m_pTxtCtrlToModify != NULL)
    {
        delete m_pTxtCtrlToModify;
        m_pTxtCtrlToModify = NULL;
    }
}


// Do not let the dialog to be closed when we press enter
BOOL DlgMFC::PreTranslateMessage(MSG* pMsg)
{
    if (pMsg->message == WM_KEYDOWN)
    {
        if ((pMsg->wParam == VK_RETURN) || (pMsg->wParam == VK_ESCAPE))
        {
            pMsg->wParam = VK_TAB;
            m_IsEnterPressed = true;
        }
    }
    return CDialog::PreTranslateMessage(pMsg);
}


//If we pressed enter, we update it and delete CEdit control 
void DlgMFC::OnEnKillFocusCtrlToModify()
{
    // we will update only when we press enter
    if(m_IsEnterPressed == true)
    {       
        m_IsEnterPressed = false;

        // UPDATE here your Database or just ListControl or both ...
        // Example: We update the same m_CtrlList's cell
        POSITION p = m_CtrlList.GetFirstSelectedItemPosition();
        int index;
        if(p)   
        {
            CString str;
            m_pTxtCtrlToModify->GetWindowTextW(str);
            index   = m_CtrlList    .GetNextSelectedItem(p);
            m_CtrlList.SetItemText(index,2,str); // 2 is subitem number
        }


        // Delete CEdit control
        if(m_pTxtCtrlToModify != NULL)
        {
            delete m_pTxtCtrlToModify;
            m_pTxtCtrlToModify = NULL;
        }

        m_CtrlList.SetFocus();
    }
}

I hope it will help you.
Thanks

各空 2024-08-18 03:01:34

遗憾的是,无法利用 LVS_EDITLABELSLVN_ENDLABELEDIT 编辑第一列以外的其他列。

有关解决方法,请参阅 CodeProject 上的 XListCtrl 文章了解更多信息,它会动态创建需要时使用编辑控件。

Unfortunately it isn't possible to utilize LVS_EDITLABELS and LVN_ENDLABELEDIT for editing other columns than the first.

For a workaround see the XListCtrl article on CodeProject for further information, it dynamically creates an edit control when needed.

携君以终年 2024-08-18 03:01:34

对于第一列:

  • 使用 LVS_EDITLABELS 样式创建列表,
  • 如果列表上没有对话框控件,则设置一个对话框控件,例如 SetDlgCtrlID( ID_EDITLABEL );
  • 您可能需要一些代码来跟踪当前选择,
  • 在消息处理程序中创建编辑,对单击/双击或其他用户输入做出反应(似乎您已经涵盖了),最好将其放在父类中。
  • 在父类中添加编辑端的处理程序

    ON_NOTIFY( LVN_ENDLABELEDIT, ID_EDITLABEL, OnEndEdit )
    
    void MyParentClass::OnEndEdit( NMHDR* pNMHDR, LRESULT* pResult )
    {
      NMLVDISPINFO* pLVDI=reinterpret_cast< NMLVDISPINFO*>(pNMHDR);
      if( pLVDI->item.pszText )
        m_List.SetItemText( m_iCurrentSelection, 0, pLVDI->item.pszText );
      *p结果 = 0;
    }
    

对于其他列:我还没有尝试过,但应该不会太难,因为你可以在MFC源代码中查找它们是如何实现的做吧。
请注意,上面的代码是使用最新功能包中的 CMFCListCtrl 进行测试的,尽管我假设普通的 CListCtrl 的行为相同。

For the first column:

  • create the list with the LVS_EDITLABELS style
  • set a dialog control on your list if it does not have one, eg SetDlgCtrlID( ID_EDITLABEL );
  • you might need some code for tracking the current selection
  • create the edit in a messagehandler reacting on a click/doubleclick or other user input (seems you have that covered already), best to put this in the parent class.
  • add a handler for the edit end in the parent class

    ON_NOTIFY( LVN_ENDLABELEDIT, ID_EDITLABEL, OnEndEdit )
    
    void MyParentClass::OnEndEdit( NMHDR* pNMHDR, LRESULT* pResult )
    {
      NMLVDISPINFO* pLVDI = reinterpret_cast< NMLVDISPINFO* >( pNMHDR );
      if( pLVDI->item.pszText )
        m_List.SetItemText( m_iCurrentSelection, 0, pLVDI->item.pszText );
      *pResult = 0;
    }
    

For other columns: I haven't tried it yet, but it should not be too hard, as you can lookup in the MFC source code how they do it.
Note that the code above is tested with a CMFCListCtrl from the latest feature pack, though I assume a plain CListCtrl behaves the same.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文