📄 mulelistctrl.cpp
字号:
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);
}
void CMuleListCtrl::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
if (nChar == 'A' && ::GetAsyncKeyState(VK_CONTROL)<0)
{
// Ctrl+A: Select all items
LV_ITEM theItem;
theItem.mask= LVIF_STATE;
theItem.iItem= -1;
theItem.iSubItem= 0;
theItem.state= LVIS_SELECTED;
theItem.stateMask= 2;
SetItemState(-1, &theItem);
}
else if (nChar==VK_DELETE)
PostMessage(WM_COMMAND, MPG_DELETE, 0);
else if (nChar==VK_F2)
PostMessage(WM_COMMAND, MPG_F2, 0);
else if (nChar == 'C' && (GetKeyState(VK_CONTROL) & 0x8000))
{
// Ctrl+C: Copy keycombo
SendMessage(WM_COMMAND, MP_COPYSELECTED);
}
if (nChar == 'V' && (GetKeyState(VK_CONTROL) & 0x8000))
{
// Ctrl+V: Paste keycombo
SendMessage(WM_COMMAND, MP_PASTE);
}
else if (m_bGeneralPurposeFind){
if (nChar == 'F' && (GetKeyState(VK_CONTROL) & 0x8000)){
// Ctrl+F: Search item
OnFindStart();
}
else if (nChar == VK_F3){
if (GetKeyState(VK_SHIFT) & 0x8000){
// Shift+F3: Search previous
OnFindPrev();
}
else{
// F3: Search next
OnFindNext();
}
}
}
return CListCtrl::OnKeyDown(nChar,nRepCnt,nFlags);
}
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)
m_lvcd = *((LPNMLVCUSTOMDRAW)lParam);
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_KEYDOWN()
ON_WM_ERASEBKGND()
ON_WM_SYSCOLORCHANGE()
END_MESSAGE_MAP()
//////////////////////////////////
// CMuleListCtrl message handlers
void CMuleListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {
//set up our flicker free drawing
CRect rcItem(lpDrawItemStruct->rcItem);
CDC *oDC = CDC::FromHandle(lpDrawItemStruct->hDC);
COLORREF crOldDCBkColor = 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);
if (m_crWindowTextBk == CLR_NONE){
DefWindowProc(WM_ERASEBKGND, (WPARAM)pDC->m_hDC, 0);
}
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 | LVIS_GLOW;
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));
BOOL bGlowing = ( lvi.state & LVIS_GLOW );
//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 if(bGlowing)
{
pDC->FillRect(rcHighlight, &CBrush(m_crGlow));
crOldBckColor = pDC->SetBkColor(m_crGlow);
}
else
{
pDC->FillRect(rcHighlight, &CBrush(m_crNoHighlight));
crOldBckColor = pDC->SetBkColor(m_crNoHighlight);
}
}
else
{
if(bGlowing)
{
pDC->FillRect(rcHighlight, &CBrush(m_crGlow));
crOldBckColor = pDC->SetBkColor(m_crGlow);
}
else
{
if (m_crWindowTextBk != CLR_NONE)
pDC->FillRect(rcHighlight, &CBrush(m_crWindow)); // was already done with WM_ERASEBKGND
crOldBckColor = pDC->SetBkColor(m_crWindow);
}
}
//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);
}
int iOldBkMode = (m_crWindowTextBk == CLR_NONE) ? pDC->SetBkMode(TRANSPARENT) : OPAQUE;
//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));
}
pDC->Flush();
if (m_crWindowTextBk == CLR_NONE)
pDC->SetBkMode(iOldBkMode);
pDC->SelectObject(pOldFont);
pDC->SetTextColor(crOldTextColor);
pDC->SetBkColor(crOldBckColor);
oDC->SetBkColor(crOldDCBkColor);
}
BOOL CMuleListCtrl::OnEraseBkgnd(CDC* pDC)
{
// if (m_crWindowTextBk == CLR_NONE) // this creates a lot screen flickering
// return CListCtrl::OnEraseBkgnd(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;
CRect rcClip;
//draw top portion
GetClientRect(&clientRect);
rcClip = clientRect;
GetItemRect(topIndex, &itemRect, LVIR_BOUNDS);
clientRect.bottom = itemRect.top;
if (m_crWindowTextBk != CLR_NONE)
pDC->FillSolidRect(&clientRect,GetBkColor());
else
rcClip.top = itemRect.top;
//draw bottom portion if we have to
if(topIndex + maxItems >= itemCount) {
GetClientRect(&clientRect);
GetItemRect(topIndex + drawnItems - 1, &itemRect, LVIR_BOUNDS);
clientRect.top = itemRect.bottom;
rcClip.bottom = itemRect.bottom;
if (m_crWindowTextBk != CLR_NONE)
pDC->FillSolidRect(&clientRect, GetBkColor());
}
//draw right half if we need to
if (itemRect.right < clientRect.right) {
GetClientRect(&clientRect);
clientRect.left = itemRect.right;
rcClip.right = itemRect.right;
if (m_crWindowTextBk != CLR_NONE)
pDC->FillSolidRect(&clientRect, GetBkColor());
}
if (m_crWindowTextBk == CLR_NONE){
CRect rcClipBox;
pDC->GetClipBox(&rcClipBox);
rcClipBox.SubtractRect(&rcClipBox, &rcClip);
if (!rcClipBox.IsRectEmpty()){
pDC->ExcludeClipRect(&rcClip);
CListCtrl::OnEraseBkgnd(pDC);
InvalidateRect(&rcClip, FALSE);
}
}
return TRUE;
}
void CMuleListCtrl::OnSysColorChange()
{
//adjust colors
CListCtrl::OnSysColorChange();
SetColors();
//redraw the up/down sort arrow (if it's there)
if(m_iCurrentSortItem >= 0)
SetSortArrow(m_iCurrentSortItem, (ArrowType)m_atSortArrow);
}
HIMAGELIST CMuleListCtrl::ApplyImageList(HIMAGELIST himl)
{
HIMAGELIST himlOld = (HIMAGELIST)SendMessage(LVM_SETIMAGELIST, LVSIL_SMALL, (LPARAM)himl);
if (m_imlHeaderCtrl.m_hImageList != NULL){
// Must *again* set the image list for the header control, because LVM_SETIMAGELIST
// always resets any already specified header control image lists!
GetHeaderCtrl()->SetImageList(&m_imlHeaderCtrl);
}
return himlOld;
}
void CMuleListCtrl::DoFind(int iStartItem, int iDirection /*1=down, 0 = up*/, BOOL bShowError)
{
CWaitCursor curHourglass;
if (iStartItem < 0) {
MessageBeep((UINT)-1);
return;
}
int iNumItems = iDirection ? GetItemCount() : 0;
int iItem = iStartItem;
while ( iDirection ? iItem < iNumItems : iItem >= 0 )
{
CString strItemText(GetItemText(iItem, m_iFindColumn));
if (!strItemText.IsEmpty())
{
if ( m_bFindMatchCase
? _tcsstr(strItemText, m_strFindText) != NULL
: stristr(strItemText, m_strFindText) != NULL )
{
// Deselect all listview entries
SetItemState(-1, 0, LVIS_SELECTED);
// Select the found listview entry
SetItemState(iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
SetSelectionMark(iItem);
EnsureVisible(iItem, FALSE/*bPartialOK*/);
SetFocus();
return;
}
}
if (iDirection)
iItem++;
else
iItem--;
}
if (bShowError)
AfxMessageBox(GetResString(IDS_SEARCH_NORESULT), MB_ICONINFORMATION);
else
MessageBeep((UINT)-1);
}
void CMuleListCtrl::OnFindStart()
{
CListViewSearchDlg dlg;
dlg.m_pListView = this;
dlg.m_strFindText = m_strFindText;
dlg.m_iSearchColumn = m_iFindColumn;
if (dlg.DoModal() != IDOK || dlg.m_strFindText.IsEmpty())
return;
m_strFindText = dlg.m_strFindText;
m_iFindColumn = dlg.m_iSearchColumn;
DoFindNext(TRUE/*bShowError*/);
}
void CMuleListCtrl::OnFindNext()
{
DoFindNext(FALSE/*bShowError*/);
}
void CMuleListCtrl::DoFindNext(BOOL bShowError)
{
int iStartItem = GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED);
if (iStartItem == -1)
iStartItem = 0;
else
iStartItem = iStartItem + (m_iFindDirection ? 1 : -1);
DoFind(iStartItem, m_iFindDirection, bShowError);
}
void CMuleListCtrl::OnFindPrev()
{
int iStartItem = GetNextItem(-1, LVNI_SELECTED | LVNI_FOCUSED);
if (iStartItem == -1)
iStartItem = 0;
else
iStartItem = iStartItem + (!m_iFindDirection ? 1 : -1);
DoFind(iStartItem, !m_iFindDirection, FALSE/*bShowError*/);
}
BOOL CMuleListCtrl::PreTranslateMessage(MSG* pMsg)
{
if ( pMsg->message == 260 && pMsg->wParam == 13 && GetAsyncKeyState(VK_MENU)<0 ) {
PostMessage(WM_COMMAND, MPG_ALTENTER, 0);
return TRUE;
}
return CListCtrl::PreTranslateMessage(pMsg);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -