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