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

How to Limit no. of characters per line in Multi Line Edit box

I have a requirement that to limit no. of character per line to 64 in each line of Multi Line edit box using MFC.  I started using Call back procedure EDITWORDBREAKPROC to override the editbox word break behaviour.  Horizontal scrollbar is required. Can any body send me the sample code for the requirement?
0
rk2611
Asked:
rk2611
  • 8
  • 7
  • 3
1 Solution
 
mahesh1402Commented:
If you get this two long lines in the edit control - do you see a horizontal scroll bar ?
If it is so, remove the ES_AUTOHSCROLL style from your window creation style list. You may use ModifyStyle() for this.

Also, see the following text from MSDN:

Handling Word Wrap
-----------------------------
An application can use word wrap functions with multiline edit controls to locate the word or word fragment that should be wrapped to the next line.
Using the default word wrap function provided by the system, lines always end at the spaces between words.
An application can specify its own word wrap function by supplying a EditWordBreakProc word wrap function and sending an edit control an EM_SETWORDBREAKPROC message.

An application can retrieve the address of the current word wrap function by sending the control an EM_GETWORDBREAKPROC message.

An application may direct a multiline edit control to add or remove a soft line break character (two carriage returns and a linefeed) automatically at the end of wrapped text lines. An application can turn this feature on or off by sending the edit control an EM_FMTLINES message. This message applies only to multiline edit controls and does not affect a line that ends with a hard line break (one carriage return and a linefeed entered by the user).

-MAHESH
0
 
mahesh1402Commented:
My suggestion is Just do *not* use ES_AUTOHSCROLL style.

-MAHESH
0
 
rk2611Author Commented:
Thanks for your comment.  If I turned off  'AUTO HScroll' property of the edit box from dialog properties, I may not limit exact no. of characters per line.  It's depend on the size of the edit box & max. no. of characters allowed may not be same in all lines (because it's depend on the character width).  Pls. give me comment on my openion.
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
mahesh1402Commented:
what about using EM_SETLIMITTEXT ? CEdit::SetLimitText()...

You'd need to implement something like that yourself - handle the EN_UPDATE message (OnUpdate handler), use GetWindowText to get the current (yet to be displayed text), do your checking and if it violates your limits, change the text to the last known good text in the control.

-MAHESH
0
 
mahesh1402Commented:
EM_LIMITTEXT ( CEdit::LimitText)

-MAHESH
0
 
rk2611Author Commented:
I have added the following code in OnUpdate command handler of Edit box.  When user enters 65th character, new line break character inserted beween 64th and 65the character & carrot position is moved to next line automatically.  I am using SetSel & ReplaceSel() to insert line break character. This is working fine  at the time of inputting characters.  The problem is that when user deletes the end characters in the line, the carrot position is moved to unknown position.  This is causing a problem to me.


  int lintLineCount = 0;
  int lintStartPos = 0;
  int lintEndPos = 0;
  int lintLineLength = 0;
  int lintMaxChars = 10;
  int lintTotChars = 0;
 
  CString lstrLine;
  CString lstrText;
  CString lstrTemp;
  lintLineCount = mCAnnotationEdit.GetLineCount();
  CString lstrFull = _T("");
  if (lintLineCount > 0 ) {
    for (int k = 0; k <lintLineCount; k++) {
      lintLineLength =
      mCAnnotationEdit.LineLength(mCAnnotationEdit.LineIndex(k));
      lintStartPos = mCAnnotationEdit.LineIndex(k);
      lintEndPos =  lintStartPos + mCAnnotationEdit.LineLength(lintStartPos);

        if (lintLineLength > lintMaxChars ) {
          mCAnnotationEdit.GetLine
            (k,lstrLine.GetBuffer(lintLineLength),lintLineLength);
          lstrLine.ReleaseBuffer(lintLineLength);
          lstrText.Format("%s",lstrLine);
          lintTotChars = lstrText.GetLength();
          lstrTemp = lstrText.Right(lintTotChars - lintMaxChars);
          lstrText = lstrText.Left(lintMaxChars);
          LPTSTR  lpStrline = new TCHAR[lstrText.GetLength() + 1];
          _tcscpy(lpStrline, lstrText);
          lstrText = lpStrline;
          if (lstrTemp.GetLength() > 0 ) {
            lstrText += "\r\n" + lstrTemp;
          }
          else {
            lstrText += "\r\n";
          }
         
          mCAnnotationEdit.SetSel(lintStartPos, lintEndPos);
          mCAnnotationEdit.ReplaceSel(lstrText);
          delete lpStrline;
        }
    }
  }

Appreciate if you can give a immediate solution to this problem.
0
 
mahesh1402Commented:
So cant you control that using GetCarotPos() / SetCarotPos() functions ???

-MAHESH
0
 
mahesh1402Commented:
ALSO if you found SetCaretPos is not appropriate then to move the caret, use the SetSel function and specify the same position for both the start and end parameters. This moves the text insertion point, and repositions the caret.

-MAHESH
0
 
rk2611Author Commented:
It is not worked out.  At the the time of insertion of characters, the carot position should be at end of last input character.  But, the at the time of deleting characters, the carror position should remain at the same position.  This I am not able to differentiate.  You can check the above sample code & suggest me for any solution.
0
 
mahesh1402Commented:
but cant you set caret position forcefully using SetCaretPos when you delete characters by retrieving caret position and if its not at end then setting it forcefully..

-MAHESH
0
 
rk2611Author Commented:
I can not differenitate whether we are deleting a character or inputting a character.  At the time of deleting a last character of line, characters in the next line is shifted to first line. New line character is inserted again in this case.  But, at the time of inputting a character, carrot position is on the next line.  At the time of deleting a character,the carrot position should remain on the position.  We cannot differentiate.  You may try in the sampel application with above code in OnChange event.
0
 
mahesh1402Commented:
>>I can not differenitate whether we are deleting a character or inputting a character

I think its good to derive your own Edit control from CEdit and respond to events accordingly..

-MAHESH
0
 
rk2611Author Commented:
Is thery any simple method that we can limit 64 characters per line?  Can we override any call back function EM_SETWORDBREAKPROC to get this functionality?  I don't know how to use call back function. Pls. help me.
0
 
DanRollinsCommented:
I looked at adding a WordBreakProc, but it only gets called when the edit control thinks it needs to break a line.  And it only thinks that when the displayed characters won't fit
and that's a problem becasue of proportional fonts (66 of each below):
   iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
   MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
Thus, it won't get called in the line of i's but will on the line of Ms.

NOTE: If you con't mind using a fixed-width font (such as Courier) then this might be a valid approach.  Let me know.

Here is my first pass at how to handle it via an OnUpdate handler.  I'm out of time right now, but test this out and let me know where it needs improvment:

void CD20Dlg::OnUpdateEdit1()
{
      int nStartPos, nEndPos;
      m_ctlEdit.GetSel( nStartPos, nEndPos );

      int nLineNum= m_ctlEdit.LineFromChar(-1); // current line
      int nLineLen= m_ctlEdit.LineLength(-1);   // current line
      int nLineIdx= m_ctlEdit.LineIndex(-1);    // pos of start of current line
      
      if ( nLineLen > 65 ) {
            char szBuf[100];
            int nBrkAt;
            
             int nLen= m_ctlEdit.GetLine( nLineNum, szBuf, sizeof(szBuf) );
            szBuf[nLen]='\0';

            for (int j=nLen-1; j>0; j-- ) {  // find a space so we can break the line
                  if ( szBuf[j]== ' ') {
                        nBrkAt= nLineIdx + j;
                        break;
                  }
            }
            if ( nBrkAt == -1) {
                  nBrkAt= nLineIdx + 64;  // start of cur line + 64
            }
            m_ctlEdit.SetSel( nBrkAt, nBrkAt );
            m_ctlEdit.ReplaceSel("\r\n", TRUE );
            m_ctlEdit.SetSel( nStartPos, nEndPos );
      }
}

-- Dan
0
 
rk2611Author Commented:
I have tested the above code.  I found some issues in the above code.

a) when user entered 65th character in the line, the 65th character is moving to next line. But, carrot position is still at the end of the previous line.  Usually, cursor should also move to next line and at the end of the character,

b) But, when user delete end character from the line, the carrot position should remain at the same position.

In above my code, (b) is not working.  In your code, (a) is not working.  Pls. suggest me.
0
 
DanRollinsCommented:
This version seems to do the trick.  

Note that the settings for my edit control include:
   Multiline
   Auto HScroll
   Vertical Scroll
   Auto VScroll
   Want Return
It may not work the same with other settings.

void CD28Dlg::OnUpdateEdit1()
{
      static BOOL fBusy= FALSE;
      if ( fBusy ) {
            return;
      }
      fBusy= TRUE;
      
      int nStartPos, nEndPos;
      m_ctlEdit.GetSel( nStartPos, nEndPos );

      int nLineNum= m_ctlEdit.LineFromChar(-1); // current line
      int nLineLen= m_ctlEdit.LineLength(-1);   // current line
      int nLineIdx= m_ctlEdit.LineIndex(-1);    // pos of start of current line
      int nPosOnLine= nStartPos-nLineIdx;

      if ( nLineLen > 65 ) {
            char szBuf[100];
            int nBrkAt= -1;

            int nLen= m_ctlEdit.GetLine( nLineNum, szBuf, sizeof(szBuf) );
            szBuf[nLen]='\0';

            for (int j=nLen-1; j>0; j-- ) {  // find a space so we can break the line
                  if ( szBuf[j]== ' ') {
                        nBrkAt= nLineIdx + j;
                        if (j < 64) {
                              break;
                        }
                  }
            }
            if ( nBrkAt == -1) {
                  nBrkAt= nLineIdx + 64;  // start of cur line + 64
            }
            m_ctlEdit.SetSel( nBrkAt, nBrkAt );
            m_ctlEdit.ReplaceSel("\r\n", FALSE );

            if ( nPosOnLine>65) {  // if cursor was at the end...
                  nStartPos= nEndPos += 2;
            }
            m_ctlEdit.SetSel( nStartPos, nEndPos );
      }
      fBusy= FALSE;
}
0
 
rk2611Author Commented:
Thanks for your suggestion.  It is working fine...
0
 
DanRollinsCommented:
Glad to help.  Thgaks for the points and the grade :-)

BTW, When I was working on this, I found that a self-limiting line-length worked best when using a fixed-width font in the Edito Control.    It is more intuitive for the user... as he gets near the end of the window, he will tend to press Enter to start a new line -- and thus not be interrupted by an "unexpected" forced line wrapping.  With variable-width fonts, it is hard to know that you are nearing the max as you type.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Windows 7 Basic

This introductory course to Windows 7 environment will teach you about working with the Windows operating system. You will learn about basic functions including start menu; the desktop; managing files, folders, and libraries.

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