|
I could not find your update.
I found In WindowProc(..) function of CDateTimeEditCtrlMonthCalCtrl
if (message == WM_LBUTTONDOWN ||
message == WM_MBUTTONDOWN ||
message == WM_RBUTTONDOWN)
{
// Is mouse within control
CPoint point(lParam);
CRect rcClient;
GetClientRect(rcClient);
if (! rcClient.PtInRect(point))
{
ReleaseCapture();
GetOwner()->PostMessage(DTCEM_DESTROY_CALENDAR);
}
else
SetCapture();
}
else if (message == WM_LBUTTONUP ||
message == WM_MBUTTONUP ||
message == WM_RBUTTONUP)
{
CMonthCalCtrl::WindowProc(message, wParam, lParam);
// we seem to lose capture on Xbuttonup, which stops us catching
// out-of-rect messages after changing, for instance, the month
// so we need to re-capture messages. However, if the Xbuttondown
// was out-of-rect, then we won't exist by this point, so test validity
if (::IsWindow(m_hWnd))
SetCapture();
return 0;
}
else if (message == WM_PARENTNOTIFY)
{
if (LOWORD(wParam) == WM_DESTROY)
// just destroyed the 'year' edit/updown, but this makes us lose capture
SetCapture();
}
you have not deal with the case of the month select. how to set the capture of the calendar back afer the pop menu disappeared.
|
|
|
|
|
winkle wrote:
I could not find your update
That's because it takes a while for updates email to the webmaster to appear on the site. It'll appear in a few days.
You are correct: it is due to the WM_MENUSELECT, and the fact that this needs to be used to restore the capture.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
Hi,
One shouldn't include the decimal symbol as a valid date separator. If the decimal symbol is ',', it's accepted, if the Default characters are used or even if it's not specified in the "Specified:" field.
And I don't know whether it's a feature or a bug but if I enter only the year and the month, it's declared as a valid date string.
But never mind, the standard CDateTimeCtrl is good enough for me.
|
|
|
|
|
Hi,
I have a much simpler requirement than your great control but I didn't manage to size it down to my needs..
I simply want to make the client-edge of the standard CDateTimeCtrl disappear as all ctrls in my app have none.
Can you give me a hint on this?
Thanks a lot,
Simon
|
|
|
|
|
Hi, this is Jino.
I have a problem with CDateTimeCtrl
and I think it's very serious and weird.
The symptom is very very simple.
1. Make new dialog-based MFC application.
2. Place a DateTimePicker(CDateTimeCtrl) and a button.
3. generate button click event handler
4. copy example code from MSDN about CDateTimeCtrl::GetTime(CTime & time)
-> refer to the code below.
5. Compile and run
6. Click and Boom! Access violation occured.
below is the example code from MSDN:
---------------------------------------------------------------------
CDateTimeCtrl* pCtrl = (CDateTimeCtrl*) GetDlgItem(IDC_DATETIMEPICKER1);
ASSERT(pCtrl != NULL);
// get as a CTime
CTime timeTime;
DWORD dwResult = pCtrl->GetTime(timeTime);
if (dwResult == GDT_VALID)
{
// the user checked the box and specified data
CString str;
// is it a time-only control, or a date-only control?
if ((pCtrl->GetStyle() & DTS_TIMEFORMAT) == DTS_TIMEFORMAT)//Boom!
str = timeTime.Format(_T("%X"));
else
str = timeTime.Format(_T("%x"));
AfxMessageBox(str);
}
else
{
// the user unmarked the "none" box
AfxMessageBox(_T("Time not set!"));
}
-------------------------------------------------------------------------
When I tested exactly same code at another machine, it worked
just fine. what is happening to me?
the message told me that "unhandled exception in XXX.exe(MFC42d.dll)
:0xC0000005 : access violation"
I compared the timestamp of mscomct2.ocx file on both computer
but couldn't find any difference.
If you have anythig in mind plz don't hesitate to
give me an advice. I'm all ears.
|
|
|
|
|
Hi,
I have looked into this, and can't reproduce your error. I can't see why it would fail on one machine, and not another. I would try just calling GetStyle() on the control somewhere else, and see what it returns, as it is probably that call that is making it fall over. Also, does it work correctly when not using my control?
Let me know what you find out,
Paul.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
I have to compile my app on the Windows platform for which it is going to be used, with no code changes, when I use the CDateTimeCtrl. In other words, I have to compile on a Windows 98 machine to use the executable on W98, then compile the same code on W2000 for use on W2K, then compile on XP for use on XP. Otherwise I get an abend like above. This is with the MS control, not yours. This is a real pain.
|
|
|
|
|
Hi,
Could you please tell me if it support right to left or not?
and also as i use persian/jalali/hijri shamsi calendar may i convert the date table to the persian calendar and display it to users and be able to select the converted date and return a sting to the calling environment to save it as a text on a database?
Best Regards
Saeed
|
|
|
|
|
Hi,
I don't know whether it supports RTL, and I don't have any way of properly finding out. The best thing is to try it. If it doesn't work, then let me know what isn't working, and I may be able to address it.
Same for other calendars.
Paul.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
Hi again,
A dimme problem occurs in a dialog containing two DateTimeEditCtrl controls. Only the last EnableWindow is OK, any idea ?
|
|
|
|
|
Hi,
Thank you for the fixes ! I think they work but I already have an assert on the following lines I commented in order to make it work fine :
if (m_pEdit == NULL)
{
MSG msg;
if (PeekMessage(&msg, NULL, DTCEM_RECREATE, DTCEM_RECREATE, PM_REMOVE))
{
DispatchMessage(&msg);
/*
ASSERT(m_pEdit != NULL);
ASSERT(m_pBtn != NULL);
*/
}
}
Is this correct ? Thank you !
|
|
|
|
|
I had the same problem when I used more than one CDateTimeEditCtrl on a dialog. Everything worked fine with one control but if I add more than one I get the same assert error if I do the following in the OnInitDialog routine for the dialog.
m_ctrlDate1.SetTime(myCOleDateField1);
m_ctrlDate2.SetTime(myCOleDateField2);
Commenting out those two asserts as you did solved the problem. I'm a bit concerned about any side effects. In my testing so far this seems to work without any issues.
If I get a chance I may create a small demo app to try and reproduce the problem.
|
|
|
|
|
Finally got round to looking at this. It's best not to comment out those asserts as they indicate that the controls haven't been created properly, though in this case it's still OK, as the controls still get created eventually.
The correct solution is simple. The problem is that I am calling PeekMessage with a window of NULL, where I should be passing the current control's window. This means that the controls are getting the first re-creation message they can find, and in this case end up with each other's messages, resulting in the assertion failures, but as both of their messages are handled eventually, re-creation ultimately succeeds.
So, replace the line in CDateTimeEditCtrl::WindowProc which reads:
if (PeekMessage(&msg, NULL, DTCEM_RECREATE, DTCEM_RECREATE, PM_REMOVE))
with
if (PeekMessage(&msg, m_hWnd, DTCEM_RECREATE, DTCEM_RECREATE, PM_REMOVE))
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
The Editable Date Picker which is in english version, can i make this dtpicker in Arabic format which should display arabic month, arabic day and year, which is Hijri Date, I am working in middle east my requirement is Arabic Calendar. Please help me.
Abid
|
|
|
|
|
Dear Abid
salaam
I have the same problem but mine is i have to use persian/farsi calendar on the application.
if possible, please tell if you find how to make a DatePicker and localized or customized it.
Best Regards
saeed
|
|
|
|
|
I would like to contribute some choice (or improvement) of the control, as I have benefitted a lot form your
work. Thank you.
This is to allow formatting of the control.
Note: I make the conversion to accept user's statement, although it is not necessary for the formattin alone.
Note: You may simply it if you do not want to accept user statement.
Note: I have check with different formatting statements, but I have not check "ALL" possibilities.
Note: Please feel free to use the functions.
Note: If anyone finds any error or improvement of the logarithm, please let me know.
Note: notify me at (hshliang@hotmail.com). Thank you.
To add the Formatting function:
1) Add these definitions to class CDateTimeEditCtrl in DateTimeEditCtrl.h
under class CDateTimeEditCtrl:
public:
CString ConvertDateFormatString(LPCTSTR szFormat);
protected:
CString _convert(LPCTSTR szformat);
2) Add these functions to class CDateTimeEditCtrl in DateTimeEditCtrl.cpp
CString CDateTimeEditCtrl::ConvertDateFormatString(LPCTSTR szFormat)
{
//use string for find_first_of functions.. etc
CString fformat; //final string
string sformat = szFormat;
//Parse '' (added text) and format strings
int nQuote1 = 0;
int nQuote2 = 0;
CStringArray saT; //to hold statements
CStringArray saF; //to hold format strings
//search first (')
nQuote1 = sformat.find_first_of('\'',0);
//if one is found, read the string and skip to next quote
//if no quote found, start with first char
if(nQuote1 == -1) nQuote1 = 0;
else nQuote1 += 1; //start with first char after quote
while(nQuote1 < sformat.size() && nQuote2 < sformat.size()){
nQuote2 = sformat.find_first_of('\'',nQuote1);
//if no Quote2 found, use last
if(nQuote2 == -1 || nQuote2 >= sformat.size()){
nQuote2 = sformat.size();
saF.Add(sformat.substr(nQuote1, nQuote2 - nQuote1).c_str());
}
else{ //second quote found, read the format string, then the following text
saT.Add(sformat.substr(nQuote1, nQuote2 - nQuote1).c_str());
//next
nQuote1 = sformat.find_first_of('\'',nQuote2+1);
//if next quote not found, use last char
if(nQuote1 == -1) nQuote1 = sformat.size();
else nQuote1++;
//assume format string if nQuote2 != sformat.size() //last letter
saF.Add(sformat.substr(nQuote2 + 1, nQuote1 - nQuote2 - 2).c_str());
}
}
//form final string
for( int i = 0; i < _MAX(saT.GetSize(), saF.GetSize()); i++){
if(i < saT.GetSize()) fformat += saT.GetAt(i);
if(i < saF.GetSize()) fformat += _convert(saF.GetAt(i));
}
//convert format strings
return fformat;
}
CString CDateTimeEditCtrl::_convert(LPCTSTR szformat)
{
CString sformat; //format string
const TCHAR * pch = 0; //character in question
TCHAR lastchar = 0; //character of the last group
int nchar = 0; //number of char in the last group in question
//scan the string
pch = szformat;
while(*pch != 0 || lastchar != 0){ //valid char OR still a last group to manage
if(*pch != s_chDateSep && /*skip separator*/
*pch != ' ' && /*skip space*/
NULL == strchr(".,",*pch)) /*skip punctuation marks*/
{
if(strchr("dMyhHmt",lastchar)){ //if a format character
if(nchar <1){ //new set
lastchar = *pch; //save the char as last group
nchar ++; //increment by one
pch ++; //next char
continue; //see next char
}
else if(lastchar == *pch){ //same set
nchar ++; //step one
pch ++; //next char
continue; //see next char
}
//if not the same char, finish up with last set
}
else{
ASSERT(FALSE); //not an accepted character for format string! stop!
}
}
if(nchar > 0 && lastchar != 0){
switch(lastchar){
case 'd':{
switch(nchar){
case 1: //d
sformat += _T("%#d"); break;
case 2: //dd
sformat += _T("%d"); break;
case 3: //ddd
sformat += _T("%a"); break;
case 4: //dddd
sformat += _T("%A"); break;
}
break;
}
case 'M':{
switch(nchar){
case 1: //M
sformat += _T("%#m"); break;
case 2: //MM
sformat += _T("%m"); break;
case 3: //MMM
sformat += _T("%b"); break;
case 4: //MMMM
sformat += _T("%B"); break;
}
break;
}
case 'y':{
switch(nchar){
case 2: //yy
sformat += _T("%y"); break;
case 4: //yyyy
sformat += _T("%Y"); break;
}
break;
}
case 'h':{
switch(nchar){
case 1: //h
sformat += _T("%#I"); break;
case 2: //hh
sformat += _T("%I"); break;
}
break;
}
case 'H':{
switch(nchar){
case 1: //H
sformat += _T("%#H"); break;
case 2: //HH
sformat += _T("%H"); break;
}
break;
}
case 'm':{
switch(nchar){
case 1: //m
sformat += _T("%#M"); break;
case 2: //mm
sformat += _T("%M"); break;
}
break;
}
case 't':{
switch(nchar){
case 1: //t
sformat += _T("%#p"); break; //no equivalent option (%#p == %p
'#' is ignored)
case 2: //tt
sformat += _T("%p"); break;
}
break;
}
default:
if(*pch != 0) sformat += lastchar;
}
if(*pch != 0) sformat += *pch; //save the char
nchar = 0; //new group
lastchar = 0;
}
else{
if(*pch != 0) sformat += *pch;
}
if(strchr("dMyhHmt",*pch)){
lastchar = *pch; //save the char if a format set
}
if(*pch != 0) pch ++; //next char, if has not reached end yet (need to prevent overrun)
}
return sformat;
}
3) In WindowProc function of CDateTimeEditCtrl, make these changes:
Change the display formatting in DTM_SETSYSTEMTIME
Add function strcpy(s_szDateFormat, (LPCTSTR)lParam); to the function call of DTM_SETFORMAT
like:
LRESULT CDateTimeEditCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
..........
..........
case DTM_SETSYSTEMTIME:
..........
Instead of : CString sDate = date.Format(VAR_DATEVALUEONLY);
Use : CString sDate = date.Format(ConvertDateFormatString(s_szDateFormat));
..........
..........
case DTM_SETFORMAT:
TRACE("Got DTM: %s\n", FormatDTM(message));
TRACE("lParam: %s\n", (LPCTSTR)lParam);
strcpy(s_szDateFormat, (LPCTSTR)lParam);
break;
case DTM_GETRANGE:
case DTM_SETRANGE:
ASSERT(FALSE); // not supported
AfxThrowNotSupportedException();
break;
..........
..........
}
4) In OnNotify function of CDateTimeEditCtrl, make these changes:
Add statement to convert the date to the formatted string:
BOOL CDateTimeEditCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
..........
..........
Instead of : CString sDate = date.Format(VAR_DATEVALUEONLY);
Use : CString sDate = date.Format(ConvertDateFormatString(s_szDateFormat));
..........
..........
}
////////////////////////////////////
Voila, now you can modify the format like the original CDateTimeCtrl control
E.g.:
In:
BOOL CDateTimeEditCtrlDemoDlg::OnInitDialog()
{
Add::
DateTime_SetFormat(m_date.GetSafeHwnd(),_T("d/M/yyyy")); //to give 5/5/2005
OR::
DateTime_SetFormat(m_date.GetSafeHwnd(),_T("dd/MM/yy")); //to give 05/05/05
Etc:
}
you should get what you want. If you find any problem, please let me know.
Henry
hshliang@hotmail.com
|
|
|
|
|
I must say that this is the best DateTimeControl I have ever come across! I have been trying to capture the edit control of the CDateTimeCtrl for years, and this is the first time that I have been able to do something with the Edit Box.
Thank you Paul.
Now there is a strange behaviour that I cannot explain. Normally, if you set the edit box to Readonly, it will have a colored background so the user recognises that it is not changable. With your SetNonEditable(), the edit box remain to have the same look. that is a strange behaviour. Is there an explanation to it? I try to change the m_pEdit with SetReadOnly(), it will stop the user entry, but the edit box remains the same in appreance. It seems not to be a problem of your code but somehow the CEdit of the CDateTimeCtrl does not response as any other CEdit.
H Liang
|
|
|
|
|
I am sorry to ask this question. I found out today that you purposely make it different from the standard Editbox response. Hence, I only have to remove the special funciton to make the background white and I have what I want. Thank you.
H Liang
|
|
|
|
|
Hi, Sorry to bother you with what might be a brain-dead case, but I've added your class to a dll in my application, and when try to link it I keep getting the following error:
Linking...
Creating library Debug/Archive.lib and object Debug/Archive.exp
DateTimeEditCtrl.obj : error LNK2001: unresolved external symbol "public: static struct CRuntimeClass const CDateTimeCtrl::classCDateTimeCtrl" (?classCDateTimeCtrl@CDateTimeCtrl@@2UCRuntimeClass@@B)
Debug/Archive.dll : fatal error LNK1120: 1 unresolved externals
Error executing link.exe.
I've added /GR to the project setting in both my dll and my main application - but I still get this error.
Any help you could provide would be much appreciated!!
Thank you
HC
|
|
|
|
|
Oops, my bad.
When I modified the following line in the file DateTimeEditCtrl.cpp (as in a previous reply to this article), it resolved my link error.
IMPLEMENT_DYNAMIC(CDateTimeEditCtrl, CDateTimeCtrl)
to be
IMPLEMENT_DYNAMIC(CDateTimeEditCtrl, CDateTimeEditCtrl)
-HC
|
|
|
|
|
OK, but I wouldn't do it this way because, as I said in my reply, it stops you using IsKindOf (or DYNAMIC_DOWNCAST) to determine if your control is a CDateTimeCtrl.
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
Same problem, any other ideas ?
Thanks ))
|
|
|
|
|
As I have existing code, when I implemented the CDateTimeEditCtrl control, I experienced a minor side effect. In my app, there are constraints to the dates which can be entered by the user (i.e., min and max). These constraints are tested when a DTN_DATETIMECHANGE message is passed (i.e., date changed by the user), not when the calendar is "closed up" (DTN_CLOSEUP). This works for the CDateTimeCtrl. However, with the CDateTimeEditCtrl, the date selected by the user is put into the edit control (effectively overriding the edit constraints).
Casey
|
|
|
|
|
To fix this, you need to move some code in the CDateTimeEditCtrl::OnNotify function.
Move the code:
LPNMSELCHANGE lpnmsc = (LPNMSELCHANGE)pnmhdr;
COleDateTime date(lpnmsc->stSelStart);
ASSERT(date.GetStatus() == COleDateTime::valid);
CString sDate = date.Format(VAR_DATEVALUEONLY);
m_pEdit->SetWindowText(sDate);
to be the first block of code after the line:
else if (pnmhdr->code == MCN_SELCHANGE)
I was grabbing the date from the calendar and overwriting what had been selected (or in this case constrained) by the last DTN_DATETIMECHANGE message. It now behaves (at least in this respect) the same as the standard control.
I have uploaded a fixed version of the source (version 3.1).
---
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
When I attempted to implement the control in a DLL (needing only to export the constructor and destructor), I encountered a Link Reference Error for CRuntime info of CDateTimeCtrl (Windows standard control). It seems that runtime info is not exported for this control (at least not in the libraries I'm linking to).
Link Error is as follows:
error LNK2001: unresolved external symbol "public: static struct CRuntimeClass const CDateTimeCtrl::classCDateTimeCtrl" (classCDateTimeCtrl@CDateTimeCtrl@@2UCRuntimeClass@@B)
I was able to get around this link error by modifying the following line in the file DateTimeEditCtrl.cpp.
IMPLEMENT_DYNAMIC(CDateTimeEditCtrl, CDateTimeCtrl)
to be
IMPLEMENT_DYNAMIC(CDateTimeEditCtrl, CDateTimeEditCtrl)
When I changed the second parameter from CDateTimeCtrl to CDateTimeEditCtrl, this macro no longer causes a link reference error, and functions perfectly.
***
Paul's solution was similar (although more in-depth)...he writes the following,
Meanwhile, I've been looking into it too. I got the same problem, but only as part of an extension DLL.
After a lot of tweaking, I've found it's down to the CDateTimeCtrl. It doesn't have its IMPLEMENT_DYNAMIC(CDateTimeCtrl, CWnd) exported. Dumping the strings of the MFC libs gives me the following for CDateTimeCtrl (some variants and duplicates omitted):
NAFXCWD.LIB: ?classCDateTimeCtrl@CDateTimeCtrl@@2UCRuntimeClass@@B
NAFXCW.LIB: ?classCDateTimeCtrl@CDateTimeCtrl@@2UCRuntimeClass@@B
Whereas doing the same for CListCtrl (which I am also exporting an override to) gives me this:
NAFXCWD.LIB: ?classCListCtrl@CListCtrl@@2UCRuntimeClass@@B
NAFXCW.LIB: ?classCListCtrl@CListCtrl@@2UCRuntimeClass@@B
MFC42D.LIB: __imp_?classCListCtrl@CListCtrl@@2UCRuntimeClass@@B
MFC42D.LIB: ?classCListCtrl@CListCtrl@@2UCRuntimeClass@@B
MFC42.LIB: __imp_?classCListCtrl@CListCtrl@@2UCRuntimeClass@@B
MFC42.LIB: ?classCListCtrl@CListCtrl@@2UCRuntimeClass@@B
The difference being that CDateTimeCtrl doesn't have an 'importable' version of the runtime stuff.
To get round this add the following somewhere in a cpp file, where it will only get used once, for example in your stdafx.cpp:
#ifdef _AFXDLL
IMPLEMENT_DYNAMIC(CDateTimeCtrl, CWnd)
#endif
[You could put it in the DateTimeEditCtrl cpp file, but then it'll error if it also happens to be elsewhere]
***
All the best,
Casey
|
|
|
|
|