• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 337
  • Last Modified:

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
0
flynny
Asked:
flynny
  • 7
  • 6
1 Solution
 
itsmeandnobodyelseCommented:
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
0
 
flynnyAuthor 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.
0
 
itsmeandnobodyelseCommented:
>>>> 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
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
itsmeandnobodyelseCommented:
>>>> 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
   }
0
 
flynnyAuthor Commented:
ok i've changed it to this and the pEdit being returned is NULL as its bypassing the LimitText call.
any ideas why?
0
 
flynnyAuthor 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?
0
 
itsmeandnobodyelseCommented:
>>>> 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();

0
 
itsmeandnobodyelseCommented:
>>>> 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.
0
 
itsmeandnobodyelseCommented:
>>>> 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.
0
 
flynnyAuthor 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.

0
 
flynnyAuthor 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?
0
 
itsmeandnobodyelseCommented:
>>>> CEditTreeCtrl::OnEditTimer

make the OnEditTimer a static function and pass it with the SetTimer

   SetTimer(99, 100, CEditTreeCtrl::OnEditTimer);

It looks like your function is not using member data, so turning it to a static is no problem.

If you pass a NULL for the callback, the OnTimer function of your dialog would be called in case you would add the handler by using class wizard.
0
 
flynnyAuthor 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 )
0

Featured Post

[Webinar] Kill tickets & tabs using PowerShell

Are you tired of cycling through the same browser tabs everyday to close the same repetitive tickets? In this webinar JumpCloud will show how you can leverage RESTful APIs to build your own PowerShell modules to kill tickets & tabs using the PowerShell command Invoke-RestMethod.

  • 7
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now