Sample files are available as part of the file nov98.zip from our Web site. Visit www.zdjournals.com/cpb and click the Source Code hyperlink.
If you've ever used a Rich Edit component, you've no doubt been impressed with its visual appeal. You can display characters in different fonts and paragraphs with varied indentations. And, most of this functionality is hidden, so you needn't know anything about the rich text format (RTF) layout to make good use of it.
That's an advantage if you're concerned only with displaying your text. However, what if your application requires that you gain access to the underlying formatted text--for instance, to copy formatted text to another component, or to send an RTF string out a socket or port? You'll find that this hidden functionality becomes a disadvantage.
In this article, we'll show you how to directly access the formatted text of a TRichEdit component. We'll also discuss the marriage between the TRichEdit VCL component and the underlying Rich Edit common control provided by Windows. (Throughout this article, we'll use the terms component and common control to differentiate between the TRichEdit component and the Windows Rich Edit common control.)
This is some formatted text...
all you get back from a method like GetSelTextBuf() is:
This is some formatted text...
In fact, all the methods and properties of TRichEdit that have the word text in their titles operate the same way. You may then turn to TRichEdit's Lines property, which is a TStrings* type. Knowing that the text of the Rich Edit control is stored there, you may try code like
String s = RichEdit1->Lines->Text;to pull out all the rich-edit text at one time. Again, you'll find that only the plain text is returned. So, what's the deal with hiding the RTF characters? Now, you've discovered the disadvantage of the Rich Edit common control provided by Windows.
Figure A: This example program demonstrates using the TRichEdit component.
We've included buttons that let you copy text from one TRichEdit component to another. Notice the three groups of buttons: one group copies RTF text using the Clipboard's functionality, one copies RTF text using streams, and the third copies plain text using the TRichEdit component's properties and methods.
We've already discussed the two buttons for transferring plain text. The other buttons represent the means to access the underlying RTF text in a Rich Edit common control via the Clipboard and via streams.
Since the TRichEdit component is a wrapper around the Rich Edit common control, it contains methods that make direct use of the common control's Clipboard functions. It should be no surprise that the easiest way to transfer RTF text from one TRichEdit component to another is through the Clipboard. Listing A shows the simple code in the Rich Via Clipboard Copy All button's event handler. In just a few lines, RTF text is copied and pasted through the clipboard.
Listing A: Copying RTF text via the Clipboard
// The rich edit control registers the following // clipboard formats: CF_RTF and // CF_RETEXTOBJ (rich edit text and objects). RichEdit1->SelectAll(); RichEdit1->CopyToClipboard(); RichEdit2->Clear(); RichEdit2->PasteFromClipboard();The first line in Listing A is required to select all the text in RichEdit1, because the CopyToClipboard() method sends only the selected (highlighted) text to the Clipboard. The third line clears the destination component's contents for aesthetic reasons only.
As you may have guessed, the code for the Rich Via Clipboard Copy Selected button is even simpler, because only the selected text is copied. This code looks like Listing A, minus the line
RichEdit1->SelectAll();Using the Clipboard, you can paste RTF text from your TRichEdit component into other applications that recognize RTF. For example, you could have a Copy button or Edit | Copy menu item that simply executes the single command
RichEdit1->CopyToClipboard()Then, other applications like Write or WordPad can use their Edit | Paste menu item to insert your RTF text. The process can also go the other way--you can paste RTF text from other applications into your TRichEdit component.
RichEdit1->Lines->SaveToFile( filename ); or RichEdit1->Lines->LoadFromFile( filename );Such code is great for disk access--but what about transferring RTF text to other components? There's hope. Just as the SaveToFile() and LoadFromFile() methods use streams to pass formatted data to disk, you can use the SaveToStream() and LoadFromStream() methods of Lines to pass RTF text to a stream (for instance, TMemoryStream). Listing B shows the code we placed in the event handler of our example's Rich Via Stream Copy All button.
Listing B: Copying via streams
// Create a memory stream. TMemoryStream* strm = new TMemoryStream; // Save the rich edit text to the stream. RichEdit1->Lines->SaveToStream( strm ); // Reset to front of stream. strm->Position = 0; // Copy the stream to the other rich edit control. RichEdit2->Lines->LoadFromStream( strm ); // Clean up. delete strm;
| Note: Flaw in using Text |
|---|
| The Help file says that SaveToStream() uses the Text property of Lines to get the RTF text from the TRichEdit component. However, if you use Lines->Text directly, only plain text is returned. Something is going on that isn't explained, but that's beyond the scope of this article. |
Let's look at one last capability. So far, everything we've discussed about transferring RTF text has treated the text as a mysterious RTF object whose insides we didn't have to understand. But, what if you want to get a character buffer of the actual RTF text, so you can look at the special control characters and do some tweaking? Or, what if you want to send the RTF text through a socket or port, but the text must first be in a character-string format?
To get an actual character string of the RTF text, you begin by using a stream, as in the previous example. The only difference is that once the RTF text is saved to the stream, you can call the stream's Read method to read the contents of the stream into a user-provided character buffer. Listing C shows the appropriate code snippet.
Listing C: RTF text-to-character buffer
// Create a memory stream. TMemoryStream* strm = new TMemoryStream; // Save the rich edit text to the stream. RichEdit1->Lines->SaveToStream( strm ); // Reset to front of stream. strm->Position = 0; // Create a temporary character buffer. int bufSize = strm->Size; char* buf = new char [ bufSize + 1 ]; // Copy the stream to the other rich edit control. strm->Read( buf, bufSize ); // Do stuff with the buffer now. . . . // Clean up. delete strm; delete buf;Before we leave our discussion on streams, you'll notice that another button in the Rich Via Stream group--Copy Selected--is disabled. Its operation is left as an exercise for the reader to figure out how to copy only the selected text to (or from) the memory stream. You'll remember that the SaveToStream() method copies the entire TRichEdit contents regardless of what text is selected (highlighted). Sorry, I left you the harder one.