CDateTimeUI类源码分析

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的初始日期。

posted @ 2016-01-17 14:58  reyzal  阅读(1132)  评论(0编辑  收藏  举报