I've always had a fascination with graphics applications that allow you to twist and manipulate text and images—not so much from the end-user perspective, but more from the angle of a programmer who's always seen this type of programming as near-guru level. To that end, my previous few articles have focused on the GDI+ engine, which essentially makes many tasks such as rendering 3D text more accessible to those of us who don't have either the time or the inclination to become gurus in the world of graphics programming.
This article brings to a close this mini-series on text-manipulation via GDI+ by illustrating how to use the TranslateTransform and ScaleTransform methods of the Graphics class to draw reflected text.
Steps for Drawing Reflected Text
First, implement a handler for the PictureBox control's Paint method. Whenever you need to display new text, simply call the PictureBox control's Invalidate method, which in turn calls its paint method. The following steps and code refer to work within the paint method.
Note: The first few steps are the same as those in previous articles, as they pertain to tasks that are common to any text drawing. These tasks include obtaining a presentation space to draw on, instantiating a font object, measuring the text to display, and so on. I describe these steps here again because I don't want assume that the reader has read all of the articles in this series. If you have read those articles, simply skip to Step #5, where the commonality between most of the examples ends.
- Obtain the Graphics object for the picture control.
You could acquire this object via the PictureBox object's CreateGraphics method. However, that Graphics object would be volatile in that it would be collected by the GC (Garbage Collector) when the object goes out of scope. Therefore, you need to use the Graphics object that is passed to the Paint method (via the PaintEventArgs::Graphics member):
Graphics* g = e->Graphics;
- Instantiate the Font object based on the user-supplied font size.
This application uses hard-coded values for the font typeface (Times New Roman) as well as the font size (40) and style (regular):
System::Drawing::Font* font = new System::Drawing::Font("Times New Roman", 40, FontStyle::Regular);
- Obtain the size of the text to be rendered.
As discussed in a previous article, the Graphics::MeasureString method is a convenient method for measuring a string, given the presentation space in which you will draw it and the font that you will use:
SizeF textSize = g->MeasureString(textToDisplay, font);
- Clear the PictureBox Box control.
Initialize the PictureBox control using the PictureBox::Clear method and specifying the desired color. Here, I use a hard-coded value of Color::White simply because it's easier to view the demo's black and gray text on a white background:
- Calcualte where the text will be rendered on the PictureBox control.
Here, you need to determine the x and y coordinates of the text you will draw. I center the text horizontally, so that's pretty self-explanatory. However, to ensure that the totality of both the original and reflected strings (and not just the first string) is centered, vertically I need to multiply the text's height by 1.5:
Single x = (picText->Width - textSize.Width) / 2; Single y = (picText->Height - (textSize.Height*1.5)) /2;
- Prepend the translation to the transformation matrix of the PictureBox control.
Shortly, you'll need to scale the Graphics so that the reflected text is drawn inverted. However, scaling affects the entire graphics object, not just the text you wish to render. Therefore, you need to reposition the origin of the Graphics object (normally based at 0,0) to the x,y location where you wish to draw the text: