|
WM_CLTCOLOR is not sent for CDateTimeCtrl. So I think you may override OnPaint() and do the paiting by yourself.
Anand
|
|
|
|
|
add the follow codes at the end of the funcion "WindowProc" of class CDateTimeEditCtrlMonthCalCtrl
else if ( message == WM_MENUSELECT)
{
if(lParam == NULL)
SetCapture();
}
then It works ,but i don't konw whether it is absolutely right.
thanks ,paul, i thought out it with your hints.
excellent control and idea!
|
|
|
|
|
OK, this restores capture to the calendar control, but also dismisses the calendar, which is not the desired behaviour. The full fix has the same code as yours, but adds a flag to make sure that the next mouse down message does not dismiss the calendar if the menu was dismissed by the mouse. I will email you the new code directly, though it should appear on the site within the next few days.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
When you click the month selected area at the top of the calendar, the month selected menu will popup. After the menu disappears, you click the outside of calendar,but the calendar will not disappear.
|
|
|
|
|
This is to do with the menu taking capture from the calendar, so it then doesn't know that the user has clicked outside of it. I have added a fix for it, and posted an update.
"The way of a fool seems right to him, but a wise man listens to advice" - Proverbs 12:15 (NIV)
|
|
|
|
|
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
|
|
|
|
|