MFC之ListCtrl动态添加按钮
先上效果图:
图中用了一个CListCtrl插件,隐藏了网格线(LVS_EX_GRIDLINES)。
添加了“删除”按钮(按钮上贴了图片),选中哪一行则显示在哪一行。
有两种方式创建按钮,一种是直接根据行数(比如n行)创建n按钮,然后根据自己需求全部显示,或是动态显示,只显示所选中的那一行按钮;
另一种是每次只创建选中行的一个按钮,并且销毁上一次创建的按钮(第一次除外)。
本实例选用第二种方法,第一种方法也用了,但是效果不好,有其他bug.
-----------------------------------------------------------------创建按钮源代码如下---------------------------------------------------------------------
有4个基本文件,ButtonEx.h, ButtonEx.cpp, ListCtrlEx.h, ListCtrlEx.cpp.
//ButtonEx.h #pragma once #include "WDBitmapButton.h" // CButtonEx #define WM_BN_CLICK WM_USER + 100 class CButtonEx : public CWDBitmapButton { DECLARE_DYNAMIC(CButtonEx) public: CButtonEx(); CButtonEx( int nItem, int nSubItem, CRect rect, HWND hParent ); virtual ~CButtonEx(); protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnBnClicked(); int m_inItem; int m_inSubItem; CRect m_rect; HWND m_hParent; BOOL bEnable; };
// ButtonEx.cpp : 实现文件 // #include "stdafx.h" #include "ButtonEx.h" // CButtonEx IMPLEMENT_DYNAMIC(CButtonEx, CButton) CButtonEx::CButtonEx() { } CButtonEx::~CButtonEx() { } CButtonEx::CButtonEx( int nItem, int nSubItem, CRect rect, HWND hParent ) //- { m_inItem = nItem; m_inSubItem = nSubItem; m_rect = rect; m_hParent = hParent; bEnable = TRUE; } BEGIN_MESSAGE_MAP(CButtonEx, CButton) ON_CONTROL_REFLECT(BN_CLICKED, &CButtonEx::OnBnClicked) END_MESSAGE_MAP() // CButtonEx 消息处理程序 void CButtonEx::OnBnClicked() { // TODO: 在此添加控件通知处理程序代码 ::SendMessage( m_hParent, WM_BN_CLICK, m_inItem, m_inSubItem ); // }
//ListCtrl.h
#pragma once #include "ButtonEx.h" #include <map> using namespace std; typedef map<int,CButtonEx*>button_map; // CListCtrlEx class CListCtrlEx : public CListCtrl { DECLARE_DYNAMIC(CListCtrlEx) public: CListCtrlEx(); virtual ~CListCtrlEx(); protected: DECLARE_MESSAGE_MAP() public: void createItemButton( int nItem, int nSubItem, HWND hMain ); void release(); void deleteItemEx( int iCount, int nItem ); button_map m_mButton; WCHAR * charToWchar(char *s); public: UINT m_uID; //void updateListCtrlButtonPos(); //void enableButton( BOOL bFlag, int iItem ); };
// ListCtrlEx.cpp : 实现文件 // #include "stdafx.h" #include "ListCtrlEx.h" #include "resource.h" #define MAX_PATH 256 // CListCtrlEx IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl) CListCtrlEx::CListCtrlEx() { } CListCtrlEx::~CListCtrlEx() { } BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl) END_MESSAGE_MAP() // CListCtrlEx 消息处理程序 void CListCtrlEx::createItemButton( int nItem, int nSubItem, HWND hMain ) { m_mButton.clear(); char *name = NULL; CString strPath; ::GetModuleFileName( NULL, strPath.GetBuffer(MAX_PATH), MAX_PATH ); strPath.ReleaseBuffer();//当前文件的绝对路径 strPath = strPath.Left(strPath.ReverseFind(_T('\\')));//文件所在目录 strPath=strPath.Left(strPath.ReverseFind(_T('\\')));//文件目录的父目录 name = (LPSTR)(LPCSTR)strPath; WCHAR name_on[256] = {}; wcscpy(name_on,charToWchar(name)); wcscat(name_on,L"//Invaray//Invaray//res//delete.png"); CRect rect; if( !EnsureVisible(nItem, TRUE)) return ; GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect); DWORD dwStyle = WS_CHILD | WS_VISIBLE; CButtonEx *pButton = new CButtonEx(nItem,nSubItem,rect,hMain); rect.bottom = rect.bottom-2; pButton->Create(_T(""),dwStyle, rect, this, m_uID); //m_uID++; pButton->SetImage(name_on,name_on,name_on); m_mButton.insert( make_pair( nItem, pButton ) ); return; } WCHAR * CListCtrlEx::charToWchar(char *s) { int w_nlen=MultiByteToWideChar(CP_ACP,0,s,-1,NULL,0); WCHAR *ret; ret=(WCHAR*) malloc(sizeof(WCHAR)*w_nlen); memset(ret,0,sizeof(ret)); MultiByteToWideChar(CP_ACP,0,s,-1,ret,w_nlen); return ret; } void CListCtrlEx::release() { button_map::iterator iter; iter = m_mButton.begin(); while ( iter != m_mButton.end() ) { delete iter->second; iter->second = NULL; iter++; } } void CListCtrlEx::deleteItemEx( int iCount, int nItem ) { //int iCount = GetItemCount(); DeleteItem( nItem ); button_map::iterator iter; button_map::iterator iterNext; #ifdef USE_TOPINDEX_BUTTON //add----------------------------------- iter = m_mButton.find( nItem ); iterNext = iter; iterNext++; while ( iterNext != m_mButton.end() ) { iter->second->bEnable = iterNext->second->bEnable; iterNext++; iter++; } //------------------------------ #endif iter = m_mButton.find( iCount - 1 ); if ( iter != m_mButton.end() ) { delete iter->second; iter->second = NULL; m_mButton.erase( iter ); //updateListCtrlButtonPos(); } } //void CListCtrlEx::updateListCtrlButtonPos() //{ // int iTopIndex = GetTopIndex(); // int nItem = iTopIndex; // button_map::iterator iter; // button_map::iterator iterUp; // int iLine = 0; //#ifdef USE_TOPINDEX_BUTTON // iter = m_mButton.find( iTopIndex ); // iterUp = m_mButton.begin(); // while ( iter != m_mButton.end() ) // { // iterUp->second->EnableWindow( iter->second->bEnable ); // iter ++; // iterUp++; // } //#else // for ( ; nItem < GetItemCount(); nItem++ ) // { // iter = m_mButton.find(nItem); // if( iter!= m_mButton.end() ) // { // CRect rect; // iterUp = m_mButton.find(iLine); // rect = iterUp->second->m_rect; // iter->second->MoveWindow( &rect ); // iter->second->ShowWindow( SW_SHOW ); // if( iLine < iTopIndex ) // { // iterUp->second->ShowWindow( SW_HIDE ); // } // iLine++; // } // } //#endif // //} //void CListCtrlEx::enableButton( BOOL bFlag, int iItem ) //{ // button_map::iterator iter; //#ifdef USE_TOPINDEX_BUTTON // int iTopIndex = GetTopIndex(); // int nItem = iItem - iTopIndex; // iter = m_mButton.find( iItem ); // if ( iter != m_mButton.end() ) // { // iter->second->bEnable = bFlag; // } // iter = m_mButton.find( nItem ); // if ( iter != m_mButton.end() ) // { // iter->second->EnableWindow( bFlag ); // } //#else // iter = m_mButton.find( iItem ); // if ( iter != m_mButton.end() ) // { // iter->second->EnableWindow( bFlag ); // } //#endif // //}
动态创建Button的函数
createItemButton( int nItem, int nSubItem, HWND hMain ),3个参数分别是行,列,父窗口句柄;
按钮所产生消息:
void CButtonEx::OnBnClicked()
{
// TODO: 在此添加控件通知处理程序代码
::SendMessage( m_hParent, WM_BN_CLICK, m_inItem, m_inSubItem ); //
}
可以通过宏WM_BN_CLICK来接收相应的行数和列数。
如,在你的其他文件中添加消息响应函数,ON_MESSAGE( WM_BN_CLICK, onBnCLick) ,LRESULT CXXX::onBnCLick( WPARAM wParam, LPARAM lParam ){}