最新消息

[公告2014/05/30] 如有需要將部落格中,任何一篇文章的程式碼使用在商業用途,請與我聯繫。

[公告2015/04/26] Line版的 iInfo程式與投資應用 群組已上線想加入的朋友們,請先查看 "入群須知" 再與我聯繫 Line : aminwhite5168,加入請告知身分與回答 "入群須知" 的問題。

[公告2018/04/22] 台北 Python + Excel VBA 金融資訊爬蟲課程,課程如網頁內容 金融資訊爬蟲班:台北班 Python 金融資訊爬蟲、EXCEL VBA 金融資訊爬蟲

[公告2019/01/08] 請注意:我再次重申,部落格文章的程式碼,是要提供各位參考與學習,一旦網頁改版請自行修改,別要求東要求西要我主動修改,你們用我寫東西賺錢了、交差了,請問有分我一杯羹嗎?既然賺錢沒分我,請問有什麼理由要求我修改,如果沒能力改,就花錢來找我上課。

[公告2019/12/01] 若各位有 Excel VBA 案子開發需求,歡迎與我聯繫,可接案處理。

[公告2020/05/22] 頁面載入速度慢,起因為部分JS來源(alexgorbatchev.com)失效導致頁面載入變慢,目前已做調整,請多見諒。

2016年3月3日 星期四

製作MFC CListCtrl 可編輯的列表元件

近期需要寫程式需要在CListCtrl 製作一個可編輯的元件,網路上有很多種作法,看了會眼花撩亂,後來使用一個可行的方式,順道紀錄一下也提供可有需要的朋友。
Step 1. 建立一個 ListCtrlEdit Class 將以下的程式碼依序輸入
ListCtrlEdit.h
#if !defined(_ListCtrlEDIT_H_)
#define _ListCtrlEDIT_H_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ListCtrl.h : header file
// 
#include "afxcmn.h"

#define IDC_MY_LIST_EDITBOX 0xffff
#define MLSM_ITEMCHANGED (WM_USER + 200)
/////////////////////////////////////////////////////////////////////////////
// CListCtrl window

class CListCtrlEdit : public CListCtrl 
{
 // Construction
public:
 CListCtrlEdit(){};
 virtual ~CListCtrlEdit(){};
 CEdit m_Edit;
 int m_Flag;

public: 
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CListCtrl)
 public:
 virtual BOOL PreTranslateMessage(MSG* pMsg);
 //}}AFX_VIRTUAL
 // Implementation

protected: 
 int m_Row;
 int m_Col;
 
 //{{AFX_MSG(CListCtrl)
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
 afx_msg void OnKillfocusEdit();
 //}}AFX_MSG
 DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif

ListCtrlEdit.cpp
#include "stdafx.h"
#include "ListCtrlEdit.h"

//////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CListCtrlEdit, CListCtrl)
  ON_WM_LBUTTONDBLCLK()
  //ON_WM_LBUTTONDOWN()
  ON_WM_MEASUREITEM()
  ON_EN_KILLFOCUS(IDC_MY_LIST_EDITBOX, OnKillfocusEdit)
END_MESSAGE_MAP()

void CListCtrlEdit::OnLButtonDblClk(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 CListCtrl::OnLButtonDblClk(nFlags, point);

 LVHITTESTINFO hi;

 hi.pt = point;
 if(SubItemHitTest(&hi) != -1 )
 {
  if (hi.iSubItem == 0 || hi.iSubItem == 1)//限制可編輯欄位
   return;
  m_Row = hi.iItem;
  m_Col = hi.iSubItem;
  if(m_Edit.m_hWnd == NULL)
  {
   RECT rect;
   rect.left = rect.top = 0;
   rect.bottom = 20;
   rect.right = 100;
   m_Edit.Create(WS_CHILD | ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE, rect, this, IDC_MY_LIST_EDITBOX);
   m_Edit.SetFont(this->GetFont(), FALSE);
  }

  CRect rect;
  GetSubItemRect(hi.iItem, hi.iSubItem, LVIR_BOUNDS, rect);
  m_Edit.SetWindowText(this->GetItemText(hi.iItem, hi.iSubItem));
  m_Edit.MoveWindow(&rect);
  m_Edit.ShowWindow(SW_SHOW);//顯示編輯框
  m_Edit.MoveWindow(&rect);//將編輯框移動到子項上面,覆蓋在子項上
  m_Edit.SetFocus();//使編輯框取得焦點
  m_Edit.CreateSolidCaret(1, rect.Height()-5);//創建一個光標
  m_Edit.ShowCaret();//顯示光標
  m_Edit.SetSel(-1);//使光標移到最後面
 }
}

void CListCtrlEdit::OnLButtonDown(UINT nFlags, CPoint point)
{
 // TODO: Add your message handler code here and/or call default
 CListCtrl::OnLButtonDown(nFlags, point);

 LVHITTESTINFO hi;
 hi.pt = point;
 if(SubItemHitTest(&hi) != -1 )
 {
  if (hi.iSubItem == 0 )
   return;
  m_Row = hi.iItem;
  m_Col = hi.iSubItem;

  if(m_Edit.m_hWnd == NULL)
  {
   RECT rect;
   rect.left = rect.top = 0;
   rect.bottom = 20;
   rect.right = 100;
   m_Edit.Create(WS_CHILD | ES_LEFT | WS_BORDER | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE, rect, this, IDC_MY_LIST_EDITBOX);
   m_Edit.SetFont(this->GetFont(), FALSE);
  }

  CRect rect;
  GetSubItemRect(hi.iItem, hi.iSubItem, LVIR_BOUNDS, rect);
  m_Edit.SetWindowText(this->GetItemText(hi.iItem, hi.iSubItem));
  m_Edit.MoveWindow(&rect);
  m_Edit.ShowWindow(1);
  m_Edit.SetSel(0, 100);
  m_Edit.SetFocus();
 }
}

BOOL CListCtrlEdit::PreTranslateMessage(MSG* pMsg)
{
 // TODO: Add your specialized code here and/or call the base class
 BOOL bHandledMsg = FALSE;

 if(pMsg->hwnd == m_Edit.m_hWnd)
 {
  switch (pMsg->message)
  {
   case WM_KEYDOWN:
   {
    switch (pMsg->wParam)
    {
     case VK_RETURN:
      if(m_Row != -1)
      {
       CString ItemText;
       m_Edit.GetWindowText(ItemText);
       this->SetItemText(m_Row, m_Col, ItemText);
       ::PostMessage(GetParent()->m_hWnd, MLSM_ITEMCHANGED, (WPARAM)MAKELONG(m_Row, m_Col), (LPARAM)this->m_hWnd);
       }
      break;

     case VK_ESCAPE:
       m_Edit.ShowWindow(0);
       m_Col = m_Row = -1;
       bHandledMsg = TRUE;
      break;
    }
   }
   break;
  }
 }
 return (bHandledMsg ? TRUE : CListCtrl::PreTranslateMessage(pMsg));
}

void CListCtrlEdit::OnKillfocusEdit()
{
 if(m_Edit.m_hWnd != NULL)
 {
  m_Edit.ShowWindow(0);
  if(m_Row != -1 && m_Row != 1)
  {
   CString ItemText;
   m_Edit.GetWindowText(ItemText);
   this->SetItemText(m_Row, m_Col, ItemText);
   ::PostMessage(GetParent()->m_hWnd, MLSM_ITEMCHANGED, (WPARAM)MAKELONG(m_Row, m_Col), (LPARAM)this->m_hWnd);
  }
 }
 m_Row = m_Col = -1;

 m_Edit.ShowWindow(0);
}

Step 2. 使用CListCtrlEdit Class在自己的Project上宣告一個物件即可使用。

參考資料: