📄 mulelistctrl.cpp
字号:
}
return *pResult = 1;
}
}
break;
case WM_COMMAND:
//deal with menu clicks
if(wParam == MLC_IDC_UPDATE) {
UpdateLocation(lParam);
return *pResult = 1;
} else if(wParam >= MLC_IDC_MENU) {
CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
int iCount = pHeaderCtrl->GetItemCount();
int iToggle = wParam - MLC_IDC_MENU;
if(iToggle >= iCount)
break;
if(m_aColumns[iToggle].bHidden)
ShowColumn(iToggle);
else
HideColumn(iToggle);
return *pResult = 1;
}
break;
case LVM_DELETECOLUMN:
//book keeping!
if(m_aColumns != NULL) {
for(int i = 0; i < m_iColumnsTracked; i++)
if(m_aColumns[i].bHidden)
ShowColumn(i);
delete[] m_aColumns;
}
m_aColumns = new MULE_COLUMN[--m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++) {
m_aColumns[i].iLocation = i;
m_aColumns[i].bHidden = false;
}
break;
//case LVM_INSERTCOLUMN:
case LVM_INSERTCOLUMNA:
case LVM_INSERTCOLUMNW:
//book keeping!
if(m_aColumns != NULL) {
for(int i = 0; i < m_iColumnsTracked; i++)
if(m_aColumns[i].bHidden)
ShowColumn(i);
delete[] m_aColumns;
}
m_aColumns = new MULE_COLUMN[++m_iColumnsTracked];
for(int i = 0; i < m_iColumnsTracked; i++) {
m_aColumns[i].iLocation = i;
m_aColumns[i].bHidden = false;
}
break;
case LVM_SETITEM:
//book keeping
{
POSITION pos = m_Params.FindIndex(((LPLVITEM)lParam)->iItem);
if(pos) {
m_Params.SetAt(pos, MLC_MAGIC);
PostMessage(LVM_UPDATE, ((LPLVITEM)lParam)->iItem);
}
}
break;
case LVM_SETITEMTEXT:
//need to check for movement
*pResult = DefWindowProc(message, wParam, lParam);
if(*pResult)
PostMessage(WM_COMMAND, MLC_IDC_UPDATE, wParam);
return *pResult;
case LVM_SORTITEMS:
//book keeping...
m_dwParamSort = (LPARAM)wParam;
m_SortProc = (PFNLVCOMPARE)lParam;
for(POSITION pos = m_Params.GetHeadPosition(); pos != NULL; m_Params.GetNext(pos))
m_Params.SetAt(pos, MLC_MAGIC);
break;
case LVM_DELETEALLITEMS:
//book keeping...
if(!CListCtrl::OnWndMsg(message, wParam, lParam, pResult) && DefWindowProc(message, wParam, lParam))
m_Params.RemoveAll();
return *pResult = TRUE;
case LVM_DELETEITEM:
//book keeping.....
MLC_ASSERT(m_Params.GetAt(m_Params.FindIndex(wParam)) == CListCtrl::GetItemData(wParam));
if(!CListCtrl::OnWndMsg(message, wParam, lParam, pResult) && DefWindowProc(message, wParam, lParam))
m_Params.RemoveAt(m_Params.FindIndex(wParam));
return *pResult = TRUE;
//case LVM_INSERTITEM:
case LVM_INSERTITEMA:
case LVM_INSERTITEMW:
//try to fix position of inserted items
{
LPLVITEM pItem = (LPLVITEM)lParam;
int iItem = pItem->iItem;
int iItemCount = GetItemCount();
BOOL notLast = iItem < iItemCount;
BOOL notFirst = iItem > 0;
if(notFirst) {
int iNewIndex = iItem - 1;
POSITION pos = m_Params.FindIndex(iNewIndex);
int iResult = m_SortProc(pItem->lParam, GetParamAt(pos, iNewIndex), m_dwParamSort);
if(iResult < 0) {
POSITION posPrev = pos;
int iDist = iNewIndex / 2;
while(iDist > 1) {
for(int i = 0; i < iDist; i++)
m_Params.GetPrev(posPrev);
if(m_SortProc(pItem->lParam, GetParamAt(posPrev, iNewIndex - iDist), m_dwParamSort) < 0) {
iNewIndex = iNewIndex - iDist;
pos = posPrev;
} else {
posPrev = pos;
}
iDist /= 2;
}
while(--iNewIndex >= 0) {
m_Params.GetPrev(pos);
if(m_SortProc(pItem->lParam, GetParamAt(pos, iNewIndex), m_dwParamSort) >= 0)
break;
}
pItem->iItem = iNewIndex + 1;
notLast = false;
}
}
if(notLast) {
int iNewIndex = iItem;
POSITION pos = m_Params.FindIndex(iNewIndex);
int iResult = m_SortProc(pItem->lParam, GetParamAt(pos, iNewIndex), m_dwParamSort);
if(iResult > 0) {
POSITION posNext = pos;
int iDist = (GetItemCount() - iNewIndex) / 2;
while(iDist > 1) {
for(int i = 0; i < iDist; i++)
m_Params.GetNext(posNext);
if(m_SortProc(pItem->lParam, GetParamAt(posNext, iNewIndex + iDist), m_dwParamSort) > 0) {
iNewIndex = iNewIndex + iDist;
pos = posNext;
} else {
posNext = pos;
}
iDist /= 2;
}
while(++iNewIndex < iItemCount) {
m_Params.GetNext(pos);
if(m_SortProc(pItem->lParam, GetParamAt(pos, iNewIndex), m_dwParamSort) <= 0)
break;
}
pItem->iItem = iNewIndex;
}
}
if(pItem->iItem == 0) {
m_Params.AddHead(pItem->lParam);
return FALSE;
}
LRESULT lResult = DefWindowProc(message, wParam, lParam);
if(lResult != -1) {
if(lResult >= GetItemCount())
m_Params.AddTail(pItem->lParam);
else if(lResult == 0)
m_Params.AddHead(pItem->lParam);
else
m_Params.InsertAfter(m_Params.FindIndex(lResult - 1), pItem->lParam);
}
return *pResult = lResult;
}
break;
case LVM_UPDATE:
//better fix for old problem... normally Update(int) causes entire list to redraw
if(wParam == UpdateLocation(wParam)) { //no need to invalidate rect if item moved
RECT rcItem;
BOOL bResult = GetItemRect(wParam, &rcItem, LVIR_BOUNDS);
if(bResult)
InvalidateRect(&rcItem, FALSE);
return *pResult = bResult;
}
return *pResult = TRUE;
}
return CListCtrl::OnWndMsg(message, wParam, lParam, pResult);
}
BOOL CMuleListCtrl::OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
if(message != WM_DRAWITEM) {
//catch the prepaint and copy struct
if(message == WM_NOTIFY && ((NMHDR*)lParam)->code == NM_CUSTOMDRAW &&
((LPNMLVCUSTOMDRAW)lParam)->nmcd.dwDrawStage == CDDS_ITEMPREPAINT) {
m_bCustomDraw = CListCtrl::OnChildNotify(message, wParam, lParam, pResult);
if(m_bCustomDraw)
memcpy(&m_lvcd, (void*)lParam, sizeof(NMLVCUSTOMDRAW));
return m_bCustomDraw;
}
return CListCtrl::OnChildNotify(message, wParam, lParam, pResult);
}
ASSERT(pResult == NULL); // no return value expected
UNUSED(pResult); // unused in release builds
DrawItem((LPDRAWITEMSTRUCT)lParam);
return TRUE;
}
//////////////////////////////////
// CMuleListCtrl message map
BEGIN_MESSAGE_MAP(CMuleListCtrl, CListCtrl)
ON_WM_DRAWITEM()
ON_WM_ERASEBKGND()
ON_WM_SYSCOLORCHANGE()
END_MESSAGE_MAP()
//////////////////////////////////
// CMuleListCtrl message handlers
void CMuleListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {
//set up our ficker free drawing
CRect rcItem(lpDrawItemStruct->rcItem);
CDC *oDC = CDC::FromHandle(lpDrawItemStruct->hDC);
oDC->SetBkColor(m_crWindow);
CMemDC pDC(oDC, &rcItem);
CFont *pOldFont = pDC->SelectObject(GetFont());
COLORREF crOldTextColor;
if(m_bCustomDraw)
crOldTextColor = pDC->SetTextColor(m_lvcd.clrText);
else
crOldTextColor = pDC->SetTextColor(m_crWindowText);
int iOffset = pDC->GetTextExtent(_T(" "), 1 ).cx*2;
int iItem = lpDrawItemStruct->itemID;
CImageList* pImageList;
CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
//gets the item image and state info
LV_ITEM lvi;
lvi.mask = LVIF_IMAGE | LVIF_STATE;
lvi.iItem = iItem;
lvi.iSubItem = 0;
lvi.stateMask = LVIS_DROPHILITED | LVIS_FOCUSED | LVIS_SELECTED;
GetItem(&lvi);
//see if the item be highlighted
BOOL bHighlight = ((lvi.state & LVIS_DROPHILITED) || (lvi.state & LVIS_SELECTED));
BOOL bCtrlFocused = ((GetFocus() == this) || (GetStyle() & LVS_SHOWSELALWAYS));
//get rectangles for drawing
CRect rcBounds, rcLabel, rcIcon;
GetItemRect(iItem, rcBounds, LVIR_BOUNDS);
GetItemRect(iItem, rcLabel, LVIR_LABEL);
GetItemRect(iItem, rcIcon, LVIR_ICON);
CRect rcCol(rcBounds);
//the label!
CString sLabel = GetItemText(iItem, 0);
//labels are offset by a certain amount
//this offset is related to the width of a space character
CRect rcHighlight;
CRect rcWnd;
//should I check (GetExtendedStyle() & LVS_EX_FULLROWSELECT) ?
rcHighlight.top = rcBounds.top;
rcHighlight.bottom = rcBounds.bottom;
rcHighlight.left = rcBounds.left + 1;
rcHighlight.right = rcBounds.right - 1;
COLORREF crOldBckColor;
//draw the background color
if(bHighlight)
{
if(bCtrlFocused)
{
pDC->FillRect(rcHighlight, &CBrush(m_crHighlight));
crOldBckColor = pDC->SetBkColor(m_crHighlight);
}
else
{
pDC->FillRect(rcHighlight, &CBrush(m_crNoHighlight));
crOldBckColor = pDC->SetBkColor(m_crNoHighlight);
}
}
else
{
pDC->FillRect(rcHighlight, &CBrush(m_crWindow));
crOldBckColor = pDC->SetBkColor(GetBkColor());
}
//update column
rcCol.right = rcCol.left + GetColumnWidth(0);
//draw state icon
if(lvi.state & LVIS_STATEIMAGEMASK)
{
int nImage = ((lvi.state & LVIS_STATEIMAGEMASK)>>12) - 1;
pImageList = GetImageList(LVSIL_STATE);
if(pImageList)
{
COLORREF crOld = pImageList->SetBkColor(CLR_NONE);
pImageList->Draw(pDC, nImage, rcCol.TopLeft(), ILD_NORMAL);
pImageList->SetBkColor(crOld);
}
}
//draw the item's icon
pImageList = GetImageList(LVSIL_SMALL);
if(pImageList)
{
COLORREF crOld = pImageList->SetBkColor(CLR_NONE);
pImageList->Draw(pDC, lvi.iImage, rcIcon.TopLeft(), ILD_NORMAL);
pImageList->SetBkColor(crOld);
}
//draw item label (column 0)
rcLabel.left += iOffset / 2;
rcLabel.right -= iOffset;
pDC->DrawText(sLabel, -1, rcLabel, MLC_DT_TEXT | DT_LEFT | DT_NOCLIP);
//draw labels for remaining columns
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH;
rcBounds.right = rcHighlight.right > rcBounds.right ? rcHighlight.right : rcBounds.right;
int iCount = pHeaderCtrl->GetItemCount();
for(int iCurrent = 1; iCurrent < iCount; iCurrent++)
{
int iColumn = pHeaderCtrl->OrderToIndex(iCurrent);
//don't draw column 0 again
if(iColumn == 0)
continue;
GetColumn(iColumn, &lvc);
//don't draw anything with 0 width
if(lvc.cx == 0)
continue;
rcCol.left = rcCol.right;
rcCol.right += lvc.cx;
sLabel = GetItemText(iItem, iColumn);
if (sLabel.GetLength() == 0)
continue;
//get the text justification
UINT nJustify = DT_LEFT;
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
{
case LVCFMT_RIGHT:
nJustify = DT_RIGHT;
break;
case LVCFMT_CENTER:
nJustify = DT_CENTER;
break;
default:
break;
}
rcLabel = rcCol;
rcLabel.left += iOffset;
rcLabel.right -= iOffset;
pDC->DrawText(sLabel, -1, rcLabel, MLC_DT_TEXT | nJustify);
}
//draw focus rectangle if item has focus
if((lvi.state & LVIS_FOCUSED) && (bCtrlFocused || (lvi.state & LVIS_SELECTED)))
{
if(!bCtrlFocused || !(lvi.state & LVIS_SELECTED))
pDC->FrameRect(rcHighlight, &CBrush(m_crNoFocusLine));
else
pDC->FrameRect(rcHighlight, &CBrush(m_crFocusLine));
}
//restore old font
pDC->SelectObject(pOldFont);
pDC->SetTextColor(crOldTextColor);
pDC->SetBkColor(crOldBckColor);
}
BOOL CMuleListCtrl::OnEraseBkgnd(CDC* pDC) {
int itemCount = GetItemCount();
if (!itemCount)
return CListCtrl::OnEraseBkgnd(pDC);
RECT clientRect;
RECT itemRect;
int topIndex = GetTopIndex();
int maxItems = GetCountPerPage();
int drawnItems = itemCount < maxItems ? itemCount : maxItems;
//draw top portion
GetClientRect(&clientRect);
GetItemRect(topIndex, &itemRect, LVIR_BOUNDS);
clientRect.bottom = itemRect.top;
pDC->FillSolidRect(&clientRect,GetBkColor());
//draw bottom portion if we have to
if(topIndex + maxItems >= itemCount) {
GetClientRect(&clientRect);
GetItemRect(topIndex + drawnItems - 1, &itemRect, LVIR_BOUNDS);
clientRect.top = itemRect.bottom;
pDC->FillSolidRect(&clientRect, GetBkColor());
}
//draw right half if we need to
if (itemRect.right < clientRect.right) {
GetClientRect(&clientRect);
clientRect.left = itemRect.right;
pDC->FillSolidRect(&clientRect, GetBkColor());
}
return TRUE;
}
void CMuleListCtrl::OnSysColorChange() {
//adjust colors
CListCtrl::OnSysColorChange();
SetColors();
//redraw the up/down sort arrow (if it's there)
if(m_iCurrentSortItem >= 0) {
CHeaderCtrl *pHeaderCtrl = GetHeaderCtrl();
HDITEM headerItem;
headerItem.mask = HDI_FORMAT | HDI_BITMAP;
if(pHeaderCtrl->GetItem(m_iCurrentSortItem, &headerItem) && headerItem.hbm != 0) {
DeleteObject(headerItem.hbm);
headerItem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
headerItem.hbm = (HBITMAP)LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(m_atSortArrow), IMAGE_BITMAP, 0, 0,
LR_LOADMAP3DCOLORS);
pHeaderCtrl->SetItem(m_iCurrentSortItem, &headerItem);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -