对ListCtrl - button的修改
从别处下了个“ListCtrl-Button”Demo发现总体不错,但有一些小问题,如:
1、Button列不在可视区域时
2、改变列宽时(拖动或双击)
3、滚动时
4、删除时
改后代码如下:
ListCtrlEx.h
代码
/********************************************************************
* Project : NetMonitor
* FileName : ListCtrlEx.h
* Change :
* Brief :
* Author : Chen Jun ( chenjun@3cis.com.cn )
* Copyright ( c ) 2007-2008 3cis
* All Right Reserved
*********************************************************************/
#if !defined( AFX_LISTCTRLEX_H__3D2C6B4A_4031_48EF_8162_492882D99D43__INCLUDED_ )
#define AFX_LISTCTRLEX_H__3D2C6B4A_4031_48EF_8162_492882D99D43__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ButtonEx.h"
#include <map>
using namespace std;
typedef map<int,CButtonEx*>button_map;
/************************************************************************/
/*
* this CListCtrlEx class inherits from ListCtrl
* it display the terminal list and record interrelated infomation
*/
/************************************************************************/
class CListCtrlEx : public CListCtrl
{
//
public:
CListCtrlEx();
//
public:
//
public:
//
// ClassWizard
//{{AFX_VIRTUAL( CListCtrlEx )
//}}AFX_VIRTUAL
//
public:
virtual ~CListCtrlEx();
//
protected:
//{{AFX_MSG( CListCtrlEx )
//
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
void createItemButton( int nItem, int nSubItem, LPCTSTR txt,HWND hMain );
void release();
void deleteItemEx( int nItem );
button_map m_mButton;
public:
afx_msg void OnLvnEndScroll(NMHDR *pNMHDR, LRESULT *pResult);
public:
// afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
public:
//afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
UINT m_uID;
void updateListCtrlButtonPos();
void enableButton( BOOL bFlag, int iItem );
// afx_msg void OnPaint();
//afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnHdnEndtrack(NMHDR *pNMHDR, LRESULT *pResult);
virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
protected:
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
#endif // !defined( AFX_LISTCTRLEX_H__3D2C6B4A_4031_48EF_8162_492882D99D43__INCLUDED_ )
* Project : NetMonitor
* FileName : ListCtrlEx.h
* Change :
* Brief :
* Author : Chen Jun ( chenjun@3cis.com.cn )
* Copyright ( c ) 2007-2008 3cis
* All Right Reserved
*********************************************************************/
#if !defined( AFX_LISTCTRLEX_H__3D2C6B4A_4031_48EF_8162_492882D99D43__INCLUDED_ )
#define AFX_LISTCTRLEX_H__3D2C6B4A_4031_48EF_8162_492882D99D43__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ButtonEx.h"
#include <map>
using namespace std;
typedef map<int,CButtonEx*>button_map;
/************************************************************************/
/*
* this CListCtrlEx class inherits from ListCtrl
* it display the terminal list and record interrelated infomation
*/
/************************************************************************/
class CListCtrlEx : public CListCtrl
{
//
public:
CListCtrlEx();
//
public:
//
public:
//
// ClassWizard
//{{AFX_VIRTUAL( CListCtrlEx )
//}}AFX_VIRTUAL
//
public:
virtual ~CListCtrlEx();
//
protected:
//{{AFX_MSG( CListCtrlEx )
//
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
void createItemButton( int nItem, int nSubItem, LPCTSTR txt,HWND hMain );
void release();
void deleteItemEx( int nItem );
button_map m_mButton;
public:
afx_msg void OnLvnEndScroll(NMHDR *pNMHDR, LRESULT *pResult);
public:
// afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
public:
//afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
UINT m_uID;
void updateListCtrlButtonPos();
void enableButton( BOOL bFlag, int iItem );
// afx_msg void OnPaint();
//afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnHdnEndtrack(NMHDR *pNMHDR, LRESULT *pResult);
virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
protected:
virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++
#endif // !defined( AFX_LISTCTRLEX_H__3D2C6B4A_4031_48EF_8162_492882D99D43__INCLUDED_ )
ListCtrlEx.CPP
代码
/********************************************************************
* Project : NetMonitor
* FileName : ListCtrlEx.h
* Change :
* Brief :
* Author : Chen Jun ( chenjun@3cis.com.cn )
* Copyright ( c ) 2007-2008 3cis
* All Right Reserved
*********************************************************************/
#include "stdafx.h"
#include "ListCtrl-Button.h"
#include "ListCtrlEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define IDC_BUTTON_ID 0x1235
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
m_uID = IDC_BUTTON_ID;
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP( CListCtrlEx, CListCtrl )
//{{AFX_MSG_MAP( CListCtrlEx )
//}}AFX_MSG_MAP
ON_NOTIFY_REFLECT(LVN_ENDSCROLL, &CListCtrlEx::OnLvnEndScroll)
ON_NOTIFY(HDN_ENDTRACKA, 0, &CListCtrlEx::OnHdnEndtrack)
ON_NOTIFY(HDN_ENDTRACKW, 0, &CListCtrlEx::OnHdnEndtrack)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx 儊僢僙乕僕 僴儞僪儔
void CListCtrlEx::createItemButton( int nItem, int nSubItem, LPCTSTR txt,HWND hMain )
{
CRect rcTop;
CRect rcBottom;
CRect rect;
CRect rcClient;
int buttonHeight = 0;
// Make sure that the item is visible
if( !EnsureVisible(nItem, TRUE))
return ;
GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
GetClientRect(rcClient);
// Now scroll if we need to expose the column
CSize size;
size.cx = 0;
size.cy = 0;
buttonHeight = rect.Height();
int nTopIndex,nRowCountPerPage;
nTopIndex = GetTopIndex();
nRowCountPerPage = GetCountPerPage();
GetSubItemRect(nTopIndex, nSubItem, LVIR_BOUNDS, rcTop);
GetSubItemRect(nTopIndex, nSubItem, LVIR_BOUNDS, rcBottom);
rcBottom.OffsetRect(0,rcTop.Height()*(nRowCountPerPage-2));
size.cx = rect.right - rcClient.right;// + rect.left;
size.cy = rect.bottom - rcBottom.bottom;
Scroll(size);
rect.top -= size.cy;
rect.bottom = rect.top+buttonHeight;
rect.left -= size.cx;
rect.right = rect.left + GetColumnWidth(nSubItem);
rect.bottom = rect.top + rect.Height();
int iPageCout = GetCountPerPage();
if ( nItem >= iPageCout )
{
rect.top += rect.Height();
rect.bottom += rect.Height();
}
DWORD dwStyle = WS_CHILD | WS_VISIBLE;
CButtonEx *pButton = new CButtonEx(nItem,nSubItem,rect,hMain);
m_uID++;
pButton->Create(txt,dwStyle, rect, this, m_uID);
m_mButton.insert( make_pair( nItem, pButton ) );
size.cx*=-1;
size.cy*=-1;
Scroll(size);
if ( nTopIndex > 0 )
{
updateListCtrlButtonPos();
}
return;
}
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 nItem )
{
int iCount = GetItemCount();
DeleteItem( nItem );
button_map::iterator iter;
button_map::iterator iterNext;
CButtonEx* pBtn =NULL;
iter = m_mButton.find( nItem);
if ( iter != m_mButton.end() )
{
pBtn = iter->second;
delete pBtn;
iter->second = NULL;
iterNext = iter;
iterNext++;
while(iterNext != m_mButton.end())
{
iter->second = iterNext->second;
iter->second->m_inItem--;
iter++;
iterNext++;
}
m_mButton.erase( iter );
updateListCtrlButtonPos();
}
}
void CListCtrlEx::OnLvnEndScroll(NMHDR *pNMHDR, LRESULT *pResult)
{
// 偙偺婡擻偼 Internet Explorer 5.5 偐偦傟埲崀偺僶乕僕儑儞傪昁梫偲偟傑偡丅
// 僔儞儃儖 _WIN32_IE 偼 >= 0x0560 偵側傜側偗傟偽側傝傑偣傫丅
LPNMLVSCROLL pStateChanged = reinterpret_cast<LPNMLVSCROLL>(pNMHDR);
// TODO: 偙偙偵僐儞僩儘乕儖捠抦僴儞僪儔 僐乕僪傪捛壛偟傑偡丅
updateListCtrlButtonPos();
*pResult = 0;
}
void CListCtrlEx::updateListCtrlButtonPos()
{
int iTopIndex = GetTopIndex();
int iLastIndex = iTopIndex + GetCountPerPage();
int nItem = iTopIndex;
button_map::iterator iter;
button_map::iterator iterUp;
int iLine = 0;
CRect rect;
int offset = 0;
int nColumnWidth = 0;
// Now scroll if we need to expose the column
CRect rcClient;
CRect subItemRect;
CSize size;
size.cx = 0;
size.cy = 0;
GetClientRect(rcClient);
CRect rcTop;
CRect rcBottom;
iter = m_mButton.find(0);
iterUp = m_mButton.begin();
if(iter != m_mButton.end() )
{
GetSubItemRect(iTopIndex,iterUp->second->m_inSubItem,LVIR_BOUNDS, subItemRect);
nColumnWidth = GetColumnWidth(iterUp->second->m_inSubItem);
offset = subItemRect.right - rcClient.right;
GetSubItemRect(iTopIndex, iterUp->second->m_inSubItem, LVIR_BOUNDS, rcTop);
GetSubItemRect(iTopIndex, iterUp->second->m_inSubItem, LVIR_BOUNDS, rcBottom);
rcBottom.OffsetRect(0,rcTop.Height()*(GetCountPerPage()-2));
}
while ( iter != m_mButton.end() )
{
iter->second->EnableWindow( iter->second->bEnable );
if(iter->second->m_inItem>=iTopIndex&&iter->second->m_inItem<=iLastIndex)
{
GetSubItemRect(iter->second->m_inItem,iter->second->m_inSubItem,LVIR_BOUNDS, subItemRect);
if(((subItemRect.left>=rcClient.left&&subItemRect.left<rcClient.right)
||(subItemRect.right<=rcClient.right&&subItemRect.right>rcClient.left))
)
{
subItemRect.right = subItemRect.left+nColumnWidth;
iter->second->ShowWindow(SW_SHOW);
iter->second->MoveWindow(subItemRect);
}
else
{
iter->second->ShowWindow(SW_HIDE);
}
}
else
{
iter->second->ShowWindow(SW_HIDE);
}
iter ++;
iterUp++;
}
InvalidateRect(rcClient);
}
void CListCtrlEx::enableButton( BOOL bFlag, int iItem )
{
button_map::iterator iter;
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 );
}
}
void CListCtrlEx::OnHdnEndtrack(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
SetColumnWidth(phdr->iItem,phdr->pitem->cxy);
updateListCtrlButtonPos();
}
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: 添加您的代码以绘制指定项
CListCtrl::DrawItem(lpDrawItemStruct);
}
BOOL CListCtrlEx::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: 在此添加专用代码和/或调用基类
NMHDR* pNMHdr = (NMHDR*) lParam;
BOOL bResult = CListCtrl::OnNotify(wParam, lParam, pResult);
if (pNMHdr->code == HDN_ITEMCHANGEDA||pNMHdr->code == HDN_ITEMCHANGEDW)
{
// 结束双击列分隔符
HD_NOTIFY* phdn = (HD_NOTIFY*) pNMHdr;
int nWidth = GetColumnWidth(phdn->iItem);
updateListCtrlButtonPos();
}
return bResult;
}
* Project : NetMonitor
* FileName : ListCtrlEx.h
* Change :
* Brief :
* Author : Chen Jun ( chenjun@3cis.com.cn )
* Copyright ( c ) 2007-2008 3cis
* All Right Reserved
*********************************************************************/
#include "stdafx.h"
#include "ListCtrl-Button.h"
#include "ListCtrlEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define IDC_BUTTON_ID 0x1235
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
m_uID = IDC_BUTTON_ID;
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP( CListCtrlEx, CListCtrl )
//{{AFX_MSG_MAP( CListCtrlEx )
//}}AFX_MSG_MAP
ON_NOTIFY_REFLECT(LVN_ENDSCROLL, &CListCtrlEx::OnLvnEndScroll)
ON_NOTIFY(HDN_ENDTRACKA, 0, &CListCtrlEx::OnHdnEndtrack)
ON_NOTIFY(HDN_ENDTRACKW, 0, &CListCtrlEx::OnHdnEndtrack)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx 儊僢僙乕僕 僴儞僪儔
void CListCtrlEx::createItemButton( int nItem, int nSubItem, LPCTSTR txt,HWND hMain )
{
CRect rcTop;
CRect rcBottom;
CRect rect;
CRect rcClient;
int buttonHeight = 0;
// Make sure that the item is visible
if( !EnsureVisible(nItem, TRUE))
return ;
GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
GetClientRect(rcClient);
// Now scroll if we need to expose the column
CSize size;
size.cx = 0;
size.cy = 0;
buttonHeight = rect.Height();
int nTopIndex,nRowCountPerPage;
nTopIndex = GetTopIndex();
nRowCountPerPage = GetCountPerPage();
GetSubItemRect(nTopIndex, nSubItem, LVIR_BOUNDS, rcTop);
GetSubItemRect(nTopIndex, nSubItem, LVIR_BOUNDS, rcBottom);
rcBottom.OffsetRect(0,rcTop.Height()*(nRowCountPerPage-2));
size.cx = rect.right - rcClient.right;// + rect.left;
size.cy = rect.bottom - rcBottom.bottom;
Scroll(size);
rect.top -= size.cy;
rect.bottom = rect.top+buttonHeight;
rect.left -= size.cx;
rect.right = rect.left + GetColumnWidth(nSubItem);
rect.bottom = rect.top + rect.Height();
int iPageCout = GetCountPerPage();
if ( nItem >= iPageCout )
{
rect.top += rect.Height();
rect.bottom += rect.Height();
}
DWORD dwStyle = WS_CHILD | WS_VISIBLE;
CButtonEx *pButton = new CButtonEx(nItem,nSubItem,rect,hMain);
m_uID++;
pButton->Create(txt,dwStyle, rect, this, m_uID);
m_mButton.insert( make_pair( nItem, pButton ) );
size.cx*=-1;
size.cy*=-1;
Scroll(size);
if ( nTopIndex > 0 )
{
updateListCtrlButtonPos();
}
return;
}
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 nItem )
{
int iCount = GetItemCount();
DeleteItem( nItem );
button_map::iterator iter;
button_map::iterator iterNext;
CButtonEx* pBtn =NULL;
iter = m_mButton.find( nItem);
if ( iter != m_mButton.end() )
{
pBtn = iter->second;
delete pBtn;
iter->second = NULL;
iterNext = iter;
iterNext++;
while(iterNext != m_mButton.end())
{
iter->second = iterNext->second;
iter->second->m_inItem--;
iter++;
iterNext++;
}
m_mButton.erase( iter );
updateListCtrlButtonPos();
}
}
void CListCtrlEx::OnLvnEndScroll(NMHDR *pNMHDR, LRESULT *pResult)
{
// 偙偺婡擻偼 Internet Explorer 5.5 偐偦傟埲崀偺僶乕僕儑儞傪昁梫偲偟傑偡丅
// 僔儞儃儖 _WIN32_IE 偼 >= 0x0560 偵側傜側偗傟偽側傝傑偣傫丅
LPNMLVSCROLL pStateChanged = reinterpret_cast<LPNMLVSCROLL>(pNMHDR);
// TODO: 偙偙偵僐儞僩儘乕儖捠抦僴儞僪儔 僐乕僪傪捛壛偟傑偡丅
updateListCtrlButtonPos();
*pResult = 0;
}
void CListCtrlEx::updateListCtrlButtonPos()
{
int iTopIndex = GetTopIndex();
int iLastIndex = iTopIndex + GetCountPerPage();
int nItem = iTopIndex;
button_map::iterator iter;
button_map::iterator iterUp;
int iLine = 0;
CRect rect;
int offset = 0;
int nColumnWidth = 0;
// Now scroll if we need to expose the column
CRect rcClient;
CRect subItemRect;
CSize size;
size.cx = 0;
size.cy = 0;
GetClientRect(rcClient);
CRect rcTop;
CRect rcBottom;
iter = m_mButton.find(0);
iterUp = m_mButton.begin();
if(iter != m_mButton.end() )
{
GetSubItemRect(iTopIndex,iterUp->second->m_inSubItem,LVIR_BOUNDS, subItemRect);
nColumnWidth = GetColumnWidth(iterUp->second->m_inSubItem);
offset = subItemRect.right - rcClient.right;
GetSubItemRect(iTopIndex, iterUp->second->m_inSubItem, LVIR_BOUNDS, rcTop);
GetSubItemRect(iTopIndex, iterUp->second->m_inSubItem, LVIR_BOUNDS, rcBottom);
rcBottom.OffsetRect(0,rcTop.Height()*(GetCountPerPage()-2));
}
while ( iter != m_mButton.end() )
{
iter->second->EnableWindow( iter->second->bEnable );
if(iter->second->m_inItem>=iTopIndex&&iter->second->m_inItem<=iLastIndex)
{
GetSubItemRect(iter->second->m_inItem,iter->second->m_inSubItem,LVIR_BOUNDS, subItemRect);
if(((subItemRect.left>=rcClient.left&&subItemRect.left<rcClient.right)
||(subItemRect.right<=rcClient.right&&subItemRect.right>rcClient.left))
)
{
subItemRect.right = subItemRect.left+nColumnWidth;
iter->second->ShowWindow(SW_SHOW);
iter->second->MoveWindow(subItemRect);
}
else
{
iter->second->ShowWindow(SW_HIDE);
}
}
else
{
iter->second->ShowWindow(SW_HIDE);
}
iter ++;
iterUp++;
}
InvalidateRect(rcClient);
}
void CListCtrlEx::enableButton( BOOL bFlag, int iItem )
{
button_map::iterator iter;
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 );
}
}
void CListCtrlEx::OnHdnEndtrack(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
SetColumnWidth(phdr->iItem,phdr->pitem->cxy);
updateListCtrlButtonPos();
}
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: 添加您的代码以绘制指定项
CListCtrl::DrawItem(lpDrawItemStruct);
}
BOOL CListCtrlEx::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
// TODO: 在此添加专用代码和/或调用基类
NMHDR* pNMHdr = (NMHDR*) lParam;
BOOL bResult = CListCtrl::OnNotify(wParam, lParam, pResult);
if (pNMHdr->code == HDN_ITEMCHANGEDA||pNMHdr->code == HDN_ITEMCHANGEDW)
{
// 结束双击列分隔符
HD_NOTIFY* phdn = (HD_NOTIFY*) pNMHdr;
int nWidth = GetColumnWidth(phdn->iItem);
updateListCtrlButtonPos();
}
return bResult;
}
到目前为此暂时还没发现别的问题