Serialize CDateTimeCtrl state impossible?
Printed From: Codejock Forums
Category: Codejock Products
Forum Name: General Discussion
Forum Description: Topics Related to Visual C++ MFC Development in General
URL: http://forum.codejock.com/forum_posts.asp?TID=14024
Printed Date: 27 November 2024 at 2:49am Software Version: Web Wiz Forums 12.04 - http://www.webwizforums.com
Topic: Serialize CDateTimeCtrl state impossible?
Posted By: znakeeye
Subject: Serialize CDateTimeCtrl state impossible?
Date Posted: 15 April 2009 at 4:03am
If you create a CDateTimeCtrl with the DTS_SHOWNONE style, the control will have a checkbox where you can choose "no time".
This check can be checked using SetTime(&stValidTime) and unchecked with SetTime(NULL). When you click it manually, the time value is not changed even though the check is not toggled. When doing this programmatically with SetTime() the time is reset (NULL = no time).
This yields a problem when serializing the state of the control from a given source (like the Registry).
Q: How do you set a valid time AND uncheck the control programmatically?
------------- PokerMemento - http://www.pokermemento.com/
|
Replies:
Posted By: ABuenger
Date Posted: 15 April 2009 at 6:25am
Haven't used CDateTimeCtrl before, but why aren't you using the XTP control? (If they don't have a drop in replacement put it on the wish list)
------------- Codejock support
|
Posted By: Oleg
Date Posted: 15 April 2009 at 8:25am
Hello,
Yes, I saw same issue, but seems CDateTimeCtrl doesn't have method to make this :(
------------- Oleg, Support Team CODEJOCK SOFTWARE SOLUTIONS
|
Posted By: znakeeye
Date Posted: 15 April 2009 at 4:25pm
I believe it can be done by simulating a click...
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: znakeeye
Date Posted: 01 July 2009 at 3:34am
There must be a way! This is so annoying... No ideas?
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 01 July 2009 at 11:41pm
CDateTimeCtrl m_DateTimeCtrl;
CRect rect(20, 20, 250, 45);
m_DateTimeCtrl.Create(WS_VISIBLE | WS_CHILD | WS_TABSTOP | DTS_SHOWNONE | DTS_SHORTDATEFORMAT, rect, this, 1005);
m_DateTimeCtrl.SetFormat(_T("ddd, MMM d, yyyy - HH:mm:ss"));
//Now uncheck it - I always use such thing for datetime fields where app ALLOWS user to keep it not filled
//and if it unchecked - ignore it for store
::SendMessage(m_DateTimeCtrl.GetSafeHwnd(), (UINT) DTM_SETSYSTEMTIME, (WPARAM) (DWORD) GDT_NONE, (LPARAM) NULL);
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 04 July 2009 at 7:25pm
Thanks for your reply.
Now, try this:
1) Date should equal 17 january 1982 (not today's date, that is).
2) Checkbox should be unchecked.
This state is possible to achieve when the user clicks the control, but (afaik) impossible to accomplish programmatically.
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 04 July 2009 at 7:40pm
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 05 July 2009 at 6:26am
I'm impressed!
Thanks a lot! :)
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 06 July 2009 at 10:42am
As you know CDateTimeCtrl not allow to retrieve datetime value (visible on display) if unchecked.
This is simple code to programmatically change mode without user click - after you can get value - and uncheck CDateTimeCtrl control back.
LPARAM lparam = MAKELPARAM(10, 15);
m_DateTimeCtrl.SendMessage(WM_LBUTTONDOWN, NULL, lparam);
//Of course 10 (y) and 15 (x) is coordinates for standard case - normal font. Need to adjust for some custom setup like large font
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 07 July 2009 at 3:06am
Yeah, but in your previous post, you used GDT_NONE instead of simulating a click?
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 07 July 2009 at 7:56am
This is not about GDT_NONE - it's about opposite - how to porgrammatically set to VALID state and get internal Value - like GetTime
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 22 July 2009 at 4:40pm
No, this can't be done!
The problem lies in CDateTimeCtrl::GetTime(). When the control is unchecked, the time cannot be read! This means the time cannot be stored, hence not serialized (yes, deserialization is possible). You would have to capture all date changes and store the date on your own...
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 22 July 2009 at 4:45pm
Control will not answer you on your call but still keep previously set value on it's display. I demonstarted how to get it back!
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 22 July 2009 at 4:45pm
mdoubson wrote:
As you know CDateTimeCtrl not allow to retrieve datetime value (visible on display) if unchecked.
This is simple code to programmatically change mode without user click - after you can get value - and uncheck CDateTimeCtrl control back.
LPARAM lparam = MAKELPARAM(10, 15);
m_DateTimeCtrl.SendMessage(WM_LBUTTONDOWN, NULL, lparam);
//Of course 10 (y) and 15 (x) is coordinates for standard case - normal font. Need to adjust for some custom setup like large font |
Sorry, missed that post. But still, the solution is quite ugly (not to mention that the coordinate of the checkbox cannot be safely determined).
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 23 July 2009 at 3:54pm
If somebody ask a question: "How do you set a valid time AND uncheck the control programmatically?"
and recive positive answer - last he can do in his comment - use term ugly or talk about safe way!?
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 23 July 2009 at 11:04pm
Sorry, didn't mean it that way :(
The problem is not your solution. The problem is that Microsoft implemented the control this way.
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 24 July 2009 at 1:29am
OK.
This is a simple way to bypass "the coordinate of the checkbox cannot be safely determined"
for (int i = 0; i < 30; i++)
{
//LPARAM lparam = MAKELPARAM(10, 15);
LPARAM lparam = MAKELPARAM(i, 15);
m_DateTimeCtrl.SendMessage(WM_LBUTTONDOWN, NULL, lparam);
COleDateTime dt;
m_DateTimeCtrl.GetTime(dt);
if (dt.GetStatus() == COleDateTime::valid)
{
CString s; s.Format(_T( "Valid with i =%d"), i);
AfxMessageBox(s);
break;
}
}
i = 0 - bad, 1 - good
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 25 July 2009 at 2:38am
Thanks for your hints.
Though, I believe this is the best solution:
BOOL CDateTimeCtrlEx::OnDateTimeChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMDATETIMECHANGE pDTChange = reinterpret_cast<LPNMDATETIMECHANGE>(pNMHDR);
m_lastDate = pDTChange->st;
*pResult = 0;
return FALSE; // Let the parent handle the message as well!
}
"m_lastDate" will always contain the latest selection, no matter if the checkbox was checked or not. Though, just in case, I only use this variable if GetTime() fails (which it does when unchecked). One must also be careful with calls to SetTime() since it cannot be overloaded.
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 26 July 2009 at 3:07am
No - this is not true - in the moment user uncheck control - m_lastDate will have invalid data. Proper syntax for notification - void - you can use *pResult to pass TRUE or FALSE)
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 03 August 2009 at 2:37pm
Disagree.
If you use ON_NOTIFY_REFLECT_EX() in your message map, your message handler may or may not allow the parent window to handle the message. If the handler returns FALSE, the message will be handled by the parent as well, while a call that returns TRUE does not allow the parent to handle it.
And
If you want more than one object in the notification routing to handle a message, you can use ON_NOTIFY_EX (or ON_NOTIFY_EX_RANGE) rather than ON_NOTIFY (or ON_NOTIFY_RANGE).
If the user unchecks the control, m_lastDate is assigned a valid date. Just verified this.
------------- PokerMemento - http://www.pokermemento.com/
|
Posted By: mdoubson
Date Posted: 03 August 2009 at 2:54pm
Sure I did before posting:
void CMFC_DATEDlg::OnDateTimeChanged(NMHDR *pNMHDR, LRESULT *pResult){
LPNMDATETIMECHANGE pDTChange = reinterpret_cast<LPNMDATETIMECHANGE>(pNMHDR);
m_lastDate = pDTChange->st; SetWindowText(m_lastDate.Format()); *pResult = 0; }
------------- Mark Doubson, Ph.D.
|
Posted By: znakeeye
Date Posted: 04 August 2009 at 3:01am
Strange. Anyway, you don't have to assign it if it is invalid.
if ((pDTChange->dwFlags == GDT_VALID)
m_lastDate = pDTChange->st;
Strange indeed, since my date value is not changed when debugging during "unchecking"...
------------- PokerMemento - http://www.pokermemento.com/
|
|