头文件:
#pragma once
// CLinkList
#define WM_LIST_BTN_CLICK WM_USER + 500
class CLinkList : public CListCtrl
{
DECLARE_DYNAMIC(CLinkList)
public:
CLinkList();
virtual ~CLinkList();
int InsertItem(int nItem, LPCTSTR lpszItem, LPCTSTR lpctszUrl = NULL);
BOOL SetItemText(int nItem, int nSubItem, LPCTSTR lpszText, LPCTSTR lpctszUrl = NULL);
void DeleteAllGridData();
CString GetLinkText(){ return m_curUrl;}
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
DECLARE_MESSAGE_MAP()
void GetCurLinkIndex();
BOOL HasLink(int row, int col);
private:
CMapStringToOb m_gridMap;
CMapStringToString m_linkMap;
int m_row; // 鼠标当前所在行
int m_col; // 鼠标当前所在列
CString m_curUrl;
int m_nItemHeight;
public:
afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);
//设置行高
void SetItemHeight(UINT nHeight);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
};
///
源文件:
// LinkList.cpp : 实现文件
//
#include "stdafx.h"
#include "LinkList.h"
// CLinkList
IMPLEMENT_DYNAMIC(CLinkList, CListCtrl)
CLinkList::CLinkList()
{
}
CLinkList::~CLinkList()
{
DeleteAllGridData();
}
BEGIN_MESSAGE_MAP(CLinkList, CListCtrl)
ON_NOTIFY_REFLECT(NM_CLICK, &CLinkList::OnNMClick)
ON_WM_MOUSEMOVE()
ON_WM_SETCURSOR()
ON_WM_MEASUREITEM_REFLECT()
END_MESSAGE_MAP()
// CLinkList 消息处理程序
int CLinkList::InsertItem(int nItem, LPCTSTR lpctszItem,
LPCTSTR lpctszUrl /*= NULL*/)
{
CString strIndex;
strIndex.Format(_T("%d-%d"), nItem, 0);
CStringArray* pArrText = (CStringArray*)m_gridMap[strIndex];
if (pArrText == NULL)
{
pArrText = new CStringArray;
m_gridMap[strIndex] = (CObject*)pArrText;
}
pArrText->Add(lpctszItem);
if (lpctszUrl)
{
strIndex.Format(_T("%d-%d-%s"), nItem, 0, lpctszItem);
m_linkMap[strIndex] = lpctszUrl;
}
strIndex.Empty();
int count = pArrText->GetCount();
for (int i(0); i < count; ++i)
{
strIndex += CString(_T(" ")) + CString(pArrText->GetAt(i));
}
strIndex.TrimLeft();
return CListCtrl::InsertItem(nItem, strIndex);
}
BOOL CLinkList::SetItemText(int nItem, int nSubItem, LPCTSTR lpctszText,
LPCTSTR lpctszUrl /*= NULL*/)
{
CString strIndex;
strIndex.Format(_T("%d-%d"), nItem, nSubItem);
CStringArray* pArrText = (CStringArray*)m_gridMap[strIndex];
if (pArrText == NULL)
{
pArrText = new CStringArray;
m_gridMap[strIndex] = (CObject*)pArrText;
}
pArrText->Add(lpctszText);
int count = pArrText->GetCount();
if (lpctszUrl)
{
strIndex.Format(_T("%d-%d-%d"), nItem, nSubItem, count - 1);
m_linkMap[strIndex] = lpctszUrl;
}
strIndex.Empty();
for (int i(0); i < count; ++i)
{
strIndex += CString(_T(" ")) + CString(pArrText->GetAt(i));
}
strIndex.TrimLeft();
return CListCtrl::SetItemText(nItem, nSubItem, strIndex);
}
void CLinkList::DeleteAllGridData()
{
POSITION pos;
CString strKey;
CStringArray *pGridItem;
//Delete the entire list
for (pos = m_gridMap.GetStartPosition(); pos != NULL; )
{
m_gridMap.GetNextAssoc( pos, strKey, (CObject*&)pGridItem);
if (pGridItem)
{
CStringArray* pArr = pGridItem;
pArr->RemoveAll();
delete pGridItem;
pGridItem = NULL;
}
}
m_gridMap.RemoveAll();
m_linkMap.RemoveAll();
}
void CLinkList::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
CWnd* pWnd = GetParent();
if (pWnd && !m_curUrl.IsEmpty())
{
NMHDR nmhdr;
nmhdr.hwndFrom = m_hWnd;
nmhdr.idFrom = GetDlgCtrlID();
nmhdr.code = WM_LIST_BTN_CLICK; // 用户自定义消息
pWnd->SendMessage(WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
}
*pResult = 0;
}
void CLinkList::GetCurLinkIndex()
{
DWORD dwPos = GetMessagePos();
CPoint point( LOWORD(dwPos), HIWORD(dwPos) );
ScreenToClient(&point);
LVHITTESTINFO lvinfo;
lvinfo.pt = point;
lvinfo.flags = LVHT_ABOVE;
int nItem = SubItemHitTest(&lvinfo);
if (nItem == -1)
{
return ;
}
m_row = lvinfo.iItem;
m_col = lvinfo.iSubItem;
int start(5);
for (int i(0); i < lvinfo.iSubItem; ++i)
{
start += GetColumnWidth(i);
}
CString strIndex;
strIndex.Format(_T("%d-%d"), lvinfo.iItem, lvinfo.iSubItem);
CStringArray* pArrText = (CStringArray*)m_gridMap[strIndex];
if (pArrText)
{
int cnt = pArrText->GetCount();
for (int i(0); i < cnt; ++i)
{
int txtLen = GetStringWidth(pArrText->GetAt(i));
if (point.x > start && point.x < start + txtLen)
{
CString strIndex;
strIndex.Format(_T("%d-%d-%d"), m_row, m_col, i);
m_curUrl = m_linkMap[strIndex];
break;
}
else
{
start += txtLen + 5;
}
}
}
}
void CLinkList::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
GetCurLinkIndex();
if (!m_curUrl.IsEmpty())
{
::SetCursor(::LoadCursor(NULL, IDC_HAND));
}
CListCtrl::OnMouseMove(nFlags, point);
}
BOOL CLinkList::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
return CListCtrl::OnSetCursor(pWnd, nHitTest, message);
}
BOOL CLinkList::HasLink(int row, int col)
{
BOOL has(FALSE);
CString strIndex;
strIndex.Format(_T("%d-%d"), row, col);
CStringArray* pArrText = (CStringArray*)m_gridMap[strIndex];
if (pArrText)
{
int cnt = pArrText->GetCount();
for (int i(0); i < cnt; ++i)
{
strIndex.Format(_T("%d-%d-%d"), m_row, m_col, i);
CString str(m_linkMap[strIndex]);
if (!str.IsEmpty())
{
has = TRUE;
break;
}
}
}
return has;
}
void CLinkList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your code to draw the specified item
ASSERT(lpDrawItemStruct->CtlType == ODT_LISTVIEW);
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
ASSERT(NULL != dc.GetSafeHdc());
//dc.SelectObject(GetStockObject(DEFAULT_GUI_FONT));
// Save these value to restore them when done drawing.
COLORREF crOldTextColor = dc.GetTextColor();
COLORREF crOldBkColor = dc.GetBkColor();
CFont * pOldFont = NULL;
// If this item is selected, set the background color
// and the text color to appropriate values. Also, erase
// rect by filling it with the background color.
//if ((lpDrawItemStruct->itemAction | ODA_SELECT) &&
// (lpDrawItemStruct->itemState & ODS_SELECTED))
//{
// dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
// dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
// dc.FillSolidRect(&lpDrawItemStruct->rcItem,
// ::GetSysColor(COLOR_HIGHLIGHT));
//}
//else
//{
// if(lpDrawItemStruct->itemID%2)
// dc.FillSolidRect(&lpDrawItemStruct->rcItem, RGB(128,128,128));
// else
// dc.FillSolidRect(&lpDrawItemStruct->rcItem, RGB(255,128,255));
//}
// If this item has the focus, draw a red frame around the
// item's rect.
/*if ((lpDrawItemStruct->itemAction | ODA_FOCUS) &&
(lpDrawItemStruct->itemState & ODS_FOCUS))
{
CBrush br(RGB(128, 128, 128));
dc.FrameRect(&lpDrawItemStruct->rcItem, &br);
} */
// Draw the text.
CString strText(_T(""));
CRect rcItem;
for(int i=0; i
GetItemCount(); i++)
{
strText = GetItemText(lpDrawItemStruct->itemID, i);
GetSubItemRect(lpDrawItemStruct->itemID, i, LVIR_LABEL, rcItem);
rcItem.left += 5;
bool has(false);
CString strIndex;
strIndex.Format(_T("%d-%d"), lpDrawItemStruct->itemID, i);
CStringArray* pArrText = (CStringArray*)m_gridMap[strIndex];
if (pArrText)
{
int cnt = pArrText->GetCount();
for (int j(0); j < cnt; ++j)
{
strIndex.Format(_T("%d-%d-%d"),lpDrawItemStruct->itemID, i, j);
CString str(m_linkMap[strIndex]);
if (!str.IsEmpty())
{
has = true;
break;
}
}
}
if (has)
{
int cnt = pArrText->GetCount();
int start = rcItem.left;
for (int j(0); j < cnt; ++j)
{
int txtLen = GetStringWidth(pArrText->GetAt(j));
CRect rcTxt(rcItem);
rcTxt.left = start;
rcTxt.right = start + txtLen;
strIndex.Format(_T("%d-%d-%d"), lpDrawItemStruct->itemID, i, j);
CString str(m_linkMap[strIndex]);
if (!str.IsEmpty())
{
dc.SetTextColor(RGB(0,0,255));
CFont * pFont = GetFont();
ASSERT(pFont);
LOGFONT lf;
pFont->GetLogFont(&lf);
lf.lfUnderline = TRUE;
CFont fUnderline;
fUnderline.CreateFontIndirect(&lf);
pOldFont = dc.SelectObject(&fUnderline);
dc.DrawText(
pArrText->GetAt(j),
pArrText->GetAt(j).GetLength(),
&rcTxt,
DT_LEFT|DT_SINGLELINE|DT_VCENTER);
if (pOldFont) dc.SelectObject(pOldFont);
}
else
{
dc.SetTextColor(RGB(0,0,0));
dc.DrawText(
pArrText->GetAt(j),
pArrText->GetAt(j).GetLength(),
&rcTxt,
DT_LEFT|DT_SINGLELINE|DT_VCENTER);
}
start += txtLen +5;
}
}
else
{
dc.SetTextColor(RGB(0,0,0));
dc.DrawText(
strText,
strText.GetLength(),
&rcItem,
DT_LEFT|DT_SINGLELINE|DT_VCENTER);
}
}
// Reset the background color and the text color back to their
// original values.
dc.SetTextColor(crOldTextColor);
dc.SetBkColor(crOldBkColor);
dc.Detach();
}
void CLinkList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if( m_nItemHeight > 0 )
lpMeasureItemStruct->itemHeight = m_nItemHeight;
}
//设置行高
void CLinkList::SetItemHeight(UINT nHeight)
{
m_nItemHeight = nHeight;
CRect rcWin;
GetWindowRect(&rcWin);
WINDOWPOS wp;
wp.hwnd = m_hWnd;
wp.cx = rcWin.Width();
wp.cy = rcWin.Height();
wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp);
}