先上效果圖:
圖中用了一個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 ){}