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

CDateTimeUI类源码分析的更多相关文章

  1. List 接口以及实现类和相关类源码分析

    List 接口以及实现类和相关类源码分析 List接口分析 接口描述 用户可以对列表进行随机的读取(get),插入(add),删除(remove),修改(set),也可批量增加(addAll),删除( ...

  2. Cocos2d-X3.0 刨根问底(六)----- 调度器Scheduler类源码分析

    上一章,我们分析Node类的源码,在Node类里面耦合了一个 Scheduler 类的对象,这章我们就来剖析Cocos2d-x的调度器 Scheduler 类的源码,从源码中去了解它的实现与应用方法. ...

  3. Java Properties类源码分析

    一.Properties类介绍 java.util.Properties继承自java.util.Hashtable,从jdk1.1版本开始,Properties的实现基本上就没有什么大的变动.从ht ...

  4. java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析

    java面试中经常被问到list常用的类以及内部实现机制,平时开发也经常用到list集合类,因此做一个源码级别的分析和比较之间的差异. 首先看一下List接口的的继承关系: list接口继承Colle ...

  5. Java并发编程笔记之Unsafe类和LockSupport类源码分析

    一.Unsafe类的源码分析 JDK的rt.jar包中的Unsafe类提供了硬件级别的原子操作,Unsafe里面的方法都是native方法,通过使用JNI的方式来访问本地C++实现库. rt.jar ...

  6. String 类源码分析

    String 源码分析 String 类代表字符序列,Java 中所有的字符串字面量都作为此类的实例. String 对象是不可变的,它们的值在创建之后就不能改变,因此 String 是线程安全的. ...

  7. Cocos2d-X3.0 刨根问底(三)----- Director类源码分析

    上一章我们完整的跟了一遍HelloWorld的源码,了解了Cocos2d-x的启动流程.其中Director这个类贯穿了整个Application程序,这章随小鱼一起把这个类分析透彻. 小鱼的阅读源码 ...

  8. Java线程池ThreadPoolExecutor类源码分析

    前面我们在java线程池ThreadPoolExecutor类使用详解中对ThreadPoolExector线程池类的使用进行了详细阐述,这篇文章我们对其具体的源码进行一下分析和总结: 首先我们看下T ...

  9. Spring之WebContext不使用web.xml启动 初始化重要的类源码分析(Servlet3.0以上的)

    入口: org.springframework.web.SpringServletContainerInitializer implements ServletContainerInitializer ...

随机推荐

  1. 树的直径的求法即相关证明【树形DP || DFS】

    学习大佬:树的直径求法及证明 树的直径 定义: 一棵树的直径就是这棵树上存在的最长路径. 给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和.树中最远的两个节点之间的距 ...

  2. 检查WIFI是否连接

    查看网络连接 查看WiFi连接状态 (连接- -断开)

  3. vue中a的href写法

    注意点:href前面要加“:”或者v-bind: 2.字符串要用单引号“ ’ ”包住 加上了冒号是为了动态绑定数据,等号后面可以写变量. 如果不使用冒号,等号后面就可以写字符串等原始类型数据.这是就无 ...

  4. 【洛谷P2216】[HAOI2007]理想的正方形

    理想的正方形 [题目描述] 一个a*b的矩阵,从中取一个n*n的子矩阵,使所选矩阵中的最大数与最小数的差最小. 思路: 二维的滑动窗口 对于每行:用一个单调队列维护,算出每个长度为n的区间的最大值和最 ...

  5. 基础算法之Dijkstra最短路径

    核心思想:以起始原点为中心,想外层扩展,知道扩展到重点为止. 设到A点的最短路径上,A点前驱节点为B,则该路径包含到达节点B的最短路径. S集合代表已经探索过的节点,U集合表示未探索过的节点. 时间复 ...

  6. 【题解】洛谷P1350 车的放置(矩阵公式推导)

    洛谷P1350:https://www.luogu.org/problemnew/show/P1350 思路 把矩阵分为上下两块N与M 放在N中的有i辆车 则放在M中有k-i辆车 N的长为a   宽为 ...

  7. C#位数不足补零

    C#位数不足补零:int i=10;方法1:Console.WriteLine(i.ToString("D5"));方法2:Console.WriteLine(i.ToString ...

  8. android 界面控件 textview 全解

    textview基本使用: <TextView 10. android:id="@+id/txtOne" 11. android:layout_width="200 ...

  9. LeetCode 中级 - 第k个排列(60)

    可以用数学的方法来解, 因为数字都是从1开始的连续自然数, 排列出现的次序可以推 算出来, 对于n=4, k=15 找到k=15排列的过程: 1 + 对2,3,4的全排列 (3!个) 2 + 对1,3 ...

  10. LeetCode 简单 - 最大子序和(53)

    采用动态规划方法O(n) 设sum[i]为以第i个元素结尾且和最大的连续子数组.假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以 ...