📄 listvwex.cpp
字号:
ListCtrl.GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
CRect rcLabel;
ListCtrl.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
{
m_clrText;
COLORREF* p = NULL;
if( m_RowClrArray.GetSize() > nItem )
p = (COLORREF*)m_RowClrArray.GetAt(nItem);
if( p )
pDC->FillRect(rcAllLabels, &CBrush(*p));
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;
}
if( bSelected )
pDC->SetTextColor(RGB(255,255,255));
else
pDC->SetTextColor(m_clrText);
// draw state icon
UINT nStateImageMask = lvi.state & LVIS_STATEIMAGEMASK;
if (nStateImageMask)
{
int nImage = (nStateImageMask>>12) - 1;
pImageList = ListCtrl.GetImageList(LVSIL_STATE);
if (pImageList)
{
pImageList->Draw(pDC, nImage,
CPoint(rcItem.left, rcItem.top), ILD_TRANSPARENT);
}
}
// draw normal and overlay icon
CRect rcIcon;
ListCtrl.GetItemRect(nItem, rcIcon, LVIR_ICON);
pImageList = ListCtrl.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
ListCtrl.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; ListCtrl.GetColumn(nColumn, &lvc); nColumn++)
{
rcItem.left = rcItem.right;
rcItem.right += lvc.cx;
int nRetLen = ListCtrl.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 CListVwEx::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 CListVwEx::RepaintSelectedItems()
{
CListCtrl& ListCtrl = GetListCtrl();
CRect rcItem, rcLabel;
// invalidate focused item so it can repaint properly
int nItem = ListCtrl.GetNextItem(-1, LVNI_FOCUSED);
if(nItem != -1)
{
ListCtrl.GetItemRect(nItem, rcItem, LVIR_BOUNDS);
ListCtrl.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 = ListCtrl.GetNextItem(-1, LVNI_SELECTED);
nItem != -1; nItem = ListCtrl.GetNextItem(nItem, LVNI_SELECTED))
{
ListCtrl.GetItemRect(nItem, rcItem, LVIR_BOUNDS);
ListCtrl.GetItemRect(nItem, rcLabel, LVIR_LABEL);
rcItem.left = rcLabel.left;
InvalidateRect(rcItem, FALSE);
}
}
// update changes
UpdateWindow();
}
//////////////////////////////////////////////////////////////////////
// OnHeaderClicked()
// Parameters: pNMHDR - Contains information about a notificationmessage.
// LRESULT - Contains the result from the message
// Action: Sort the column that the user clicks on. If it is not
// the same column as the last sorting then sorting ascending.
// If is the same column then toggle the sorting style. The
// list only recieves this message if the "no sort header" is
// NOT checked in the resource.// Returns: Nothing.
//////////////////////////////////////////////////////////////////////
void CListVwEx::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult)
{
HD_NOTIFY *phdNotify = (HD_NOTIFY *)pNMHDR;
if (phdNotify->iButton == 0)
{
m_bSortAscending = (phdNotify->iItem == m_nSortedColumn) ?!m_bSortAscending : TRUE;
m_nSortedColumn = phdNotify->iItem;
m_nCompareAs = (ListCompareType)m_nColumnType[m_nSortedColumn];
Sort();
}
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////// Sort()
// Parameters: None.
// Action: This function is called when the user clicks on a column
// header. Derived classes should override this function
// if they want to change the m_nCompareAs based on the
// the column that was selected.// Returns: Nothing.
//////////////////////////////////////////////////////////////////////
void CListVwEx::Sort()
{
Sort(m_nSortedColumn, m_bSortAscending, m_nCompareAs);
}
//////////////////////////////////////////////////////////////////////// Sort()
// Parameters: nColumn - column to sort by
// bAscending - TRUE ascending sort, FALSE descending
// nCompareAs - How to compare the values as
// Action: Set all the sorting attributes then do a quick sort
// on the whole list. Derived class may want to override
// this if they want to use a different sort algorithm or
// want to use a different range// Returns: Nothing.
//////////////////////////////////////////////////////////////////////
void CListVwEx::Sort(int nColumn, BOOL bAscending, ListCompareType nCompareAs)
{
m_nSortedColumn = nColumn;
m_bSortAscending = bAscending;
m_nCompareAs = nCompareAs;
QuickSort(0, GetListCtrl().GetItemCount() - 1);
}
//////////////////////////////////////////////////////////////////////
// QuickSort()
// Parameters: p - start position, usually index 0
// q - end position, usually last index
// Action: Standard quick sort algorthim// Returns: Nothing.
//////////////////////////////////////////////////////////////////////
void CListVwEx::QuickSort(int p, int r)
{
if (p < r)
{
int q = Partition(p, r);
QuickSort(p, q);
QuickSort(q + 1, r);
}
}
//////////////////////////////////////////////////////////////////////
// Partition()
// Parameters: p - start position// q - end position
// Action: Partition of the array in the quick sort algorithm
// Returns: Nothing.
///////////////////////////////////////////////////////////////////
int CListVwEx::Partition(int p, int r)
{
CString tmp;
CListCtrl& ListCtrl = GetListCtrl();
CString x = ListCtrl.GetItemText( p, m_nSortedColumn);
int i = p - 1;
int j = r + 1;
while (i < j)
{
do
{
j--;
tmp = ListCtrl.GetItemText(j, m_nSortedColumn);
}
while (CompareBy(tmp, x, m_bSortAscending ? ELOT_GT : ELOT_LT));
do
{
i++;
tmp = ListCtrl.GetItemText(i, m_nSortedColumn);
}
while (CompareBy(tmp, x, m_bSortAscending ? ELOT_LT : ELOT_GT));
if (i < j)
{
SwapRow(i, j);
}
}
return j;
}
//////////////////////////////////////////////////////////////////////
// CompareBy()
// Parameters: str1 - string 1 (left operand)
// str2 - string 2 (right operand)
// op - operator type
// Action: Convert strings to new data type based on m_nCompareAs'
// value. Compare the strings using the operator.
// Returns: The result of (str1 op str2)
//////////////////////////////////////////////////////////////////////
BOOL CListVwEx::CompareBy(CString str1, CString str2, ListOperatorType op)
{
BOOL bReturn = FALSE;
switch (m_nCompareAs)
{
case ELCT_INTEGER:
{
int val1 = atoi(str1);
int val2 = atoi(str2);
if (op == ELOT_LT)
bReturn = (val1 < val2);
else if (op == ELOT_GT)
bReturn = (val1 > val2);
else if (op == ELOT_LTE)
bReturn = (val1 <= val2);
else if (op == ELOT_GTE)
bReturn = (val1 >= val2);
else
bReturn = (val1 == val2);
break;
}
case ELCT_DOUBLE:
{
double val1 = atof(str1);
double val2 = atof(str2);
if (op == ELOT_LT)
bReturn = (val1 < val2);
else if (op == ELOT_GT)
bReturn = (val1 > val2);
else if (op == ELOT_LTE)
bReturn = (val1 <= val2);
else if (op == ELOT_GTE)
bReturn = (val1 >= val2);
else
bReturn = (val1 == val2);
break;
}
case ELCT_DATETIME:
{
COleDateTime val1 = ParseDateTime(str1);
COleDateTime val2 = ParseDateTime(str2);
if (op == ELOT_LT)
bReturn = (val1 < val2);
else if (op == ELOT_GT)
bReturn = (val1 > val2);
else if (op == ELOT_LTE)
bReturn = (val1 <= val2);
else if (op == ELOT_GTE)
bReturn = (val1 >= val2);
else
bReturn = (val1 == val2);
break;
}
case ELCT_STRING_NOCASE:
{
str1.MakeUpper();
str2.MakeUpper();
}
case ELCT_STRING_CASE:
default:
{
if (op == ELOT_LT)
bReturn = (str1 < str2);
else if (op == ELOT_GT)
bReturn = (str1 > str2);
else if (op == ELOT_LTE)
bReturn = (str1 <= str2);
else if (op == ELOT_GTE)
bReturn = (str1 >= str2);
else
bReturn = (str1 == str2);
break;
}
}
return bReturn;
}
//////////////////////////////////////////////////////////////////////
// GetColumnCount()
// Parameters: None.// Action:
// Returns: The number of columns in the list control
//////////////////////////////////////////////////////////////////////
int CListVwEx::GetColumnCount() const
{
//Get the header control
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
//Return the number of items in it (i.e. the number of columns)
return pHeader->GetItemCount();
}
//////////////////////////////////////////////////////////////////////
// SwapRow()
// Parameters: nRow1 - row index (zero based)
// nRow2 - row index (zero based)
// Action: Swap nRow1 with nRow2
// Returns: TRUE if successful, else FALSE
//////////////////////////////////////////////////////////////////////
BOOL CListVwEx::SwapRow(int nRow1, int nRow2)
{
BOOL bOk = FALSE;
CListCtrl& ListCtrl = GetListCtrl();
int nMaxRows = ListCtrl.GetItemCount();
int nStart = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -