#include "stdafx.h" #include "PropertyGridInplaceEdit.h" #include "PropertyGridInplaceButton.h" #include "PropertyGridInplaceList.h" #include "PropertyGridItem.h" #include "PropertyGridExtItemDate.h" #include "PropertyGrid.h" ///////////////////////////////////////////////////////////////////////////// // CInplaceDateEdit ///////////////////////////////////////////////////////////////////////////// CInplaceDateEdit::CInplaceDateEdit() : m_pItem(0) , m_pGrid(0) { } CInplaceDateEdit::~CInplaceDateEdit() { } BEGIN_MESSAGE_MAP(CInplaceDateEdit, CDateEdit) //{{AFX_MSG_MAP(CInplaceDateEdit) ON_WM_CTLCOLOR_REFLECT() ON_CONTROL_REFLECT(EN_KILLFOCUS, OnEnKillfocus) ON_CONTROL_REFLECT(EN_SETFOCUS, OnEnSetfocus) ON_WM_GETDLGCODE() ON_WM_KEYDOWN() ON_WM_CHAR() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CInplaceDateEdit::SetValue(CString strValue) { m_strValue = strValue; } void CInplaceDateEdit::Create(CPropertyGridExtItemDate* pItem, CRect rect) { ASSERT(pItem && pItem->GetGrid()); m_pGrid = pItem->GetGrid(); m_pItem = pItem; if (!m_hWnd) { CDateEdit::Create(WS_CHILD|ES_AUTOHSCROLL, rect, m_pGrid, 0); } SetWindowText(m_strValue); SetWindowPos(0, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER|SWP_SHOWWINDOW); } HBRUSH CInplaceDateEdit::CtlColor(CDC* pDC, UINT /*nCtlColor*/) { pDC->SetTextColor(GetStyle() & ES_READONLY ? GetSysColor(COLOR_GRAYTEXT): ((CPropertyGridView*)m_pGrid)->m_clrFore); COLORREF clr = ((CPropertyGridView*)m_pGrid)->m_clrBack; if (clr != m_clrBack || !m_brBack.GetSafeHandle()) { m_brBack.DeleteObject(); m_brBack.CreateSolidBrush(clr); m_clrBack = clr; } pDC->SetBkColor(m_clrBack); return m_brBack; } void CInplaceDateEdit::OnEnSetfocus() { ASSERT(m_pItem && m_pGrid); m_pGrid->Invalidate(FALSE); } void CInplaceDateEdit::OnEnKillfocus() { if (m_pItem) { m_pItem->OnValidateEdit(); m_pGrid->Invalidate(FALSE); } } UINT CInplaceDateEdit::OnGetDlgCode() { return DLGC_WANTALLKEYS; } void CInplaceDateEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_TAB) return; if (nChar == VK_ESCAPE || nChar == VK_RETURN) { m_pGrid->SetFocus(); return; } CDateEdit::OnChar(nChar, nRepCnt, nFlags); } void CInplaceDateEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_TAB) { CWnd* pParent = m_pGrid->GetParent(); if (!pParent || !pParent->GetParent()) { ASSERT(FALSE); return; } CWnd* pWndNext = pParent->GetParent()->GetNextDlgTabItem( pParent, ::GetKeyState(VK_SHIFT) < 0 ); if (pWndNext != NULL) { pWndNext->SetFocus(); } return; } else if (nChar == VK_ESCAPE) { SetWindowText(m_strValue); return; } else if (nChar == VK_RETURN) { return; } CDateEdit::OnKeyDown(nChar, nRepCnt, nFlags); } void CInplaceDateEdit::DestroyItem() { // reset variables to defaults. m_pItem = NULL; m_pGrid = NULL; m_strValue.Empty(); m_brBack.DeleteObject(); // destroy the window. DestroyWindow( ); } ///////////////////////////////////////////////////////////////////////////// // CInplaceMonthCal ///////////////////////////////////////////////////////////////////////////// CInplaceMonthCal::CInplaceMonthCal() : m_pItem(0) { } CInplaceMonthCal::~CInplaceMonthCal() { } BEGIN_MESSAGE_MAP(CInplaceMonthCal, CMonthCalCtrl) //{{AFX_MSG_MAP(CInplaceMonthCal) ON_NOTIFY_REFLECT(MCN_SELECT, OnSelect) ON_WM_KEYDOWN() ON_WM_KILLFOCUS() ON_WM_MOUSEACTIVATE() //}}AFX_MSG_MAP END_MESSAGE_MAP() void CInplaceMonthCal::Create(CPropertyGridExtItemDate* pItem) { ASSERT(pItem && pItem->GetGrid()); m_pItem = pItem; CWnd* pGrid = m_pItem->GetGrid(); // 创建日历控件 if (m_hWnd == NULL) { CreateEx(0, MONTHCAL_CLASS, NULL, WS_CHILD | WS_BORDER, CRect(0, 0, 1, 1), pGrid, 0); SetOwner(pGrid); } // 计算日历控件的位置 CRect rcItem= m_pItem->GetItemRect(); pGrid->ClientToScreen(&rcItem); CRect rect; GetMinReqRect(&rect); rect.SetRect(rcItem.right - rect.Width(), rcItem.bottom, rcItem.right, rcItem.bottom + rect.Height()); CRect rcWork; ::SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcWork, 0); if (rect.bottom > rcWork.bottom) rect.OffsetRect(0, - rect.Height() - rcItem.Height() - 1); if (rect.top < rcWork.top) rect.OffsetRect(0, rcWork.top - rect.top); if (rect.left < rcWork.left) rect.OffsetRect(rcWork.left - rect.left, 0); if (rect.right > rcWork.right) rect.OffsetRect(rcWork.right - rect.right, 0); // 以子窗口方式创建内置日历控件,然后再执行下面这段代码,内置日历 // 控件将以弹出窗口方式显示,并得到输入焦点,但当前窗口保持不变 SetFocus(); ::SetWindowLong(m_hWnd, GWL_HWNDPARENT, NULL); ModifyStyle(WS_CHILD, WS_POPUP); ::SetWindowLong(m_hWnd, GWL_HWNDPARENT, (LONG)pGrid->m_hWnd); SetWindowPos(0, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER|SWP_SHOWWINDOW|SWP_NOACTIVATE); // 要在显示日历控件后再选择日期,因为属性项处于编辑状态时, // 编辑控件在激活日历控件时失去焦点,从而更新属性值 SetCurSel( m_pItem->GetDate() ); CPGMouseMonitor::SetupHook(this); } void CInplaceMonthCal::OnSelect(NMHDR* pNMHDR, LRESULT* pResult) { // 更新属性项 Apply(); *pResult = 0; } void CInplaceMonthCal::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { switch (nChar) { case VK_RETURN: Apply(); break; case VK_ESCAPE: Cancel(); } CMonthCalCtrl::OnKeyDown(nChar, nRepCnt, nFlags); } void CInplaceMonthCal::OnKillFocus(CWnd* pNewWnd) { CMonthCalCtrl::OnKillFocus(pNewWnd); // 如果不是内置控件导致的事件,则删除窗口 if (!IsChild(pNewWnd)) { CPGMouseMonitor::SetupHook(NULL); DestroyItem(); } } int CInplaceMonthCal::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) { // 用鼠标点击内置日历控件时,不改变当前窗口 return MA_NOACTIVATE; } void CInplaceMonthCal::Apply() { SYSTEMTIME st; GetCurSel(&st); COleDateTime dt; dt.SetDate(st.wYear, st.wMonth, st.wDay); CString str = CDateEdit::DateToString(dt); if (str != m_pItem->GetValue()) m_pItem->OnValueChanged(str); GetOwner()->SetFocus(); } void CInplaceMonthCal::Cancel() { GetOwner()->SetFocus(); } void CInplaceMonthCal::DestroyItem() { m_pItem = NULL; DestroyWindow( ); } ///////////////////////////////////////////////////////////////////////////// // CPropertyGridExtItemDate ///////////////////////////////////////////////////////////////////////////// CPropertyGridExtItemDate::CPropertyGridExtItemDate(CString strCaption, COleDateTime dtDate /* = 当前日期 */ ) : CPropertyGridItem(strCaption) { m_wndDateEdit.m_pItem = this; m_wndMonthCal.m_pItem = this; m_pBindDate = NULL; m_nFlags = pgitemHasEdit | pgitemHasComboButton; SetDate(dtDate); } CPropertyGridExtItemDate::CPropertyGridExtItemDate(UINT nID, COleDateTime dtDate /* = 当前日期 */ ) : CPropertyGridItem(nID) { m_wndDateEdit.m_pItem = this; m_wndMonthCal.m_pItem = this; m_pBindDate = NULL; m_nFlags = pgitemHasEdit | pgitemHasComboButton; SetDate(dtDate); } CPropertyGridExtItemDate::~CPropertyGridExtItemDate() { m_wndDateEdit.DestroyItem(); m_wndMonthCal.DestroyItem(); } void CPropertyGridExtItemDate::SetDate(COleDateTime dtDate) { // 如果参数dtDate不合法,则使用缺省构造函数产生的日期做为属性值 if (dtDate.GetStatus() == COleDateTime::valid) m_dtDate = dtDate; else m_dtDate = COleDateTime(); CPropertyGridItem::SetValue( CDateEdit::DateToString(m_dtDate) ); if (m_pBindDate) *m_pBindDate = m_dtDate; } COleDateTime CPropertyGridExtItemDate::GetDate() { return m_dtDate; } void CPropertyGridExtItemDate::SetValue(CString strValue) { SetDate(CDateEdit::StringToOleDateTime(strValue)); } void CPropertyGridExtItemDate::OnValidateEdit() { if (m_wndDateEdit.GetSafeHwnd()) { m_wndDateEdit.ShowWindow(SW_HIDE); CString strValue; m_wndDateEdit.GetWindowText(strValue); if (m_strValue != strValue) { // 如果输入的日期合法,则更新属性值,否则发出错误提示音 COleDateTime dt= CDateEdit::StringToOleDateTime(strValue); if (dt.GetStatus() == COleDateTime::valid) { OnValueChanged(strValue); m_pGrid->Invalidate(FALSE); } else { ::MessageBeep( (UINT)-1 ); // 内置编辑控件恢复原来的属性值 SetEditText(m_strValue); } } } } void CPropertyGridExtItemDate::SetEditText(CString str) { if (!m_pGrid) return; if (m_wndDateEdit.GetSafeHwnd()) m_wndDateEdit.SetWindowText(str); } void CPropertyGridExtItemDate::OnSelect() { ASSERT(m_bVisible); if (!m_bReadOnly && (m_nFlags & (pgitemHasComboButton | pgitemHasExpandButton))) { GetInplaceButton().Create(this, GetItemRect()); } if (m_nFlags & pgitemHasEdit) { m_wndDateEdit.SetValue(m_strValue); m_wndDateEdit.Create(this, GetValueRect()); m_wndDateEdit.SetReadOnly(m_bReadOnly); m_wndDateEdit.SetFont(GetGrid()->GetFont()); m_wndDateEdit.SetMargins(3, 0); } } BOOL CPropertyGridExtItemDate::OnChar(UINT nChar) { if (m_nFlags & pgitemHasEdit) { OnSelect(); m_wndDateEdit.SetFocus(); m_wndDateEdit.MaskSelectAll(); if (nChar != VK_TAB) m_wndDateEdit.SendMessage(WM_CHAR, nChar); return TRUE; } return FALSE; } void CPropertyGridExtItemDate::OnLButtonDblClk() { if (HasChilds()) { if(m_bExpanded) Collapse(); else Expand(); } else { OnSelect(); if (m_nFlags & pgitemHasEdit) { m_wndDateEdit.SetFocus(); m_wndDateEdit.MaskSelectAll(); } } } void CPropertyGridExtItemDate::BindToDate(COleDateTime* pBindDate) { m_pBindDate = pBindDate; if (m_pBindDate) SetDate(*m_pBindDate); } void CPropertyGridExtItemDate::OnInplaceButtonDown() { m_wndMonthCal.Create(this); }