Add your own alternative version
Stats
143.9K views 46 bookmarked
Posted
25 Mar 2000
Licenced
|
Comments and Discussions
|
|
thanks for your article. my requirement was similar but smaller i guess, and i tried to use the Allow Edit property (DTN_APPCANPARSE), maybe microsoft added it recently, but here is my solution:
(the COleDateTime m_D is a quick fix data buffer, maybe it can be avoided!)
EditableDateTimeCtrl.h
#pragma once
#include "afxdtctl.h"
class CEditableDateTimeCtrl :
public CDateTimeCtrl
{
public:
CEditableDateTimeCtrl(void);
private:
COleDateTime m_D;
protected:
afx_msg void OnUserString(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDatetimeChange(NMHDR* pNMHDR, LRESULT* pResult);
DECLARE_MESSAGE_MAP()
};
EditableDateTimeCtrl.cpp:
#include "stdafx_ERFGUI.h"
#include "EditableDateTimeCtrl.h"
CEditableDateTimeCtrl::CEditableDateTimeCtrl(void)
{
m_D.SetDate(1000, 1, 1);
}
BEGIN_MESSAGE_MAP(CEditableDateTimeCtrl, CDateTimeCtrl)
ON_NOTIFY_REFLECT(DTN_DATETIMECHANGE, OnDatetimeChange)
ON_NOTIFY_REFLECT(DTN_USERSTRING, OnUserString)
END_MESSAGE_MAP()
void CEditableDateTimeCtrl::OnUserString(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMDATETIMESTRING pDTString = reinterpret_cast<LPNMDATETIMESTRING>(pNMHDR);
VERIFY(m_D.ParseDateTime(pDTString->pszUserString));
*pResult = 0;
}
void CEditableDateTimeCtrl::OnDatetimeChange(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMDATETIMECHANGE pDTChange = reinterpret_cast<LPNMDATETIMECHANGE>(pNMHDR);
SetFormat(NULL);
if (m_D.GetYear() != 1000) {
SetTime(m_D);
m_D.SetDate(1000, 1, 1);
}
*pResult = 0;
}
|
|
|
|
|
well i add this class to my project, and from the main dialog i create an instance using the Create function and the edit box appears in the app. The problem is that i can't change the content of the edit box. I am a beginner and i think that the m_strMask i somehow not connected to my main dialog. Please help or give me a link to the source or project files...
|
|
|
|
|
What could have taken hours took just a few minutes thanks to your class! 
|
|
|
|
|
I need to instantiate the control on a dialog, but the control is not visible when the dialog displays. I'm using the following code in the OnInitDialog function:
<br />
RECT DTRect;<br />
DTRect.left = 20;<br />
DTRect.top = 232;<br />
DTRect.right = 165;<br />
DTRect.bottom = 247;<br />
VDateTimeEdit * m_DateTime = new VDateTimeEdit;<br />
m_DateTime->Create(ES_LEFT, DTRect, this, IDC_DATE_TIME);
The coordinates of DTRect are within the boundaries of the dialog.
I also commented out the SetDateTime function call in the PreSubclassWindow method as suggested by another poster.
1) Is OnInitDialog the right place to create the control?
2) Is "this" the correct value for the 3rd parameter?
Can anyone help with this?
|
|
|
|
|
Hi everybody,
first to say: great code. Easy to modify. Nice.
All i needed for date or time.
I've added some functionality:
1. Added macros for INCREMENTING/DECREMENTING the cursor to the next/previous masked char like numeric input does. Fixed chars will be left out.
2. causing VK_BACK to delete the according char and replace it with a '0' like the normal numeric input will do.
Modify your code to the following:
#define INCREMENT_CURSOR() if (++pos < m_strMask.GetLength())\
for ( c = m_strMask[pos]; pos < m_strMask.GetLength()\
&& c != 'D' && c != 'M' \
&& c != 'Y' && c != 'h' \
&& c != 'm' && c != 's';\
c = m_strMask[pos])\
pos++;
#define DECREMENT_CURSOR() if (--pos > 0)\
for ( c = m_strMask[pos]; pos > 0 \
&& c != 'D' && c != 'M' \
&& c != 'Y' && c != 'h' \
&& c != 'm' && c != 's';\
c = m_strMask[pos]) \
pos--;
Modify the code in the OnChar handler
from:
CString old;
GetWindowText(old);
int pos;
TCHAR c;
GetSel(pos, pos);
switch (nChar) {
case VK_BACK: pos--;
break;
case VK_UP: pos--;
break;
case '0':case '1':case '2':case '3':
case '4':case '5':case '6':case '7':
case '8':case '9':
to:
CString old;
GetWindowText(old);
int pos;
TCHAR c;
GetSel(pos, pos);
int nAddPos=0;
switch (nChar) {
case VK_UP: pos--;
break;
case VK_BACK:
nAddPos = pos;
DECREMENT_CURSOR();
nAddPos = pos-nAddPos;
nChar = '0';
if( pos <0)
{
pos = 0;
break;
}
case '0':case '1':case '2':case '3':
case '4':case '5':case '6':case '7':
case '8':case '9':
Add the nAddPos param to SetSel like:
SetSel(pos+nAddPos, pos+nAddPos);
Last but not least add in the OnKeyDown handler:
case VK_RIGHT:
{
int pos;
TCHAR c;
GetSel(pos, pos);
INCREMENT_CURSOR();
SetSel(pos, pos);
}
break;
case VK_LEFT:
{
int pos;
TCHAR c;
GetSel(pos, pos);
DECREMENT_CURSOR();
SetSel(pos, pos);
}
break;
|
|
|
|
|
Could anybody fix it that date can be changed or edit by input?
|
|
|
|
|
Same here...
|
|
|
|
|
This is what i'm looking for!
Thanks again!
|
|
|
|
|
Also thanks to Trevor Ash, without his comments i cann't even implement this Class.
|
|
|
|
|
You excellcent work help me a lot! But I've met a little problem:
void OnChar(...)
{
...
case '0':case '1':case '2':case '3':
case '4':case '5':case '6':case '7':
case '8':case '9':
...
// Next lines may cause the edit control uneditable
// Reason: invalid date return by GetDateTime()
// cause the status of dt is invalid,
// so the SetDateTime() function won't be called.
COleDateTime dt = GetDateTime(str);
if (dt.GetStatus() == COleDateTime::valid)
SetDateTime(dt);
...
break;
...
}
To make the GetDateTime() function return a invalid date:
1. Type month:12, day 31
2. Change first digit of month to 0
See the return date--"02/31"!
Solution:
Restrict the return date of GetDateTime() function, 31 or 30 days in a month, 28 or 29 days in Feb... a little , hoho~~
Pardon me for my poor English...
|
|
|
|
|
I would first like to let you know that this control rocks!
It is very usefull.
I would like to know if you could help me.
I would like to have a default character used as a place holder for
all valid digit entry positions ie if the mask character was '_' then the
deafault view ( after reset) would be __/__/____ if the mask was MM/DD/YYYY.
This could represent a NULL date.
I would also like the backspace to remove any digit and replace with the mask character.
i.e.
before backspace ( cursor in day after second digit ): 12/25/2003
after backspace 12/2_/2003.
Thanks for taking the time to help. 
|
|
|
|
|
Hi Tri,
I am just wondering if you can answer me this question.
How do you detect Ctrl+Left Mouse button down in MFC ?
I am writing an application that will allow people to
select icons using Ctrl+left mouse button. thanks,
Chi-Cheong
|
|
|
|
|
Worked perfectly and saved me a lot of time.
Thank you very much!
|
|
|
|
|
There is a problem when something is selected. For example when second number is selected and I rewrite it, nothing happens. I solved this way
void CDateTimeEdit::OnChar(UINT nChar, UINT /*nRepCnt*/, UINT /*nFlags*/)
{
CString old;
GetWindowText(old);
int pos, endpos;
TCHAR c;
GetSel(pos, endpos);
if (endpos - pos == 0) ////this two lines i added
pos = endpos; ////
It looks that it works.
|
|
|
|
|
There is a problem when I select for example second number and rewrite it, nothing happens.
|
|
|
|
|
I added
t.tm_mon += 1;
t.tm_year += 1900;
t.tm_mday = 1;
t.tm_hour = 0;
t.tm_min = 0;
t.tm_sec = 0;
int i, n = m_strMask.GetLength();
because i did not use the seconds field in my mask and kept getting whatever seconds the system clock was at when the routine was called.
so far i like this control - saved me lots of time
chris
|
|
|
|
|
Hi,
I couldn't see the result of this class. I'm calling create function of the object in oninitdialog of the dialog box. But it is giving the exception as division by zero.
maha

|
|
|
|
|
If you are creating controls dynamically do the following change:
void VDateTimeEdit::PreSubclassWindow()
{
//SetDateTime(COleDateTime::GetCurrentTime());
CEdit::PreSubclassWindow();
}
The control is not shown yet at that point.
|
|
|
|
|
|
Just figured out how to do the trick !!
As you may know, a CSpinButtonCtrl won't work at all because it will change the selection state when you set it as a buddy (I learned it the hard way)
The elegant solution is then to add the WS_VSCROLL style in your VDateTimeEdit CEdit derived control : since the resource editor won't allow a Vertical scroll unless you use a Multiline Edit, you better do it by hand by editing the resource file as text (the good old way)
In my case, it looked like this, IDC_EDIT1 being my VDateTimeEdit:
EDITTEXT IDC_EDIT1,7,55,139,12, WS_VSCROLL
Then, just map WM_VSCROLL with the class wizard, it will add for you:
->in the header:
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
->in the code:
BEGIN_MESSAGE_MAP(VDateTimeEdit, CEdit)
ON_WM_CONTEXTMENU()
//{{AFX_MSG_MAP(VDateTimeEdit)
ON_WM_CHAR()
ON_WM_KEYUP()
ON_WM_KEYDOWN()
ON_WM_MOUSEMOVE()
ON_WM_VSCROLL()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
And here is the trick, when you receive scroll notification, make it believe it's a arrow key message :
void VDateTimeEdit::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if (nSBCode == SB_LINEDOWN)
OnKeyDown(VK_DOWN, 0, 0);
else if (nSBCode == SB_LINEUP)
OnKeyDown(VK_UP, 0, 0);
}
After all, a SpinCtrl is just a special case of a vertical scroll !
Isn't cool ?
Huge thanks for the original implementation, such controls should have been in the standard MFC for a long time.
|
|
|
|
|
it might be easier to add
ShowScrollBar(SB_VERT);
to the
void CEditTime::PreSubclassWindow()
method than modifying the resource file
//////////////////////////////////////////////////////////////////
void CEditTime::PreSubclassWindow()
{
ShowScrollBar(SB_VERT);
SetDateTime(COleDateTimeSpan::GetCurrentTime());
CEdit::PreSubclassWindow();
}
//////////////////////////////////////////////////////////////////
|
|
|
|
|
Thank you. Well worth the 2 minutes to implement in my project.
|
|
|
|
|
Others may have complained a bit, but I have found this code to perfectly suit my needs. I think you're correct in saying that one reason other solutions don't work as well is because they try to encompass too many masks into one control. I've been searching for this tool and I've already seen about 5 to 10 others that just don't work well.
This really was cut-n-paste for those that are asking for the source code. Just create a new class using class wizard called VDateTimeEdit and derive it from CEdit. Add handlers through CW for all of the window messages that are shown in the sample code. Then add the extra methods and properties required for the rest of the class. It takes a whole 3 minutes of time.
Personally, I only wanted the Date portion and not the time. All I had to do was modify the mask string by removing the "hh mm ss" from it in the constructor. The only other thing that felt funny to me was the initial "DD/MM/YYYY" format. Once again, it took only 2 seconds to modify the mask in the constructor from "DD/MM/YYYY" to "MM/DD/YYYY".
This works perfect from me because I use COleDateTime everywhere else in my code. Also, for those of you that didn't notice from the code, up and down arrows are handled to automatically increment/decrement the date/time that the cursor is at, and it actually works as expected. You can still select all of the text with a mouse AND with the keyboard (many others don't allow that).
Thank you very much. Good, Simple, Efficient!
|
|
|
|
|
Do you have a version of the date/time widget that will work in Visual C++ 1.52 (16 bit) in Win3.1 and
Doesn't use OLE?
Thanks!
Pete
|
|
|
|
|
Why don't you post your source in .h and .cpp format so they can be downloaded? I would think this could be a very helpful class if the documentation was written in a format similar to other articles posted here
|
|
|
|
|
|
General News Suggestion Question Bug Answer Joke Praise Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
|