Managed Extensions: Using GDI+ to Render Sheared Text

Welcome to this week's installment of .NET Tips & Techniques! Each week, award-winning Architect and Lead Programmer Tom Archer demonstrates how to perform a practical .NET programming task using either C# or Managed C++ Extensions.

Last month, I wrote a couple of GDI+ articles and quickly found out that the ability to draw text and implement imaging in Visual C++.NET applications is used much more widely than I originally realized. In fact, I've received quite a few requests for more articles on various techniques such as drawing shear text, creating the illusion of reflected text, and so on. Therefore, in this month's first article, I illustrate how easily you can draw shear (or slanted) text using the GDI+ objects.

Steps to Rendering Shear Text

  1. Store the shear parameters.
    This is an issue only if the end-user specifies the values and then invokes the text-rendering process (for example, by clicking a button). This article's accompanying demo works this way. In this case, store these values in a member variable when the user requests that the text be rendered, and then cause the invocation of the PictureBox control's Paint method. Otherwise, if you simply use the form control values in the Paint method, sometimes you'll use values that the user has typed in but hasn't requested to be rendered. In the demo, this code looks like the following (where the btnDisplayText_Click method is an event handler that is called when the user clicks the Display Text button):
    public __gc class Form1 : public System::Windows::Forms::Form
      String* textToDisplay;
      Decimal fontSize;
      Decimal shearSize;
    private: System::Void btnDisplayText_Click(System::Object *
                                               System::EventArgs *
      // Set up internal display values
      textToDisplay = txtToDisplay->Text;
      fontSize      = spnFontSize->Value;
      shearSize     = spnShear->Value;
      // Invalidate the control
  2. Implement a Paint method for the PictureBox control.
    The text will be rendered on the PictureBox control, and implementing a Paint method ensures that the control is repainted when needed—such as when the user switches away from and then back to the application. The following is an example where the conditional statement simply ensures that the user has entered text to be displayed before attempting to use the object (textToDisplay) containing that value:
    private: System::Void picText_Paint(System::Object *  sender,
                                        PaintEventArgs *  e)
      if (textToDisplay)
  3. Note: The remainder of the steps involve code placed in the PictureBox object's Paint method.
  4. Obtain the Graphics object for the picture control.
    You could acquire this object via the PictureBox object's CreateGraphics method. However, because the GC (Garbage Collector) would collect that Graphics object when it goes out of scope, the object would volatile it. Therefore, you need the Graphics object that is passed to the Paint method (via the PaintEventArgs::Graphics member):
    Graphics* g = e->Graphics;
  5. Instantiate the Font object based on the user-supplied font size.
    This application uses a hard-coded font typeface of "Times New Roman," but obviously that's application specific. The following code creates a "Times New Roman" font with a style of "regular" (as opposed to bold) for the size the user specifies:
    System::Drawing::Font* font = 
      new System::Drawing::Font("Times New Roman", 
  6. Obtain the size of the text to be rendered.
    As a previous article discussed, the Graphics::MeasureString method is a convenient method for measuring a string, given the presentation space in which it will be drawn and the font that will be used:
    SizeF textSize = g->MeasureString(textToDisplay, font);
  7. Clear the PictureBox Box control.
    Initialize the PictureBox control by using the PictureBox::Clear method and specifying the desired color. The following code uses the user-defined (via the Display Properties application) value for controls:
  8. Calcualte where the text will be rendered on the PictureBox control.

  9. The following code is used to determine the x and y coordinates for centering the text:
    Single x = (picText->Width  - textSize.Width)  / 2;
    Single y = (picText->Height - textSize.Height) / 2;
  10. Prepend the translation to the transformation matrix of the PictureBox control.
    To scale text, you must scale the entire graphics object. Therefore, you need to first reposition the origin of the Graphics object to the calcualted x and y positions. You accomplished this via the Graphics::TranslateTransform method:
    g->TranslateTransform(x, y);
  11. Retrieve the newly generated transform.
    Once you've generated a "world transformation" for a given Graphics object, it can be retrieved via the Graphics::Transform property. This property returns a Matrix object that is used to shear the text:
    Matrix* transform = g->Transform;
  12. Shear the transform per the user's specified amount.
    The Matrix object has a method called Shear that does what you set out to accomplish. It takes the horizontal and vertical shear factors. The demo specifies only the horizontal shear value (hence the passing of the literal 0 for the second parameter), but both can be specified easily. However, note that the transformation technically is only a true shear if one of these values (either the horizontal or vertical) is set to 0:
    transform->Shear(Convert::ToSingle(shearSize), 0);
  13. Set the Graphic object's Transform to the newly manipulated one.
    Once the local Matrix object has been modified via the Shear method, you need to set the Graphic object's transform to this value:
    g->Transform = transform;
  14. Render the text.
    Now that the PictureBox control's presentation space is set up (via Graphics object), you finally can call the Graphics::DrawString method to render the text:
    g->DrawString(textToDisplay, font, Brushes::Black, 0, 0);

About the Author

Tom Archer - MSFT

I am a Program Manager and Content Strategist for the Microsoft MSDN Online team managing the Windows Vista and Visual C++ developer centers. Before being employed at Microsoft, I was awarded MVP status for the Visual C++ product. A 20+ year veteran of programming with various languages - C++, C, Assembler, RPG III/400, PL/I, etc. - I've also written many technical books (Inside C#, Extending MFC Applications with the .NET Framework, Visual C++.NET Bible, etc.) and 100+ online articles.



  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 23, 2015 The cloud is not just about a runtime platform for your projects – now, you can do your development in the cloud, too. Check out this webcast to learn how the cloud improves your development experience and team collaboration. Join Dana Singleterry, Principal Product Manager for Oracle Dev Tools, as he discusses how to simplify every aspect of the development lifecycle, including requirements gathering, version management, code reviews, build automation, and …

  • Lenovo recommends Windows 8 Pro. "I dropped my laptop getting out of the taxi." This probably sounds familiar to most IT professionals. If your employees are traveling, you know their devices are in for a rough go. Whether it's a trip to the conference room or a convention out of town, any time equipment leaves a user's desk it is at risk of being put into harm's way. Stay connected at all times, whether at the office or on the go, with agile, durable, and flexible devices like the Lenovo® …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date