CDateTimeUI类源码分析

时间:2022-06-03 23:59:50

CDateTimeUI是duilib里选择日期的控件,继承于CLabelUI控件,用于记录已经选择的日期,选择控件则是调用win32的日期选择控件。

CDateTimeUI包含两个类,一个是CDateTimeUI,另一个是CDateTimeWnd。

CDateTimeWnd是创建win32日期控件的类,父类是CWindowWnd。

实现代码如下:

#define DT_NONE   0
#define DT_UPDATE 1
#define DT_DELETE 2
#define DT_KEEP 3

class CDateTimeWnd : public CWindowWnd
{
public:
CDateTimeWnd();

void Init(CDateTimeUI* pOwner);
RECT CalPos();

LPCTSTR GetWindowClassName()
const;
LPCTSTR GetSuperClassName()
const;
void OnFinalMessage(HWND hWnd);

LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
& bHandled);

protected:
CDateTimeUI
* m_pOwner;
HBRUSH m_hBkBrush;
bool m_bInit;
};

CDateTimeWnd::CDateTimeWnd() : m_pOwner(NULL), m_hBkBrush(NULL), m_bInit(
false)
{
}

void CDateTimeWnd::Init(CDateTimeUI* pOwner)
{
m_pOwner
= pOwner;
m_pOwner
->m_nDTUpdateFlag = DT_NONE;

if (m_hWnd == NULL)
{
RECT rcPos
= CalPos();
UINT uStyle
= WS_CHILD;
Create(m_pOwner
->GetManager()->GetPaintWindow(), NULL, uStyle, 0, rcPos);
SetWindowFont(m_hWnd, m_pOwner
->GetManager()->GetFontInfo(m_pOwner->GetFont())->hFont, TRUE);
}

if (m_pOwner->GetText().IsEmpty())
::GetLocalTime(
&m_pOwner->m_sysTime);

::SendMessage(m_hWnd, DTM_SETSYSTEMTIME,
0, (LPARAM)&m_pOwner->m_sysTime);
::ShowWindow(m_hWnd, SW_SHOWNOACTIVATE);
::SetFocus(m_hWnd);

m_bInit
= true;
}

//获取控件应该显示的位置,一般是父窗口的位置,如果父窗口不显示则当前win32日期控件也不显示
RECT CDateTimeWnd::CalPos()
{
CDuiRect rcPos
= m_pOwner->GetPos();

CControlUI
* pParent = m_pOwner;
RECT rcParent;
while( pParent = pParent->GetParent() ) {
if( !pParent->IsVisible() ) {
rcPos.left
= rcPos.top = rcPos.right = rcPos.bottom = 0;
break;
}
rcParent
= pParent->GetPos();
if( !::IntersectRect(&rcPos, &rcPos, &rcParent) ) {
rcPos.left
= rcPos.top = rcPos.right = rcPos.bottom = 0;
break;
}
}
return rcPos;
}

LPCTSTR CDateTimeWnd::GetWindowClassName()
const
{
return _T("DateTimeWnd");
}

//设置控件类名
LPCTSTR CDateTimeWnd::GetSuperClassName() const
{
return DATETIMEPICK_CLASS;
}

void CDateTimeWnd::OnFinalMessage(HWND /*hWnd*/)
{
// Clear reference and die
if( m_hBkBrush != NULL ) ::DeleteObject(m_hBkBrush);
m_pOwner
->m_pWindow = NULL;
delete this;
}

LRESULT CDateTimeWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRes
= 0;
BOOL bHandled
= TRUE;

if( uMsg == WM_NOTIFY)
{
::SetFocus(m_hWnd);
}
if( uMsg == WM_KILLFOCUS )
{
//失去焦点就关闭当前win32日期控件
POINT pt;
::GetCursorPos(
&pt);
RECT rcWnd;
::GetWindowRect(m_hWnd,
&rcWnd);
if( !( pt.x >= rcWnd.left && pt.x <= rcWnd.right )||
!( pt.x >= rcWnd.top && pt.x <= rcWnd.bottom ))
{
lRes
= OnKillFocus(uMsg,wParam, lParam,bHandled);
}
}
else if (uMsg == WM_KEYUP && (wParam == VK_ESCAPE))
{
//esc键按下则不保存当前已选择的日期
LRESULT lRes = ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
m_pOwner
->m_nDTUpdateFlag = DT_KEEP;
PostMessage(WM_CLOSE);
return lRes;
}
else if (uMsg == WM_KEYUP && (wParam == VK_RETURN))
{
//回车键按下就当做失去焦点处理
PostMessage(WM_KILLFOCUS);
return 0;
}
else bHandled = FALSE;
if( !bHandled ) return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
return lRes;
}

LRESULT CDateTimeWnd::OnKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL
& bHandled)
{
LRESULT lRes
= ::DefWindowProc(m_hWnd, uMsg, wParam, lParam);
if (m_pOwner->m_nDTUpdateFlag == DT_NONE)
{
::SendMessage(m_hWnd, DTM_GETSYSTEMTIME,
0, (LPARAM)&m_pOwner->m_sysTime);
m_pOwner
->m_nDTUpdateFlag = DT_UPDATE;
m_pOwner
->UpdateText();
}
PostMessage(WM_CLOSE);
return lRes;
}

