We help IT Professionals succeed at work.

restricting edit field in tree control to set number of characters

flynny
flynny asked
on
356 Views
Last Modified: 2013-11-20
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
Comment
Watch Question

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

Author

Commented:
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
   }

Author

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

Author

Commented:
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.

Author

Commented:
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.

Author

Commented:
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?
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Author

Commented:
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 )

Gain unlimited access to on-demand training courses with an Experts Exchange subscription.

Get Access
Why Experts Exchange?

Experts Exchange always has the answer, or at the least points me in the correct direction! It is like having another employee that is extremely experienced.

Jim Murphy
Programmer at Smart IT Solutions

When asked, what has been your best career decision?

Deciding to stick with EE.

Mohamed Asif
Technical Department Head

Being involved with EE helped me to grow personally and professionally.

Carl Webster
CTP, Sr Infrastructure Consultant
Empower Your Career
Did You Know?

We've partnered with two important charities to provide clean water and computer science education to those who need it most. READ MORE

Ask ANY Question

Connect with Certified Experts to gain insight and support on specific technology challenges including:

  • Troubleshooting
  • Research
  • Professional Opinions
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.