TRichTextBox – A universal RichTextBox which can display animated images and more

AID: 4189
  • Status: Published

7770 points

  • Bytrestan
  • TypeGeneral
  • Posted on2010-12-02 at 13:41:59
Awards
  • Community Pick
  • Experts Exchange Approved

Summary

Displaying images in RichTextBox is a common requirement with limited solutions available. Pasting through clipboard or embedding into RTF content only support static images.  This article describes how to insert Windows control objects into a RichTextBox and use them to host images.  It is a straightforward -- but flexible and usable -- solution.   An attached demo project shows a simple example of the result:
demo3.PNG
  • 40 KB
  • Demo -- shows images in an IM chat box
Demo -- shows images in an IM chat box


Introduction


Quite often here at EE, I come across questions about how to insert images into a RichTextBox.  Especially for developers working with Instant Messaging (IM) projects, emotion icons are inevitable elements besides handling chat text messages.  A crying picture sounds much louder than pale text like “I’m crying” “I want to cry.”  However, RichTextBox is basically the only choice left for the programmers, unless you write your own reader or browser.  Using a web browser control is actually not a bad option. We may discuss it in the following articles (but not this one).

There are two "standard" ways of displaying static images in a RichTextBox.  The CodeProject article, Insert Plain Text and Images into RichTextBox at Runtime, describes two ways of implementation in much detail:
 
  • Copying an image to the clipboard and pasting the data into target RichTextBox.
  • Reading the RTF specification and inserting image data through metafile wrapped with RTF tags.

Molesting the content of clipboard is really annoying and not good programming practice.  For example, I’m used to copying words as a backup while typing, and I'll definitely copy the whole article again before I post it to a forum.  In case anything goes wrong, I have the clipboard as an emergency backup tool.

Actually it’s trivial to restore the original clipboard data after pasting the image and a responsible developer should do it:
public void InsertImage()  {
  ...
  string lstrFile = fileDialog.FileName;
  Bitmap myBitmap = new Bitmap(lstrFile);

//keep the clipboard data before set image in it.
  object orgData = Clipboard.GetDataObject

  Clipboard.SetDataObject(myBitmap);

  DataFormats.Format myFormat = DataFormats.GetFormat (DataFormats.Bitmap);

  if(NoteBox.CanPaste(myFormat)) {
    NoteBox.Paste(myFormat);
  }
  else {
    MessageBox.Show("The data format that you attempted site" + 
      " is not supportedby this control.");
  }
//Restore the original data.
Clipboard.SetDataObject(orgData )
  ...
}
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:

Select allOpen in new window



The fatal problem of both of the above solutions is that they disable the animation of a GIF image.  An animated GIF file contains multiple frames of images. “Copy&Paste” just reads the first frame of the image so the animation stops.  While “RTF tagging” transforms the image data into a huge string and the RTF specification does not extend enough to support getting the next active frame from a string.


Insert Windows Controls


Picture boxes can display animated images.  And a user control can contain other controls. So ther is nothing unconventional about inserting controls into a RichTextBox for any possible purpose. There are two issues that need to be addressed before it would be working:

  • First, an inner control stays still in the parent control, and...
  • Second, the input text will go behind the control instead of wrapping around it.

We need to make inner controls move along with the text while the RichTextBox is scrolling, and we need to leave enough space for the inner controls to prevent overlapping -- and covering up the nearby text as shown here:
demo1.PNG
  • 88 KB
  • PictureBox covers text
PictureBox covers text

To resolve the above issues, the start point of the text can be used as a reference point to decide the control’s position relative to the text.  When the content moves from PosA to PosB, the PictureBox must also move to a new position as well, which is easily calculated:

    thePictureBox.newPosition = PosB – PosA + thePictureBox.oldPosition = PosB – Delta
demo2.PNG
  • 35 KB
  • Re-position the embedded control
Re-position the embedded control

The RichTextBox.GetPositionFromCharIndex method allows us to retrieve the beginning position (PosA) of the text with character index of zero.  We need to store this value and, in the VScroll event, use the same method to retrieve the new start position (PosB) of the text. Then we can set the new position of the inner controls.

The call to GetPositionFromCharIndex is a little expensive.  Consider that tens or even hundreds of images could be inserted into the RichTextBox during a session of chat, so frequent calls to the function would make scrolling very sluggish.  

An alternative call to get the new position is a Win32 API GetScrollPos(). In most cases, the value obtained from GetScrollPos() is almost exactly the negated value to the one coming from GetPositionFromCharIndex... with a couple of points differentiation, which makes no difference to the naked eye.  However, further tests reveal that the number returned from GetScrollPos() does not change if the user clicks on the slider bar and drags.  The new position value can only be retrieved after the user releases the mouse button.  So the pictures do not move while scrolling and then they fly to the new positions only after the scrolling stops. We have to send messages to notify the position change while dragging.  So we must add some more coding logic.  Finally the call to get the position in VScroll is:
private void TRichTextBox_VScroll(object sender, EventArgs e)
    {
        Point pt = new Point();
        SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref pt);

        foreach (MetaInfo one in ControlList)
        {
            one.TheControl.Location = new Point(one.TheControl.Location.X, -pt.Y - one.DeltaY);
        }
    }
                                    
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

Select allOpen in new window



Using the Code


All the deductive procedure is to make using the ttechnique easy and simple.  Firstly, derive your RichTextBox from TRichTextBox, in Form1.Designer.cs:
private Trestan.TRichTextBox richTextBox1;
this.richTextBox1 = new Trestan.TRichTextBox();
                                    
1:
2:

Select allOpen in new window


Secondly, wherever you need to use a PictureBox to display image, simply call richTextBox1.AddControl to add it in the list:

PictureBox thePic = new PictureBox();
                    thePic.Image = theImage;
                    thePic.Size = theImage.Size;
                    this.richTextBox1.AddControl(thePic);
                                    
1:
2:
3:
4:

Select allOpen in new window


That’s it! TRichTextBox takes care everything else for you.


Bonus / Notes


  • GDI+ seems more delicate than GDI functions. Some images can be loaded by GDI functions but will crash in GDI+. So a simple sanity check is called before setting the image to PictureBox, in which multiple frames are read one by one and the image will be discarded if any exception is caught.

  • A self-management function RemoveSome(), which will automatically truncate messages received in earlier time using the length of text and number of images received as thresholds.

  • Most interestingly, you are not limited to add only PictureBox controls into a TRichTextBox, you can insert virtually any kind of controls into it. And they will all scroll with the text as an integrated part of content. As illustrated in the following picture, a button is affixed to each line of message. Thus the TRichTextBox gains more potential to become a client side reader, in a P2P forum with no centralized website.

Final result:
demo3.PNG
  • 40 KB
  • Demo -- shows images in an IM chat box
Demo -- shows images in an IM chat box


Attachment

This is the demo project that contains the TRichTextBox code and an example of usage.
    Asked On
    2010-12-02 at 13:41:59ID4189
    Tags

    RichTextBox animated image

    Topic

    Microsoft Visual C#.Net

    Views
    2618

    Comments

    Add your Comment

    Please Sign up or Log in to comment on this article.

    Join Experts Exchange Today

    Gain Access to all our Tech Resources

    Get personalized answers

    Ask unlimited questions

    Access Proven Solutions

    Search 3.2 million solutions

    Read In-Depth How-To Guides

    1000+ articles, demos, & tips

    Watch Step by Step Tutorials

    Learn direct from top tech pros

    And Much More!

    Your complete tech resource

    See Plans and Pricing

    30-day free trial. Register in 60 seconds.

    Loading Advertisement...

    Top Visual C# Experts

    1. kaufmed

      39,306

      0 points yesterday

      Profile
      Rank: Genius
    2. JamesBurger

      29,150

      0 points yesterday

      Profile
      Rank: Sage
    3. CodeCruiser

      16,200

      0 points yesterday

      Profile
      Rank: Genius
    4. AndyAinscow

      13,836

      0 points yesterday

      Profile
      Rank: Genius
    5. nishantcomp2512

      13,260

      0 points yesterday

      Profile
      Rank: Wizard
    6. emoreau

      8,800

      0 points yesterday

      Profile
      Rank: Genius
    7. jonnidip

      7,868

      0 points yesterday

      Profile
      Rank: Master
    8. Idle_Mind

      7,162

      0 points yesterday

      Profile
      Rank: Savant
    9. mas_oz2003

      6,750

      0 points yesterday

      Profile
      Rank: Genius
    10. Sudhakar-Pulivarthi

      6,532

      0 points yesterday

      Profile
      Rank: Guru
    11. Michael74

      6,018

      0 points yesterday

      Profile
      Rank: Wizard
    12. RolandDeschain

      6,000

      0 points yesterday

      Profile
      Rank: Sage
    13. ddayx10

      5,300

      0 points yesterday

      Profile
      Rank: Sage
    14. apeter

      5,232

      0 points yesterday

      Profile
      Rank: Sage
    15. TheLearnedOne

      5,000

      0 points yesterday

      Profile
      Rank: Savant
    16. navneethegde

      5,000

      0 points yesterday

      Profile
      Rank: Wizard
    17. mroonal

      4,900

      0 points yesterday

      Profile
      Rank: Sage
    18. naman_goel

      4,664

      0 points yesterday

      Profile
      Rank: Guru
    19. AhmedHindy

      4,500

      0 points yesterday

      Profile
    20. mlmcc

      4,000

      0 points yesterday

      Profile
      Rank: Savant
    21. UndefinedException

      4,000

      0 points yesterday

      Profile
    22. ged325

      3,468

      0 points yesterday

      Profile
      Rank: Genius
    23. keyu

      3,400

      0 points yesterday

      Profile
      Rank: Master
    24. nilhan

      3,200

      0 points yesterday

      Profile
    25. SStory

      3,136

      0 points yesterday

      Profile
      Rank: Sage

    Hall Of Fame