MFC では、リスト コントロール内の項目のテキストを編集できますが、Edit Labels を true に設定することで最初の列に対してのみ編集できます。最初の列アイテムをクリックしてテキストを変更すると、そのテキストを変更できますが、Enter キーを押してもテキストが更新されません。他の列のテキストを編集するには、なぜ、どのようにすればよいですか?
3 に答える
List コントロールのセルの位置 (List コントロールをダブルクリックしたとき) に CEdit コントロールを作成し、Enter キーを押すと値が更新されます。この例では、1 つのサブ項目 (2 番目) のみを変更します。リスト コントロールを dbclick すると、多くの 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();
}
}
お役に立てば幸いです。ありがとう
残念ながら、最初の列以外の列を利用LVS_EDITLABELS
して編集することはできません。LVN_ENDLABELEDIT
回避策については、CodeProject のXListCtrlの記事を参照してください。必要に応じて編集コントロールが動的に作成されます。
最初の列の場合:
- 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 ); *pResult = 0; }
他のコラムについて: 私はまだ試していませんが、MFC のソース コードで彼らのやり方を調べることができるので、それほど難しいことではありません。上記のコードは、最新の機能パックの CMFCListCtrl でテストされていることに注意してください。ただし、プレーンな CListCtrl も同じように動作すると想定しています。