此类Init代码用来显示win32日期控件,创建一个大小和CDateTimeUI大小一样的控件显示在CDateTimeUI上面。当此控件失去焦点后将选择的日期显示在CDateTimeUI控件上。

CDateTimeUI控件继承于CLabelUI。

头文件:

/// 时间选择控件
class UILIB_API CDateTimeUI : public CLabelUI
{
friend
class CDateTimeWnd;
public:
CDateTimeUI();
LPCTSTR GetClass()
const;
LPVOID GetInterface(LPCTSTR pstrName);

SYSTEMTIME
& GetTime();
void SetTime(SYSTEMTIME* pst);

void SetReadOnly(bool bReadOnly);
bool IsReadOnly() const;

void UpdateText();

void DoEvent(TEventUI& event);

protected:
SYSTEMTIME m_sysTime;
int m_nDTUpdateFlag;
bool m_bReadOnly;

CDateTimeWnd
* m_pWindow;
};

源文件:

//////////////////////////////////////////////////////////////////////////
//
CDateTimeUI::CDateTimeUI()
{
::GetLocalTime(
&m_sysTime);
m_bReadOnly
= false;
m_pWindow
= NULL;
m_nDTUpdateFlag
=DT_UPDATE;
UpdateText();
m_nDTUpdateFlag
= DT_NONE;
}

LPCTSTR CDateTimeUI::GetClass()
const
{
return _T("DateTimeUI");
}

LPVOID CDateTimeUI::GetInterface(LPCTSTR pstrName)
{
if( _tcscmp(pstrName, DUI_CTR_DATETIME) == 0 ) return static_cast<CDateTimeUI*>(this);
return CLabelUI::GetInterface(pstrName);
}

SYSTEMTIME
& CDateTimeUI::GetTime()
{
return m_sysTime;
}

void CDateTimeUI::SetTime(SYSTEMTIME* pst)
{
m_sysTime
= *pst;
Invalidate();
}

void CDateTimeUI::SetReadOnly(bool bReadOnly)
{
m_bReadOnly
= bReadOnly;
Invalidate();
}

bool CDateTimeUI::IsReadOnly() const
{
return m_bReadOnly;
}

void CDateTimeUI::UpdateText()
{
if (m_nDTUpdateFlag == DT_DELETE)
SetText(_T(
""));
else if (m_nDTUpdateFlag == DT_UPDATE)
{
CDuiString sText;
sText.SmallFormat(_T(
"%4d-%02d-%02d"),
m_sysTime.wYear, m_sysTime.wMonth, m_sysTime.wDay, m_sysTime.wHour, m_sysTime.wMinute);
SetText(sText);
}
}

void CDateTimeUI::DoEvent(TEventUI& event)
{
if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
if( m_pParent != NULL ) m_pParent->DoEvent(event);
else CLabelUI::DoEvent(event);
return;
}

if( event.Type == UIEVENT_SETCURSOR && IsEnabled() )
{
::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_IBEAM)));
return;
}
if( event.Type == UIEVENT_WINDOWSIZE )
{
if( m_pWindow != NULL ) m_pManager->SetFocusNeeded(this);
}
if( event.Type == UIEVENT_SCROLLWHEEL )
{
if( m_pWindow != NULL ) return;
}
if( event.Type == UIEVENT_SETFOCUS && IsEnabled() )
{
//有焦点了就显示日期选择窗口
if( m_pWindow ) return;
m_pWindow
= new CDateTimeWnd();
ASSERT(m_pWindow);
m_pWindow
->Init(this);
m_pWindow
->ShowWindow();
}
if( event.Type == UIEVENT_KILLFOCUS && IsEnabled() )
{
Invalidate();
}
if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK || event.Type == UIEVENT_RBUTTONDOWN)
{
//鼠标按下就显示日期选择窗口
if( IsEnabled() ) {
GetManager()
->ReleaseCapture();
if( IsFocused() && m_pWindow == NULL )
{
m_pWindow
= new CDateTimeWnd();
ASSERT(m_pWindow);
}
if( m_pWindow != NULL )
{
m_pWindow
->Init(this);
m_pWindow
->ShowWindow();
}
}
return;
}
if( event.Type == UIEVENT_MOUSEMOVE )
{
return;
}
if( event.Type == UIEVENT_BUTTONUP )
{
return;
}
if( event.Type == UIEVENT_CONTEXTMENU )
{
return;
}
if( event.Type == UIEVENT_MOUSEENTER )
{
return;
}
if( event.Type == UIEVENT_MOUSELEAVE )
{
return;
}

CLabelUI::DoEvent(
event);
}

当控件获得焦点时则调用CDateTimeWnd类,然后显示出来,根据控件内的文字设置CDateTimeWnd的初始日期。