📄 listctrlex.cpp
字号:
// ListCtrlEx.cpp : implementation file
//
#include "stdafx.h"
#include "StraceGui.h"
#include "ListCtrlEx.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
m_bFullRowSel = FALSE;
m_bClientWidthSel = TRUE;
m_cxClient = 0;
m_cxStateImageOffset = 0;
m_clrText = ::GetSysColor(COLOR_WINDOWTEXT);
m_clrTextBk = ::GetSysColor(COLOR_WINDOW);
m_clrBkgnd = ::GetSysColor(COLOR_WINDOW);
m_bFullRowSel = TRUE;
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
//{{AFX_MSG_MAP(CListCtrlEx)
ON_WM_SIZE()
ON_WM_PAINT()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CListCtrlEx::SetFullRowSel(BOOL bFullRowSel)
{
// no painting during change
LockWindowUpdate();
m_bFullRowSel = bFullRowSel;
BOOL bRet;
if (m_bFullRowSel)
bRet = ModifyStyle(0L, LVS_OWNERDRAWFIXED);
else
bRet = ModifyStyle(LVS_OWNERDRAWFIXED, 0L);
// repaint window if we are not changing view type
if (bRet && (GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
Invalidate();
// repaint changes
UnlockWindowUpdate();
return(bRet);
}
BOOL CListCtrlEx::GetFullRowSel()
{
return(m_bFullRowSel);
}
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers
LRESULT CListCtrlEx::OnSetImageList(WPARAM wParam, LPARAM lParam)
{
if( (int) wParam == LVSIL_STATE)
{
int cx, cy;
if(::ImageList_GetIconSize((HIMAGELIST)lParam, &cx, &cy))
m_cxStateImageOffset = cx;
else
m_cxStateImageOffset = 0;
}
return(Default());
}
LRESULT CListCtrlEx::OnSetTextColor(WPARAM wParam, LPARAM lParam)
{
m_clrText = (COLORREF)lParam;
return(Default());
}
LRESULT CListCtrlEx::OnSetTextBkColor(WPARAM wParam, LPARAM lParam)
{
m_clrTextBk = (COLORREF)lParam;
return(Default());
}
LRESULT CListCtrlEx::OnSetBkColor(WPARAM wParam, LPARAM lParam)
{
m_clrBkgnd = (COLORREF)lParam;
return(Default());
}
void CListCtrlEx::OnSize(UINT nType, int cx, int cy)
{
m_cxClient = cx;
CListCtrl::OnSize(nType, cx, cy);
}
void CListCtrlEx::OnPaint()
{
// in full row select mode, we need to extend the clipping region
// so we can paint a selection all the way to the right
if (m_bClientWidthSel &&
(GetStyle() & LVS_TYPEMASK) == LVS_REPORT &&
GetFullRowSel())
{
CRect rcAllLabels;
GetItemRect(0, rcAllLabels, LVIR_BOUNDS);
if(rcAllLabels.right < m_cxClient)
{
// need to call BeginPaint (in CPaintDC c-tor)
// to get correct clipping rect
CPaintDC dc(this);
CRect rcClip;
dc.GetClipBox(rcClip);
rcClip.left = min(rcAllLabels.right-1, rcClip.left);
rcClip.right = m_cxClient;
InvalidateRect(rcClip, FALSE);
// EndPaint will be called in CPaintDC d-tor
}
}
CListCtrl::OnPaint();
}
void CListCtrlEx::OnSetFocus(CWnd* pOldWnd)
{
CListCtrl::OnSetFocus(pOldWnd);
// check if we are getting focus from label edit box
if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
return;
// repaint items that should change appearance
if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
RepaintSelectedItems();
}
void CListCtrlEx::OnKillFocus(CWnd* pNewWnd)
{
CListCtrl::OnKillFocus(pNewWnd);
// check if we are losing focus to label edit box
if(pNewWnd != NULL && pNewWnd->GetParent() == this)
return;
// repaint items that should change appearance
if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
RepaintSelectedItems();
}
// offsets for first and other columns
#define OFFSET_FIRST 2
#define OFFSET_OTHER 6
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rcItem(lpDrawItemStruct->rcItem);
UINT uiFlags = ILD_TRANSPARENT;
CImageList* pImageList;
int nItem = lpDrawItemStruct->itemID;
BOOL bFocus = (GetFocus() == this);
COLORREF clrTextSave, clrBkSave;
COLORREF clrImage = m_clrBkgnd;
static _TCHAR szBuff[MAX_PATH];
LPCTSTR pszText;
// get item data
LV_ITEM lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvi.iItem = nItem;
lvi.iSubItem = 0;
lvi.pszText = szBuff;
lvi.cchTextMax = sizeof(szBuff);
lvi.stateMask = 0xFFFF; // get all state flags
GetItem(&lvi);
BOOL bSelected = (bFocus || (GetStyle() & LVS_SHOWSELALWAYS)) && lvi.state & LVIS_SELECTED;
bSelected = bSelected || (lvi.state & LVIS_DROPHILITED);
// set colors if item is selected
CRect rcAllLabels;
GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
CRect rcLabel;
GetItemRect(nItem, rcLabel, LVIR_LABEL);
rcAllLabels.left = rcLabel.left;
if (m_bClientWidthSel && rcAllLabels.right<m_cxClient)
rcAllLabels.right = m_cxClient;
if (bSelected)
{
clrTextSave = pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
clrBkSave = pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
pDC->FillRect(rcAllLabels, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
}
else
pDC->FillRect(rcAllLabels, &CBrush(m_clrTextBk));
// set color and mask for the icon
if (lvi.state & LVIS_CUT)
{
clrImage = m_clrBkgnd;
uiFlags |= ILD_BLEND50;
}
else if (bSelected)
{
clrImage = ::GetSysColor(COLOR_HIGHLIGHT);
uiFlags |= ILD_BLEND50;
}
// draw state icon
UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK;
if (nStateImageMask)
{
int nImage = (nStateImageMask>>12) - 1;
pImageList = GetImageList(LVSIL_STATE);
if (pImageList)
{
pImageList->Draw(pDC, nImage,
CPoint(rcItem.left, rcItem.top), ILD_TRANSPARENT);
}
}
// draw normal and overlay icon
CRect rcIcon;
GetItemRect(nItem, rcIcon, LVIR_ICON);
pImageList = GetImageList(LVSIL_SMALL);
if (pImageList)
{
UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
if (rcItem.left<rcItem.right-1)
{
ImageList_DrawEx(pImageList->m_hImageList, lvi.iImage,
pDC->m_hDC,rcIcon.left,rcIcon.top, 16, 16,
m_clrBkgnd, clrImage, uiFlags | nOvlImageMask);
}
}
// draw item label
GetItemRect(nItem, rcItem, LVIR_LABEL);
rcItem.right -= m_cxStateImageOffset;
pszText = MakeShortString(pDC, szBuff,
rcItem.right-rcItem.left, 2*OFFSET_FIRST);
rcLabel = rcItem;
rcLabel.left += OFFSET_FIRST;
rcLabel.right -= OFFSET_FIRST;
pDC->DrawText(pszText,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
// draw labels for extra columns
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH;
for(int nColumn = 1; GetColumn(nColumn, &lvc); nColumn++)
{
rcItem.left = rcItem.right;
rcItem.right += lvc.cx;
int nRetLen = GetItemText(nItem, nColumn,
szBuff, sizeof(szBuff));
if (nRetLen == 0)
continue;
pszText = MakeShortString(pDC, szBuff,
rcItem.right - rcItem.left, 2*OFFSET_OTHER);
UINT nJustify = DT_LEFT;
if(pszText == szBuff)
{
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
{
case LVCFMT_RIGHT:
nJustify = DT_RIGHT;
break;
case LVCFMT_CENTER:
nJustify = DT_CENTER;
break;
default:
break;
}
}
rcLabel = rcItem;
rcLabel.left += OFFSET_OTHER;
rcLabel.right -= OFFSET_OTHER;
pDC->DrawText(pszText, -1, rcLabel,
nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
}
// draw focus rectangle if item has focus
if (lvi.state & LVIS_FOCUSED && bFocus)
pDC->DrawFocusRect(rcAllLabels);
// set original colors if item was selected
if (bSelected)
{
pDC->SetTextColor(clrTextSave);
pDC->SetBkColor(clrBkSave);
}
}
LPCTSTR CListCtrlEx::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
{
static const _TCHAR szThreeDots[] = _T("...");
int nStringLen = lstrlen(lpszLong);
if(nStringLen == 0 ||
(pDC->GetTextExtent(lpszLong, nStringLen).cx + nOffset) <= nColumnLen)
{
return(lpszLong);
}
static _TCHAR szShort[MAX_PATH];
lstrcpy(szShort,lpszLong);
int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
for(int i = nStringLen-1; i > 0; i--)
{
szShort[i] = 0;
if((pDC->GetTextExtent(szShort, i).cx + nOffset + nAddLen)
<= nColumnLen)
{
break;
}
}
lstrcat(szShort, szThreeDots);
return(szShort);
}
void CListCtrlEx::RepaintSelectedItems()
{
CRect rcItem, rcLabel;
// invalidate focused item so it can repaint properly
int nItem = GetNextItem(-1, LVNI_FOCUSED);
if(nItem != -1)
{
GetItemRect(nItem, rcItem, LVIR_BOUNDS);
GetItemRect(nItem, rcLabel, LVIR_LABEL);
rcItem.left = rcLabel.left;
InvalidateRect(rcItem, FALSE);
}
// if selected items should not be preserved, invalidate them
if(!(GetStyle() & LVS_SHOWSELALWAYS))
{
for(nItem = GetNextItem(-1, LVNI_SELECTED);
nItem != -1; nItem = GetNextItem(nItem, LVNI_SELECTED))
{
GetItemRect(nItem, rcItem, LVIR_BOUNDS);
GetItemRect(nItem, rcLabel, LVIR_LABEL);
rcItem.left = rcLabel.left;
InvalidateRect(rcItem, FALSE);
}
}
// update changes
UpdateWindow();
}
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx diagnostics
#ifdef _DEBUG
void CListCtrlEx::Dump(CDumpContext& dc) const
{
CListCtrl::Dump(dc);
dc << "m_bFullRowSel = " << (UINT)m_bFullRowSel;
dc << "\n";
dc << "m_cxStateImageOffset = " << m_cxStateImageOffset;
dc << "\n";
}
#endif //_DEBUG
void CListCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
UINT uFlags = 0;
int nHitItem = HitTest(point, &uFlags);
// we need additional checking in owner-draw mode
// because we only get LVHT_ONITEM
BOOL bHit = FALSE;
if (uFlags == LVHT_ONITEM && (GetStyle() & LVS_OWNERDRAWFIXED))
{
CRect rect;
GetItemRect(nHitItem, rect, LVIR_ICON);
// check if hit was on a state icon
if (point.x < rect.left)
bHit = TRUE;
}
else if (uFlags & LVHT_ONITEMSTATEICON)
bHit = TRUE;
if (bHit){
int i = -1;
BOOL NewState = !IsChecked(nHitItem);
if( GetItemState(nHitItem,LVNI_SELECTED) )
{
while( (i = GetNextItem(i,LVNI_SELECTED)) != -1)
{
if(NewState)
SetItemState(i,
INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK);
else{
SetItemState(i,
INDEXTOSTATEIMAGEMASK(1), LVIS_STATEIMAGEMASK);
}
}
}
else{
CheckItem(nHitItem);
}
}
else
CListCtrl::OnLButtonDown(nFlags, point);
}
void CListCtrlEx::CheckItem(int nNewCheckedItem)
{
// reset if there is checked item
UINT ItemState = GetItemState(nNewCheckedItem, LVIS_STATEIMAGEMASK);
if(ItemState & INDEXTOSTATEIMAGEMASK(1))
{
SetItemState(nNewCheckedItem,
INDEXTOSTATEIMAGEMASK(2), LVIS_STATEIMAGEMASK);
}
else
{
SetItemState(nNewCheckedItem,
INDEXTOSTATEIMAGEMASK(1), LVIS_STATEIMAGEMASK );
}
}
BOOL CListCtrlEx::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
cs.style &= ~LVS_TYPEMASK;
cs.style |= LVS_REPORT | LVS_OWNERDRAWFIXED;
m_bFullRowSel = TRUE;
return CListCtrl::PreCreateWindow(cs);
}
BOOL CListCtrlEx::IsChecked(int i)
{
UINT ItemState = GetItemState(i, LVIS_STATEIMAGEMASK);
return (ItemState & INDEXTOSTATEIMAGEMASK(2));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -