Link to home
Start Free TrialLog in
Avatar of lisab
lisab

asked on

CRichEditCtrl & Fast Parsing

I have created an ActiveX control that's an MFC Doc/View Rich Edit Control. I need to add color to the text as it is displayed to highlight syntax, keywords, etc. I can fairly quickly handle files up to 32K or so but beyond that it is as slow as molasses. So my question is...
How can I speed this up prior to displaying it?


I've tried a worker thread without much/any speed improvements.
I've tried the EDITSTREAM callback figuring that I could modify the StreamIn text prior to display. Unfortunately the callback is never executed (I'm missing something there)

I really can't use a 3rd party one since I need to add some specific bells & whistles not found in any I've reviewed.

Thanks in advance,
Lisa
Avatar of mikeblas
mikeblas

When you ran your application under the profiler, what exactly was the slow part?

Your own parsing? Only you can help yourself there.

You mentioned throwing a thread at the problem. Why did you expect that to help? Is your code I/O-intensive?

If you don't pass the right parameters to EDITSTREAM, the stream functions will return errors and your streaming functions won't be called. If you show your code, maybe I can spot your error. This is by far the fastest way to stream in (or out) the content of a rich edit control.

But if you're working line-by-line, you probably want to use SetSel() to append your new text to the end of the control. If you're taking this approach, then you'll also want to make sure you have turned off redraw for the duration of your replacement and formatting.

Unfortunately, I've had to provide a shotgun answer because your question is too vague to give a specific response.

B ekiM


?sdrawkcab eman ruoy si yhW
niarB

(^:

Avatar of lisab

ASKER

I have not run it under Profiler, I will, however I think the problem lies in SetSelectionCharFormat. If I comment this line out my parsing runs significantly faster. (Except no text color change which is critical)

::ZeroMemory(&cf, sizeof(cf));            
cf.cbSize = sizeof(cf);
cf.dwMask = CFM_COLOR;            
cf.crTextColor = RGB(245, 0, 0);
dwFlags = NULL;
            
_tcscpy (pFT.lpstrText, "//");
pFT.chrg.cpMin = *cpMin;
pFT.chrg.cpMax = *cpMax;
dwFlags = NULL;
nIndex = -1;
do  //search for "//" comments
{      
      nResult = theCtrl.FindText(dwFlags, &pFT) ;
      if (nResult != -1)
      {//advance to the end of the line
            nIndex = theCtrl.LineIndex (theCtrl.LineFromChar (nResult) + 1) - 1;
            theCtrl.SetSel(nResult, nIndex);
            theCtrl.SetSelectionCharFormat(cf);
            pFT.chrg.cpMin = nIndex;
      }
}while (nResult != -1);

Yes, it is my own parsing. For comments I'm using the approach above, for keywords I build a string list of keywords and search for each word in the file. If you have an alternative suggestion that would be great.  Would searching this text as CString instead of Rich Edit work any faster?

Parsing a giant CString was my next approach. I could not get the EditStreamCallback to work at all. I could find no useful documentation on this function so I copied code from ?VIEWRICH.CPP? My callback is never executed so apparantly this is incorrect. It looks as follows:

EDITSTREAM es = {0, 0, EditStreamCallBack};
_afxRichEditCookie cookie(ar);
es.dwCookie = (DWORD)&cookie;
GetRichEditCtrl().StreamIn(nFormat, es);


I tried the thread to enable me to parse part of a large file, allow the user to edit his code and continue parsing in a thread. I know this isn't a great solution, but I could not improve the parsing and couldn't get the editstream callback to work. Desparate, I know.

Thanks for your help.
Lisa
Avatar of lisab

ASKER

Update:

I modified all my parsing code to use ::SendMessage for updating the rich edit ctrl. This is significantly faster, but still not the light speed I was hoping for. Any ideas?

Lisa

::ZeroMemory(&cf, sizeof(CHARFORMAT));            
      cf.cbSize = sizeof(cf);
      cf.dwMask = CFM_COLOR;            
      cf.crTextColor = RGB(245, 0, 0);
      dwFlags = FR_DOWN;
            
      _tcscpy (pFT.lpstrText, "//");
      pFT.chrg.cpMin = *cpMin;
      pFT.chrg.cpMax = *cpMax;
      dwFlags = NULL;
      nIndex = -1;
      CHARRANGE cr;
      do  
      {      
            //nResult = theCtrl.FindText(dwFlags, &pFT) ;
            nResult = ::SendMessage(m_hWnd, EM_FINDTEXTEX, dwFlags, (LPARAM)&pFT);
            if (nResult != -1)
            {
                  cr.cpMax =  (long)::SendMessage(m_hWnd, EM_EXLINEFROMCHAR, 0, nResult);
                  cr.cpMax = ((long)::SendMessage(m_hWnd, EM_LINEINDEX, cr.cpMax + 1, 0)) - 1;
                  cr.cpMin = nResult;
                  ::SendMessage(m_hWnd, EM_EXSETSEL, 0, (LPARAM)&cr);
                  ::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);
                  pFT.chrg.cpMin = cr.cpMax;
            }
      }while (nResult != -1);
> Would searching this text as CString
 > instead of Rich Edit work any faster?

Yes.  Using the RichEdit control for syntax colouring is not a great idea; it's just not designed for that kind of high-bandwidth formatting. Visual C++ (and the other Visual Studio editors) do their syntax colouring with a window that's painted from scratch.

If you don't have time to develop such a window, you can make a run at it with Rich Edit. In the loading phase (which is what I guess you're talking about here, because you've written code to parse the whole file) you'll want to load your file into memory. There, you should parse it and fluff it into an actual RTF stream.  Then, you can use stream in to load that buffer into the rich edit control.

As the user changes the content of the control, you can reparse the line(s) surrounding their change and use the selection formatting.

Using that approach, I think you'll realize the best performance.

That you've noticed a speedup by switching to ::SendMessage() calls makes no sense to me. For the calls you show in the code you've posted here, MFC supplies inline functions that do, exactly, a ::SendMessage().  Are your observations based on a release build or a debug build?

You really need to use the profiler to identify the hot-spots in your code.

B ekiM


ASKER CERTIFIED SOLUTION
Avatar of mikeblas
mikeblas

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 lisab

ASKER

Thanks for the help, Mike. It is much appreciated.

Lisa