📄 reportctrl.cpp
字号:
}
CString CReportCtrl::GetHeaderText(int nColumn) const
{
if (!HasColumnHeader())
return _T("");
HDITEM hd;
TCHAR szBuffer[256] = _T("");
hd.mask = HDI_TEXT;
hd.pszText = szBuffer;
hd.cchTextMax = 255;
return GetHeaderCtrl()->GetItem(nColumn, &hd) ? hd.pszText : _T("");
}
BOOL CReportCtrl::SetHeaderText(int nColumn, LPCTSTR lpText)
{
if (!HasColumnHeader())
return FALSE;
LPTSTR psz = NULL;
if (lpText == NULL)
{
psz = new TCHAR[1];
*psz = _T('\0');
}
else
{
psz = _tcsdup(lpText);
}
HDITEM hd;
hd.mask = HDI_TEXT;
hd.pszText = psz;
hd.cchTextMax = _tcslen(psz);
const BOOL RES = CListCtrl::GetHeaderCtrl()->SetItem(nColumn, &hd);
delete [] psz;
return RES;
}
const CHeaderCtrl* CReportCtrl::GetHeaderCtrl() const
{
// Yes, CListCtrl already provides "GetHeaderCtrl", but not const.
// I desperately need a "const" version of "GetHeaderCtrl" because that's the
// only way to make "GetColumnCount" const, which, in turn, is being called by
// A LOT of const member functions. So if "GetHeaderCtrl" is not const, there will
// be almost no const member function at all in this class. Terrible.
return (const CHeaderCtrl*)(CWnd::FromHandle(ListView_GetHeader(GetSafeHwnd())));
}
void CReportCtrl::_FreeItemMemory(int nItem)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
if (p != NULL)
{
CListCtrl::SetItemData(nItem, 0);
delete p;
}
}
void CReportCtrl::_AllocItemMemory(int nItem)
{
ASSERT(_IsValidIndex(nItem));
const int COLS = GetColumnCount();
ASSERT(COLS > 0);
CItemData* pData = new CItemData;
pData->dwData = CListCtrl::GetItemData(nItem);
pData->aTextColors.SetSize(COLS);
pData->aBkColors.SetSize(COLS);
for (int i = 0; i < COLS; i++)
{
pData->aTextColors[i] = ::GetSysColor(COLOR_WINDOWTEXT);
pData->aBkColors[i] = ::GetSysColor(COLOR_WINDOW);
}
CListCtrl::SetItemData(nItem, (DWORD)pData);
}
void CReportCtrl::_UpdateColumn(int nColumn, BOOL bInsert)
{
const int ITEMS = GetItemCount();
for (int i = 0; i < ITEMS; i++)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(i));
ASSERT(p != NULL);
if (bInsert)
p->InsertColumn(nColumn);
else
p->DeleteColumn(nColumn);
}
}
BOOL CReportCtrl::SetItemData(int nItem, DWORD dwData)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
if (p == NULL)
return FALSE;
p->dwData = dwData;
return CListCtrl::SetItemData(nItem, (DWORD)p);
}
DWORD CReportCtrl::GetItemData(int nItem) const
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
return p == NULL ? 0 : p->dwData;
}
BOOL CReportCtrl::GetItem(LVITEM *pItem) const
{
const BOOL RES = CListCtrl::GetItem(pItem);
if (RES && (pItem->mask & LVIF_PARAM) != 0)
{
CItemData* p = (CItemData*)(pItem->lParam);
if (p != NULL)
pItem->lParam = p->dwData;
}
return RES;
}
BOOL CReportCtrl::SetItem(const LVITEM *pItem)
{
if (pItem == NULL)
return FALSE;
LVITEM li;
memcpy(&li, pItem, sizeof(LVITEM));
if ((li.mask & LVIF_PARAM) != 0)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(li.iItem));
if (p != NULL)
{
p->dwData = li.lParam;
li.lParam = (LPARAM)p;
}
}
return CListCtrl::SetItem(&li);
}
BOOL CReportCtrl::SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, int nImage, UINT nState, UINT nStateMask, LPARAM lParam)
{
if ((nMask & LVIF_PARAM) != 0)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
if (p != NULL)
{
p->dwData = lParam;
lParam = (LPARAM)p;
}
}
return CListCtrl::SetItem(nItem, nSubItem, nMask, lpszItem, nImage, nState, nStateMask, lParam);
}
void CReportCtrl::SetItemTextColor(int nItem, int nSubItem, COLORREF color, BOOL bRedraw)
{
if (color == COLOR_INVALID)
color = ::GetSysColor(COLOR_WINDOWTEXT);
const int ROWS = GetItemCount();
const int COLS = GetColumnCount();
BOOL bRowValid = nItem >= 0 && nItem < ROWS;
BOOL bColValid = nSubItem >= 0 && nSubItem < COLS;
if (bRowValid && bColValid)
{
// apply to individual grid
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
ASSERT(p != NULL);
p->aTextColors[nSubItem] = color;
}
else if (bRowValid && !bColValid)
{
// apply to whole row for the existing item
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
ASSERT(p != NULL);
for (int i = 0; i < COLS; i++)
p->aTextColors[i] = color;
}
else if (!bRowValid && bColValid)
{
// apply to whole column for all existing items
for (int i = 0; i < ROWS; i++)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(i));
ASSERT(p != NULL);
p->aTextColors[nSubItem] = color;
}
}
else
{
// apply to whole table for all existing items
for (int i = 0; i < ROWS; i++)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(i));
ASSERT(p != NULL);
for (int j = 0; j < COLS; j++)
p->aTextColors[j] = color;
}
}
if (bRedraw)
RedrawWindow();
}
void CReportCtrl::SetItemBkColor(int nItem, int nSubItem, COLORREF color, BOOL bRedraw)
{
if (color == COLOR_INVALID)
color = ::GetSysColor(COLOR_WINDOW);
const int ROWS = GetItemCount();
const int COLS = GetColumnCount();
BOOL bRowValid = nItem >= 0 && nItem < ROWS;
BOOL bColValid = nSubItem >= 0 && nSubItem < COLS;
if (bRowValid && bColValid)
{
// apply to individual grid
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
ASSERT(p != NULL);
p->aBkColors[nSubItem] = color;
}
else if (bRowValid && !bColValid)
{
// apply to whole row for the existing item
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
ASSERT(p != NULL);
for (int i = 0; i < COLS; i++)
p->aBkColors[i] = color;
}
else if (!bRowValid && bColValid)
{
// apply to whole column for all existing items
for (int i = 0; i < ROWS; i++)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(i));
ASSERT(p != NULL);
p->aBkColors[nSubItem] = color;
}
}
else
{
// apply to whole table for all existing items
for (int i = 0; i < ROWS; i++)
{
CItemData* p = (CItemData*)(CListCtrl::GetItemData(i));
ASSERT(p != NULL);
for (int j = 0; j < COLS; j++)
p->aBkColors[j] = color;
}
}
if (bRedraw)
RedrawWindow();
}
COLORREF CReportCtrl::GetItemTextColor(int nItem, int nSubItem) const
{
if (!_IsValidIndex(nItem) || nSubItem < 0 || nSubItem >= GetColumnCount())
return COLOR_INVALID;
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
ASSERT(p != NULL);
return p->aTextColors[nSubItem];
}
COLORREF CReportCtrl::GetItemBkColor(int nItem, int nSubItem) const
{
if (!_IsValidIndex(nItem) || nSubItem < 0 || nSubItem >= GetColumnCount())
return COLOR_INVALID;
CItemData* p = (CItemData*)(CListCtrl::GetItemData(nItem));
ASSERT(p != NULL);
return p->aBkColors[nSubItem];
}
BOOL CReportCtrl::_PartialSort(int nStart, int nEnd)
{
if (nStart >= nEnd || !_IsValidIndex(nStart) || !_IsValidIndex(nEnd))
return FALSE;
const int COUNT = nEnd - nStart + 1;
int i = 0;
int* aIndices = new int[COUNT];
for (i = 0; i < COUNT; i++)
aIndices[i] = nStart + i;
_QuickSortRecursive(aIndices, 0, COUNT - 1);
// rearrange items
const int COLS = GetColumnCount();
ROWINFO* aRows = new ROWINFO[COUNT];
for (i = 0; i < COUNT; i++)
{
int n = aIndices[i];
aRows[i].dwStates = GetItemStates(aIndices[i]);
aRows[i].dwData = CListCtrl::GetItemData(aIndices[i]);
aRows[i].aImages.SetSize(COLS);
aRows[i].aTexts.SetSize(COLS);
for (int j = 0; j < COLS; j++)
{
aRows[i].aImages[j] = GetItemImage(aIndices[i], j);
aRows[i].aTexts[j] = GetItemText(aIndices[i], j);
}
}
for (i = 0; i < COUNT; i++)
{
SetItemStates(nStart + i, aRows[i].dwStates);
CListCtrl::SetItemData(nStart + i, aRows[i].dwData);
for (int j = 0; j < COLS; j++)
{
SetItemImage(nStart + i, j, aRows[i].aImages[j]);
CListCtrl::SetItemText(nStart + i, j, aRows[i].aTexts[j]);
}
}
delete [] aRows;
delete [] aIndices;
return TRUE;
}
int CReportCtrl::_CompareItems(int nItem1, int nItem2)
{
const CString s1 = GetItemText(nItem1, m_nSortCol);
const CString s2 = GetItemText(nItem2, m_nSortCol);
DWORD dw1, dw2;
if(_ITEM_COMPARE_FUNCS::_IsHexNumber(s1, dw1) && _ITEM_COMPARE_FUNCS::_IsHexNumber(s2, dw2))
return _ITEM_COMPARE_FUNCS::_HexNumberCompare(dw1, dw2);
double f1, f2;
if(_ITEM_COMPARE_FUNCS::_IsDecNumber(s1, f1) && _ITEM_COMPARE_FUNCS::_IsDecNumber(s2, f2))
return _ITEM_COMPARE_FUNCS::_DecNumberCompare(f1, f2);
COleDateTime date1, date2;
if(_ITEM_COMPARE_FUNCS::_IsDate(s1, date1) && _ITEM_COMPARE_FUNCS::_IsDate(s2, date2))
return _ITEM_COMPARE_FUNCS::_DateCompare(date1, date2);
// plain text.
return s1.Compare(s2);
}
int CReportCtrl::_FindSeparator(int nStartAfter, int nColumn) const
{
if (m_pszSeparator == NULL)
return -1;
const int ITEMS = GetItemCount();
for (int i = nStartAfter + 1; i < ITEMS; i++)
{
if (GetItemText(i, nColumn) == m_pszSeparator)
return i;
}
return -1;
}
void CReportCtrl::_QuickSortRecursive(int* pArr, int nLow, int nHigh)
{
int i = nHigh, j = nLow;
int n = pArr[(nLow + nHigh) / 2];
do
{
if (m_bSortAscending)
{
while (_CompareItems(pArr[j], n) < 0)
j++;
while (_CompareItems(pArr[i], n) > 0)
i--;
}
else
{
while (_CompareItems(pArr[j], n) > 0)
j++;
while (_CompareItems(pArr[i], n) < 0)
i--;
}
if ( i >= j )
{
if ( i != j )
{
int nTemp = pArr[i];
pArr[i] = pArr[j];
pArr[j] = nTemp;
}
i--;
j++;
}
} while (j <= i);
if (nLow < i)
_QuickSortRecursive(pArr,nLow,i);
if (j < nHigh)
_QuickSortRecursive(pArr,j,nHigh);
}
void CReportCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
InvalidateProgressCtrls();
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CReportCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
InvalidateProgressCtrls();
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}
void CReportCtrl::InvalidateProgressCtrls()
{
int nFirst = GetTopIndex();
int nLast = nFirst + GetCountPerPage();
//Hide the other items.
int nCount = this->GetItemCount();
CProgressCtrl* pCtrl;
for(int i = 0; i < nFirst; i++)
{
pCtrl = (CProgressCtrl*)this->GetItemData(i);
if (NULL != pCtrl)
pCtrl->ShowWindow(SW_HIDE);
}
for(i = nLast; i < nCount; i++)
{
pCtrl = (CProgressCtrl*)this->GetItemData(i);
if (NULL != pCtrl)
pCtrl->ShowWindow(SW_HIDE);
}
//Invalidate
CRect rc(0,0,0,0);
CRect rcSubItem;
for(; nFirst < nLast; nFirst++)
{
GetSubItemRect(nFirst, 1, LVIR_BOUNDS, rcSubItem);
VERIFY( rc.UnionRect(rc, rcSubItem) );
}
InvalidateRect(rc);
// Using this method, the flicker seems better that above. But I am not sure why, and think it's non-effective.
// for(; nFirst < nLast; nFirst++)
// {
// GetSubItemRect(nFirst, 1, LVIR_BOUNDS, rcSubItem);
// InvalidateRect(rcSubItem);
// }
}
void CReportCtrl::CreateProgress(int IndexItem, int IndexSubItem)
{
if (IndexItem >= GetItemCount())
return;
CProgressEntry* ProgEntry = new CProgressEntry(IndexItem, IndexSubItem);
CRect ItemRect;
GetSubItemRect(IndexItem, ProgEntry->m_SubIndex, LVIR_BOUNDS, ItemRect);
int left = ItemRect.left;
int top = ItemRect.top;
int right = ItemRect.right;
int bottom = ItemRect.bottom;
(ProgEntry->m_Prog)->Create(PBS_SMOOTH | WS_CHILD | WS_VISIBLE, CRect(left, top, right, bottom), this, 0x1000 + IndexItem);
(ProgEntry->m_Prog)->SetRange(0, 100);
(ProgEntry->m_Prog)->SetPos(0);
m_ProgEntries[IndexItem] = ProgEntry;
}
void CReportCtrl::SetProgress(int IndexItem, int pos)
{
CProgressEntry* ProgEntry;
if (m_ProgEntries.Lookup(IndexItem, ProgEntry) == TRUE)
(ProgEntry->m_Prog)->SetPos(pos);
}
CReportCtrl::CProgressEntry::CProgressEntry(int Index, int SubIndex) :
m_Index(Index), m_SubIndex(SubIndex)
{
}
CReportCtrl::CProgressEntry::~CProgressEntry()
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -