📄 reportctrl.cpp
字号:
}
// swap item data
CListCtrl::SetItemData(nItem1, DATA2);
CListCtrl::SetItemData(nItem2, DATA1);
// restore states
SetItemStates(nItem1, STATES2);
SetItemStates(nItem2, STATES1);
return TRUE;
}
int CReportCtrl::MoveToTop(int nItem)
{
return MoveTo(nItem, -1);
}
int CReportCtrl::MoveToBottom(int nItem)
{
return MoveTo(nItem, INT_MAX);
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, TCHAR val)
{
return SetItemText(nItem, nSubItem, CString(val));
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, INT val)
{
return SetItemText(nItem, nSubItem, (LONG)val);
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, UINT val)
{
return SetItemText(nItem, nSubItem, (ULONG)val);
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, DOUBLE val, int nPrecision)
{
CString sText, sFmt;
if (nPrecision >= 0)
{
sFmt.Format(_T("%%.%df"), nPrecision);
sText.Format(sFmt, val);
}
else
{
sText.Format(_T("%f"), val);
sText.TrimRight(_T('0'));
sText.TrimRight(_T('.'));
}
return SetItemText(nItem, nSubItem, sText);
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, const COleDateTime &dateTime, DWORD dwFlags)
{
return SetItemText(nItem, nSubItem, dateTime.GetStatus() == COleDateTime::valid ? dateTime.Format(dwFlags) : _T(""));
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, LONG val)
{
CString str;
str.Format(_T("%d"), val);
return SetItemText(nItem, nSubItem, str);
}
BOOL CReportCtrl::SetItemText(int nItem, int nSubItem, ULONG val)
{
CString str;
str.Format(_T("%u"), val);
return SetItemText(nItem, nSubItem, str);
}
BOOL CReportCtrl::DeleteAllColumns()
{
while (GetColumnCount() > 0)
DeleteColumn(0);
return TRUE;
}
LPCTSTR CReportCtrl::GetSortSeparator() const
{
return m_pszSeparator;
}
void CReportCtrl::SetSortSeparator(LPCTSTR lpSortSeparator)
{
if (m_pszSeparator != NULL)
{
delete [] m_pszSeparator;
m_pszSeparator = NULL;
}
if (lpSortSeparator != NULL)
m_pszSeparator = _tcsdup(lpSortSeparator);
}
int CReportCtrl::InsertItemEx(int nItem, LPCTSTR lpText, ...)
{
EndEdit(TRUE);
_UnsetSortedColumn();
const int IDX = CListCtrl::InsertItem(nItem, lpText);
if (IDX < 0)
return -1;
va_list list;
va_start(list, lpText);
for(int iColumn = 1; iColumn < GetColumnCount(); iColumn++)
{
LPCTSTR lp = va_arg(list, LPCTSTR);
if (lp != NULL)
{
CListCtrl::SetItemText(IDX, iColumn, lp);
}
else
{
break;
}
}
va_end(list);
if (IDX >= 0)
_AllocItemMemory(IDX);
return IDX;
}
BOOL CReportCtrl::_IsEditVisible() const
{
return m_bAllowEdit
&& m_ptEditting.x >= 0 && m_ptEditting.x < CListCtrl::GetItemCount()
&& m_ptEditting.y >= 0 && m_ptEditting.y < GetColumnCount();
}
void CReportCtrl::SetEditable(BOOL bSet)
{
if (!bSet)
EndEdit(TRUE);
m_bAllowEdit = bSet;
}
BOOL CReportCtrl::IsEditable() const
{
return m_bAllowEdit;
}
BOOL CReportCtrl::_ItemCheckMonitor(int nIndex, BOOL bBefore, BOOL bAfter, UINT nMsg)
{
if (!_IsValidIndex(nIndex)
|| m_nChkStyle == RC_CHKBOX_NONE
|| (bBefore && bAfter)
|| (!bBefore && !bAfter))
{
return FALSE;
}
if (m_nChkStyle == RC_CHKBOX_SINGLE)
{
// Only one item can be checked
if (!bBefore && bAfter)
{
SetAllItemStates(RC_ITEM_CHECKED, RC_ITEM_UNCHECKED); // uncheck all
SetItemStates(nIndex, RC_ITEM_CHECKED);
}
}
else if (m_nChkStyle == RC_CHKBOX_DISABLED)
{
// Cannot change the item checked/unchecked states by mouse clicks
SetItemStates(nIndex, bBefore ? RC_ITEM_CHECKED : RC_ITEM_UNCHECKED);
return TRUE;
}
SetAllItemStates(RC_ITEM_SELECTED, RC_ITEM_UNSELECTED); // unselect all
SetItemStates(nIndex, RC_ITEM_SELECTED | RC_ITEM_FOCUSED);
GetParent()->SendMessage(WM_ON_CHKBOX, (WPARAM)nIndex, (LPARAM)nMsg);
return TRUE;
}
int CReportCtrl::GetCheckboxStyle() const
{
return m_nChkStyle;
}
void CReportCtrl::_StringSplit(const CString &str, CStringArray &arr, TCHAR chDelimitior)
{
int nStart = 0, nEnd = 0;
arr.RemoveAll();
while (nEnd < str.GetLength())
{
// determine the paragraph ("xxx,xxx,xxx;")
nEnd = str.Find(chDelimitior, nStart);
if( nEnd == -1 )
{
// reached the end of string
nEnd = str.GetLength();
}
CString s = str.Mid(nStart, nEnd - nStart);
if (!s.IsEmpty())
arr.Add(s);
nStart = nEnd + 1;
}
}
BOOL CReportCtrl::SetSortable(BOOL bSet)
{
if (!HasColumnHeader())
return FALSE;
LONG lStyle = ::GetWindowLong(GetHeaderCtrl()->GetSafeHwnd(), GWL_STYLE);
if (bSet)
{
lStyle |= HDS_BUTTONS;
}
else
{
lStyle &= ~HDS_BUTTONS;
_UnsetSortedColumn();
}
::SetWindowLong(GetHeaderCtrl()->GetSafeHwnd(), GWL_STYLE, lStyle);
CListCtrl::GetHeaderCtrl()->RedrawWindow();
return TRUE;
}
DWORD CReportCtrl::SetExtendedStyle(DWORD dwNewStyle)
{
dwNewStyle &= ~MUST_NOT_EX_STYLE;
dwNewStyle |= MUST_EX_STYLE;
return CListCtrl::SetExtendedStyle(dwNewStyle);
}
BOOL CReportCtrl::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
cs.style &= ~MUST_NOT_STYLE;
cs.style |= MUST_STYLE;
return CListCtrl::PreCreateWindow(cs);
}
BOOL CReportCtrl::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if (pMsg->message == WM_KEYDOWN)
{
if (!_IsEditVisible())
{
// disable user from check/uncheck the checkboxes using space key
// things get nasty if the user is HOLDING the space bar down
if (pMsg->wParam == VK_SPACE)
return TRUE;
}
else
{
POINT pt = m_ptEditting;
switch (pMsg->wParam)
{
case VK_ESCAPE: // Cancel edit
EndEdit(FALSE);
return TRUE;
case VK_RETURN: // Commit edit
EndEdit(TRUE);
return TRUE;
case VK_TAB: // switch edit sub items
if (pt.y == GetColumnCount() - 1)
pt.y = 0;
else
pt.y++;
EndEdit(TRUE);
StartEdit(pt.x, pt.y);
return TRUE;
case VK_UP: // edit upper item
if (pt.x > 0)
{
pt.x--;
EndEdit(TRUE);
StartEdit(pt.x, pt.y);
EnsureVisible(pt.x, FALSE);
return TRUE;
}
break;
case VK_DOWN: // edit lower item
if (pt.x < CListCtrl::GetItemCount() - 1)
{
pt.x++;
EndEdit(TRUE);
StartEdit(pt.x, pt.y);
EnsureVisible(pt.x, FALSE);
return TRUE;
}
break;
default:
break;
}
}
}
return CListCtrl::PreTranslateMessage(pMsg);
}
CEdit* CReportCtrl::GetEditControl()
{
return m_pWndEdit;
}
BOOL CReportCtrl::Create(CWnd* pParentWnd, UINT nID, LPCRECT lpRect, DWORD dwStyle)
{
// TODO: Add your specialized code here and/or call the base class
ASSERT(pParentWnd != NULL);
dwStyle &= ~MUST_NOT_STYLE;
dwStyle |= MUST_STYLE;
CRect rect;
if (lpRect == NULL)
pParentWnd->GetClientRect(&rect);
else
rect = *lpRect;
return CListCtrl::Create(dwStyle, rect, pParentWnd, nID);
}
void CReportCtrl::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
LONG lStyle = ::GetWindowLong(GetSafeHwnd(), GWL_STYLE);
lStyle &= ~MUST_NOT_STYLE;
lStyle |= MUST_STYLE;
::SetWindowLong(GetSafeHwnd(), GWL_STYLE, lStyle);
SetExtendedStyle(0);
ASSERT(GetHeaderCtrl() != NULL);
CListCtrl::PreSubclassWindow();
}
BOOL CReportCtrl::IsSortable() const
{
if (!HasColumnHeader())
return FALSE;
LONG lStyle = ::GetWindowLong(GetHeaderCtrl()->GetSafeHwnd(), GWL_STYLE);
return (lStyle & HDS_BUTTONS) != 0;
}
BOOL CReportCtrl::HasColumnHeader() const
{
return (GetStyle() & LVS_NOCOLUMNHEADER) == 0;
}
void CReportCtrl::ResizeToFitParent()
{
// resize the list ctrl to fit parent client area
if (GetSafeHwnd() != NULL)
{
CRect rect;
GetParent()->GetClientRect(&rect);
MoveWindow(&rect);
}
}
BOOL CReportCtrl::ModifyStyleEx(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
dwRemove &= ~MUST_EX_STYLE;
dwRemove |= MUST_NOT_EX_STYLE;
dwAdd &= ~MUST_NOT_EX_STYLE;
dwAdd |= MUST_EX_STYLE;
return CListCtrl::ModifyStyleEx(dwRemove, dwAdd, nFlags);
}
BOOL CReportCtrl::ModifyStyle(DWORD dwRemove, DWORD dwAdd, UINT nFlags)
{
dwRemove &= ~MUST_STYLE;
dwRemove |= MUST_NOT_STYLE;
dwAdd &= ~MUST_NOT_STYLE;
dwAdd |= MUST_STYLE;
return CListCtrl::ModifyStyle(dwRemove, dwAdd, nFlags);
}
void CReportCtrl::_MouseClkMonitor(UINT nMsg, UINT nFlags, CPoint point, BOOL bTriggerEdit)
{
LVHITTESTINFO hti;
hti.pt = point;
const int IDX = SubItemHitTest(&hti);
const BOOL BEFORE = CListCtrl::GetCheck(IDX) > 0;
const BOOL WAS_EDIT = _IsEditVisible();
EndEdit(TRUE);
const BOOL WASACTIVE = bTriggerEdit ? ExamItemStates(IDX, RC_ITEM_FOCUSED | RC_ITEM_SELECTED) : FALSE;
switch (nMsg)
{
case WM_LBUTTONDOWN:
CListCtrl::OnLButtonDown(nFlags, point);
break;
case WM_LBUTTONDBLCLK:
CListCtrl::OnLButtonDblClk(nFlags, point);
break;
case WM_MBUTTONDOWN:
CListCtrl::OnMButtonDown(nFlags, point);
break;
case WM_MBUTTONDBLCLK:
CListCtrl::OnMButtonDblClk(nFlags, point);
break;
case WM_RBUTTONDOWN:
CListCtrl::OnRButtonDown(nFlags, point);
break;
case WM_RBUTTONDBLCLK:
CListCtrl::OnRButtonDblClk(nFlags, point);
break;
default:
break;
}
const BOOL STATSCHANGED = _ItemCheckMonitor(IDX, BEFORE, CListCtrl::GetCheck(IDX) > 0, nMsg);
if (bTriggerEdit && m_bAllowEdit && !STATSCHANGED && !WAS_EDIT && WASACTIVE)
StartEdit(IDX, hti.iSubItem);
}
BOOL CReportCtrl::SetItemImage(int nItem, int nSubItem, int nImageIndex)
{
return CListCtrl::SetItem(nItem, nSubItem, LVIF_IMAGE, NULL, nImageIndex, 0, 0, 0);
}
int CReportCtrl::GetItemImage(int nItem, int nSubItem) const
{
LVITEM lvi;
lvi.iItem = nItem;
lvi.iSubItem = nSubItem;
lvi.mask = LVIF_IMAGE;
return CListCtrl::GetItem(&lvi) ? lvi.iImage : -1;
}
CImageList* CReportCtrl::SetImageList(CImageList *pImageList)
{
return CListCtrl::SetImageList(pImageList, LVSIL_SMALL);
}
CImageList* CReportCtrl::GetImageList() const
{
return CListCtrl::GetImageList(LVSIL_SMALL);
}
CImageList* CReportCtrl::SetImageList(UINT nBitmapID, COLORREF crMask)
{
m_imgList.DeleteImageList();
m_imgList.Create(nBitmapID, 16, 4, crMask);
return CListCtrl::SetImageList(&m_imgList, LVSIL_SMALL);
}
BOOL CReportCtrl::StartEdit(int nItem, int nSubItem)
{
// Get the grid width and height
if (!m_bAllowEdit || !_IsValidIndex(nItem) || nSubItem < 0 || nSubItem >= GetColumnCount())
return FALSE;
if (m_ptEditting.x == nItem && m_ptEditting.y == nSubItem)
return TRUE;
EndEdit(TRUE);
m_ptEditting.x = nItem;
m_ptEditting.y = nSubItem;
SetAllItemStates(RC_ITEM_SELECTED, RC_ITEM_UNSELECTED); // unselect all
SetItemStates(m_ptEditting.x, RC_ITEM_SELECTED | RC_ITEM_FOCUSED);
// determine editbox font and alignment
const DWORD FMT = _GetHeaderTextFormat(nSubItem);
if (FMT != m_dwPrevEditFmt)
{
m_dwPrevEditFmt = FMT;
// Funny thing:
// Changing CEdit style among ES_LEFT, ES_CENTER, ES_RIGHT at runtime works
// sometimes and fails other times. It just cannot guarantee to be succeed.
// So I decided to destroy and recreate the CEdit every time when the text
// format changes.
if (m_pWndEdit->GetSafeHwnd() != NULL)
m_pWndEdit->DestroyWindow();
if (!m_pWndEdit->Create(ES_AUTOHSCROLL | ES_NOHIDESEL | WS_CHILD | WS_BORDER | FMT, CRect(0, 0, 1, 1), this, 0))
return FALSE;
}
else
{
if (m_pWndEdit->GetSafeHwnd() == NULL
&& !m_pWndEdit->Create(ES_AUTOHSCROLL | ES_NOHIDESEL | WS_CHILD | WS_BORDER | FMT, CRect(0, 0, 1, 1), this, 0))
{
return FALSE;
}
}
m_pWndEdit->SetFont(GetFont());
CRect rcEdit;
ListView_GetSubItemRect(GetSafeHwnd(), m_ptEditting.x, m_ptEditting.y, LVIR_LABEL, &rcEdit);
if (m_ptEditting.y > 0 && GetImageList() != NULL && GetItemImage(m_ptEditting.x, m_ptEditting.y) >= 0)
rcEdit.DeflateRect(16, 0, 0, 0);
// Move the editbox to that grid, obtain text from the grid, display the
// editbox, and, finally, highlights all text in the editbox and set the
// windows focus to the editbox.
m_pWndEdit->MoveWindow(&rcEdit);
m_pWndEdit->SetWindowText(GetItemText(m_ptEditting.x, m_ptEditting.y));
m_pWndEdit->ShowWindow(SW_SHOW);
m_pWndEdit->SetSel(0, -1);
m_pWndEdit->SetFocus();
return TRUE;
}
BOOL CReportCtrl::EndEdit(BOOL bCommit)
{
if (!_IsEditVisible())
return FALSE;
CString str;
m_pWndEdit->GetWindowText(str);
BOOL bChanged = bCommit && str.Compare(GetItemText(m_ptEditting.x, m_ptEditting.y)) != 0;
if (bChanged)
{
// update the list item
CListCtrl::SetItemText(m_ptEditting.x, m_ptEditting.y, str);
_UnsetSortedColumn();
GetParent()->SendMessage(WM_EDIT_COMMITTED, (WPARAM)m_ptEditting.x, (LPARAM)m_ptEditting.y);
}
m_pWndEdit->ShowWindow(SW_HIDE);
m_ptEditting.x = -1;
m_ptEditting.y = -1;
return bChanged;
}
BOOL CReportCtrl::SetHeaderImage(int nColumn, int nImageIndex, BOOL bLeftSide)
{
if (GetHeaderCtrl()->GetImageList() == NULL)
CListCtrl::GetHeaderCtrl()->SetImageList(GetImageList());
HDITEM hi;
::memset(&hi, 0, sizeof(HDITEM));
hi.mask = HDI_FORMAT;
if (!GetHeaderCtrl()->GetItem(nColumn, &hi))
return FALSE;
hi.mask |= HDI_IMAGE;
hi.fmt |= HDF_IMAGE;
if (!bLeftSide)
hi.fmt |= HDF_BITMAP_ON_RIGHT; // draw the image on right side of text
hi.iImage = nImageIndex;
return CListCtrl::GetHeaderCtrl()->SetItem(nColumn, &hi);
}
int CReportCtrl::GetSortedColumn() const
{
return m_nSortCol;
}
BOOL CReportCtrl::IsSortAscending() const
{
return m_bSortAscending;
}
void CReportCtrl::_UnsetSortedColumn()
{
m_nSortCol = -1;
m_bSortAscending = TRUE;
}
DWORD CReportCtrl::_GetHeaderTextFormat(int nColumn) const
{
if (!HasColumnHeader())
return ES_LEFT;
HDITEM hd;
hd.mask = HDI_FORMAT;
if (!GetHeaderCtrl()->GetItem(nColumn, &hd))
return ES_LEFT;
if (hd.fmt & HDF_CENTER)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -