Link to home
Start Free TrialLog in
Avatar of flynny
flynnyFlag for United Kingdom of Great Britain and Northern Ireland

asked on

restricting edit field in tree control to set number of characters

Hi all,

i have a tree control, which displays some visual information. One of the fields ia a character shotcut associated with the information this is displayed in the format

KEY:M

for example, when the user edits this text, i can strip away the KEY: no problem so that all that remains is the char. the problem is th user can still type as many charatcers as they want and i want to restict this.

i would like to restrict the edit field to be one character. is this possible? also all of these keys will be captial so if a user enters m i would like to convert this to M. how would i do this?

Many thanks for the help
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

If using MFC you can get the edit control by

   CEdit* pEdit = tree.GetEditControl();

Then, you may call functions like CEdit::LimitText to limit the text input given.

>>>> if a user enters m i would like to convert this to M.
You may do that after the the field was changed, e. g. by calling SetItemText. You would need a handler for TVN_ENDLABELEDIT to get notified.

Regards, Alex
Avatar of flynny

ASKER

thats great itsme, this will be exactly what i need. i'm doing something wrong though.

when an edit is detected (i.e. when the rename button is pressed in the tree on an item) i call a mehtod DoLabelEdit. The class I'm using etends CTreeCtrl.

i then create edit control

CEdit* pEdit = GetEditControl();
pEdit.LimitText(1); //it get to here and crashes with an access violation

when it crashes i points me to the AFXWIN2.INL and to the line which reads

{ ASSERT(::IsWindow(m_hWnd)); return (int)::SendMessage(m_hWnd,EM_LIMITTEXT, nChars, 0); }
 
any ideas what the prob could be.

many thanks matt.
>>>> pEdit.LimitText(1);
pEdit is a pointer which must be tested for not being NULL. As far as I remember it is only different from NULL *after* you called DoLabelEdit();  (but I am no sure). To understand why, imagine there is only one edit field for the tree control, initial hidden in some corner all sizes 0. If calling DoLabelEdit() they activate the edit field and move it exactly to match the cell to edit. Got it?

Regards, Alex
>>>> pEdit is a pointer which must be tested for not being NULL

So, the statement actually is

   if (pEdit != NULL)
   {
        pEdit->LimitText(1);  // note the arrow
   }
Avatar of flynny

ASKER

ok i've changed it to this and the pEdit being returned is NULL as its bypassing the LimitText call.
any ideas why?
Avatar of flynny

ASKER

sorry its me i missed the comment above.

so if the edit field is unobtainable before the doeditlabel method is called is there no way i can get hold of it before the edit?
>>>> ASSERT(::IsWindow(m_hWnd));
>>>> when it crashes i points me to the AFXWIN2.INL
I assume you got an 'assertion' rather than a crash. An assertion only happens in debug mode and tells you that a precondition for a system function doesn't apply. Here, it means that the edit window doesn't have a window associated yet. If you get this assertion after you called DoLabelEdit, you may need some delay between DoLabelEdit and SetLimitText cause they may have moved creation of the edit field to some PostMessage activity rather than doing it when you are calling DoLabelEdit. That is bad, cause you would need a delay as well, i. e. you cannot make the LimitText in the current handler function. The fasted would be to setup the OnTimer() handler for that class and invoke a timer instead of calling LimitText:

   if (pEdit != NULL)
   {
          if (!IsWindow(pEdit->m_hWnd))
          {
                SetTimer(99, 100);   // set a timer with id 99 and for next 100 msec
          }
          else
                pEdit->LimitText(1);

   }

in the OnTimer function you would do:

afx_msg void MyDialog::OnTimer(UINT nIDEvent)
{
      if (nIDEvent == 99)
      {
              CEdit* pEdit = m_treeCtrl.GetEditControl();
              if (pEdit != NULL && IsWindow(pEdit->m_hWnd))
              {
                  pEdit->LimitText(1);
                  KillTimer(99);
              }  
               /* else the timer would try again */
       }
}

Note, the SetTimer was called in the context of the dialog or view rather than from the tree control. If you are in a handeler of the tree control you may get your parent class and do the above in a member function of that class.

          MyDialog* pParent = (MyDialog*)GetParent();
          if (pParent != NULL)
               pParent->setupTreeEditControl();

>>>> is there no way i can get hold of it before the edit?
Actually if you call DoLabelEdit the edit is only created. So you can set the LimitText after calling DoLabelEdit without any problem (cause the user needs at least 1 second before typing any text). The only problem would be if the pEdit is not a valid window *after* if you caleld GetEditControl after DoLabelEdit. Then, you need the timer solution.
>>>> cause the user needs at least 1 second before typing any text
The real reason is that as long as you are in a handler function no other message was processed. So, the pEdit->LimitText would happen prior to handling any WM_KEYDOWN/WM_CHAR/WM_KEYUP message.
Avatar of flynny

ASKER

hi itsme,

ok i'm trying to add the timer however its saying that

error C2660: 'SetTimer' : function does not take 2 parameters

heres what i've done, in my CEditTreeCtrl . h file i have added the afx_msg

afx_msg void OnEditTimer(UINT nIDEvent);

and in my beginlabeledit funci call

SetTimer( 99, 100 );  

with the function

afx_msg void CEditTreeCtrl::OnEditTimer(UINT nIDEvent)
{
      if (nIDEvent == 99)
      {
            CEdit* pEdit = CTreeCtrl::GetEditControl();
             
            if (pEdit != NULL && IsWindow(pEdit->m_hWnd))
        {
                  pEdit->LimitText(1);
                  KillTimer(99);
        }  
        /* else the timer will try again */
      }
}

am i doing somehing wrong here? i've tried adding in a hwnd and callbak too but with no luck. any ideas?

thanks matt.

Avatar of flynny

ASKER

ok if i set the third param to NULL, then it compiles however (after adding break points to the timerfunc) it doesn't triggerr the timer?
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of flynny

ASKER

hi its me doing it this way gives the error

error C2664: 'SetTimer' : cannot convert parameter 3 from 'void (unsigned int)' to 'void (__stdcall *)(struct HWND__ *,unsigned int,unsigned int,unsigned long)'

do i need to use the following?

void CALLBACK MyTimerProc(

HWND hwnd,

UINT uMsg,

UINT idEvent,

DWORD dwTime )