When you write a typical Windows Forms program, the drawing, effects, and so on of forms and controls are not specifically considered. Why is this? Because by using the . Net Framework, developers can drag a series of controls onto a form and write some simple code associated with the event and then press F5 in the IDE, and a complete form program is born! All controls will draw themselves, The size and scale of the form or control are adjusted freely. This is often used here, and it is the control effect that needs a little attention. Writing games, custom chart controls, and screen savers will require the programmer to write extra code to respond to the Paint event.
This article is for those Windows Forms developers and helps them to use simple drawing techniques during application programming. First, we'll discuss some basic drawing concepts. Who in the hell is responsible for drawing operations? How does a Windows forms program know when to draw? Where are the drawing codes placed? After that, you'll see how it works, and how you can use a method to alternate between a cache and an actual display of images. Finally, we will explore the "Smart Invalid Zone", which is to simply redraw or clear the invalid part of the application form and speed up the display and responsiveness of the program. Hopefully, these concepts and techniques will guide readers through this article and help develop Windows Forms programs faster and more efficiently.
Windows Forms uses the GDI + image engine, and all the drawing code in this article involves using the managed. Net framework to manipulate and use the Windows GDI + image engine.
Although this article is used for basic form drawing operations, it also provides a fast, efficient technique and method that helps improve program performance. Therefore, before reading this article, the reader is advised to. NET Framework has a basic understanding, including Windows Forms event handling, simple GDI + objects such as line,pen and brush. Familiarity with visual Basic. NET or C # programming language.
Concept
Windows applications are self-drawn, and when a form is "dirty", that is, the form changes size, or is partially obscured by other program forms, or resumes from a minimized state, the program receives the information it needs to draw. Windows calls this "dirty" state "Invalid (invalidated)" state, which we understand as: it needs to be redrawn when a Windows Forms program needs to redraw the form to get the drawn information from the Windows message queue. This message passes. NET Framework encapsulation is then passed to the form's paintbackground and paint events, where the appropriate writing of the code to be used for the drawing can be done in the above event.
A simple drawing example is as follows:
The following is a reference fragment: Using System; Using System.Drawing; Using System.Windows.Forms; public class Basicx:form { Public Basicx () { InitializeComponent (); } private void Basicx_paint (object sender, PaintEventArgs e) { Graphics g = e.graphics; Pen p = new Pen (color.red); int width = clientrectangle.width; int height= clientrectangle.height; G.drawline (P, 0,0, width, height); G.drawline (p, 0, height, width, 0); P.dispose (); } private void InitializeComponent () { This. SetStyle (Controlstyles.resizeredraw, true); This. ClientSize = new System.Drawing.Size (300, 300); This. Text = "Basicx"; This. Paint + = new Painteventhandler (this. Basicx_paint); } [System.STAThreadAttribute ()] public static void Main () { Application.Run (New Basicx ()); } } |
The code above is divided into two basic steps to create a sample program. First the InitializeComponent method contains the settings for some properties and the process of attaching the form Paint event. Note that the style of the control in the method is also set, and the style of the control is also an effective way to customize the behavior of the Windows Forms and controls, such as: The Resizeredraw property of the control indicates that it needs to be fully redrawn after the size of the form has changed. That is, redrawing always requires redrawing the entire customer area of the form. The "Customer area" of a form refers to all form regions except the title bar and border. You can do an interesting experiment, cancel the properties of the control, and then run the program, and we can clearly see why the property is often set because the invalid area after the form is resized is not redrawn at all.
Well, we need to pay attention to the Basicx_paint method, as mentioned earlier, the Paint event is activated when the program needs to be redrawn, the program form takes charge of the paint event to respond to system messages that need to be redrawn, and the call to the Basicx_paint method requires an object Sender and a variable of type PaintEventArgs, an instance of the PaintEventArgs class, or a variable E, encapsulates two important data, the first being a Graphics object of a form, which represents a surface that a form can draw, which is also called a canvas for drawing such as a line , text, and images, the second data is ClipRectangle, which represents the range of rectangles that are not valid on the form, or the area that the form needs to redraw. Remember that when the resizereddraw of a form is set, the size of the cliprectangle is actually equal to the size of the entire customer area of the form, or the portion of the clipping area that is obscured by other program forms. About the usefulness of partial clipping areas we will elaborate in more detail in the Smart Redraw section.
Dual Buffer Drawing Technology
The dual buffer technology allows the program to draw faster and smoother, effectively reducing the image flicker when drawing. The basic principle of this technique is to first draw the image onto a piece of canvas in memory, and once all the drawing operations are complete, push the in-memory canvas onto the form or the surface of the control to display it. With this kind of operation, the program can make the user feel faster and more beautiful.
The sample program provided below illustrates the concept and implementation of a double buffer, which is quite complete and can be used entirely in real-world applications. It is also mentioned later in this section that the technique should fit some of the property settings of the control to achieve better results.
To appreciate the benefits of the dual buffer drawing technique, run the Spiderweb sample program. After the program is up and running, the size of the window is adjusted, and you will find that using this drawing algorithm is not efficient and there is a lot of flicker in the resizing process.
without the dual buffer technology SpiderWeb Sample Program
Throughout the program's source code you will find that the program Paint event is activated by calling the Linedrawroutine method to achieve the drawing of the line. The Linedrawroutine method has two parameters, the first is where the graphics object is to draw the line, and the second is the Drawing tool pen object used to draw the line. The code is fairly simple, a looping statement, Linefreq constants, and so on, the program is underlined from the bottom left of the form's surface to its top right. Note that the program uses floating-point numbers to calculate where to draw on a form, and the advantage is that position data is more accurate when the size of the form changes.
The following is a reference fragment: private void Linedrawroutine (Graphics g, Pen p) { float width = clientrectangle.width; float height = clientrectangle.height; float XDelta = width/linefreq; float Ydelta = height/linefreq; for (int i = 0; i < linefreq; i++) { G.drawline (p, 0, height-(Ydelta * i), XDelta * I, 0); } } |
Writing a very simple code to respond to the paint event Spiderweb_paint, as mentioned earlier, the Graphics object is the drawing surface of the representation form extracted from the paint event parameter PaintEventArgs object. The Graphics object, along with the newly created Pen object, is passed to the Linedrawroutine method to draw a cobweb-like line, releasing its occupied resources after using the graphics object and the Pen object, and the entire drawing operation is complete.
The following is a reference fragment: private void Spiderweb_paint (object sender, PaintEventArgs e) { Graphics g = e.graphics; Pen redpen = new Pen (color.red); Linedrawroutine (g, redpen); Redpen.dispose (); G.dispose (); } |
So what is the change to make the above Spiderweb program to implement a simple double buffer technology? The principle is quite simple, that is, the drawing operation should be drawn to the surface of the form to be drawn into the memory of the bitmap, Linedrawroutine the same web-drawing operation to this hidden canvas in memory, Wait until the drawing is finished and then push the contents of the hidden canvas onto the surface of the form by calling the Graphics.DrawImage method, and finally, with some small changes, a high-performance drawing form program is complete.
Compare the differences between the following double buffer drawing events and the simple drawing events described earlier:
the following is Reference fragment: private void Spiderweb_dblbuff_paint (object sender, PaintEventArgs e) { Graphics g = e.graphics; Pen bluepen = new Pen (color.blue); BITMA P localbitmap = new Bitmap (clientrectangle.width,clientrectangle.height); Graphics Bitmapgraphics = Graphics.fromimage (localbitmap); Linedrawroutine (bitmapgraphics, BluePen); & nbsp //Put the bitmap in memory to the foreground and display g.drawimage (localbitmap, 0, 0); BITMAPGRAPHICS.D Ispose (); Bluepen.dispose (); Localbitmap.dispose (); G.dispose (); nbsp } |
The example code above creates a memory bitmap object whose size equals the size of the form's customer area, which is the drawing surface. By calling Graphics.fromimage to pass a reference to the in-memory bitmap to the Graphics object, all subsequent operations on the Graphics object are essentially operations on the in-memory bitmap, which is done in the C + + is equivalent to copying a pointer to a bitmap object to a Graphics object, with two objects using the same memory address. Now the Graphics object represents a canvas behind the screen, and it plays a crucial role in the dual buffer technology. All of the line drawing operations have been directed to the in-memory bitmap object, and the next step is to copy the bitmap to the form by calling the DrawImage method, and the spider's line will immediately appear on the drawing surface of the form without blinking.
This series of operations is not particularly effective since we mentioned earlier that the style of the control is also a way to define the behavior of the Windows Forms program, in order to better implement the double buffer must set the control's opaque property, this property indicates that the form is not responsible for drawing their own in the background, in other words, If this property is set, the associated code must be added for the purge and redraw operations. The Spiderweb program with a dual buffer version is performed well with each of the above settings, and the form surface is cleared with its own background color, which reduces flicker even more.
The following is a reference fragment: Public Spiderweb_dblbuff () { SetStyle (Controlstyles.resizeredraw | Controlstyles.opaque, True); } private void Spiderweb_dblbuff_paint (object sender, PaintEventArgs e) { Bitmap Localbitmap = new Bitmap (Clientrectangle.width, Clientrectangle.height); Graphics bitmapgraphics = Graphics.fromimage (Localbitmap); Bitmapgraphics.clear (BackColor); Linedrawroutine (Bitmapgraphics, Bluepen); } |
What's the result? The image is much smoother to draw. Pushing a spider's line from memory to the foreground to show that it's not flashing at all, but we'll just pause a little bit to trim the in-memory bitmap and display it, and add a line of code to make the line look flatter.
The following is a reference fragment: Bitmapgraphics.smoothingmode = Smoothingmode.antialias; |
After assigning the in-memory bitmap object to the graphics by placing this line of code, each line we draw on the canvas uses anti-aliasing to make the uneven lines appear flatter.
Spiderweb_dblbuff sample program with antialiasing (anti-aliasing) property with dual buffer technology
After completing the simple double buffer application There are two issues that need to be clarified to the reader. NET some of the controls such as Button, PictureBox, label, and PropertyGrid have already made good use of the technology! These controls automatically enable dual-buffer technology by default, and users can pass the "DoubleBuffer" The dual buffer technology can be implemented by setting the property. Therefore, it would be more efficient for users to use PictureBox to draw cobwebs, and it would make the program easier.
The dual buffer technology we are discussing here is neither completely optimized but not much of a negative impact. Double-buffer technology is an important way to reduce flicker when Windows Forms are drawn, but it does consume a lot of memory because it will use double the memory space: the image that the application displays and the image in memory behind the screen. Bitmap objects are created dynamically each time the paint event is activated, which can be quite memory-intensive. Controls that come with a dual-buffer technology are much better-performing with the DoubleBuffer property.
Using the DIB (device-independent Bitmap) object of GDI + to implement a memory buffer other than this, a control with a double-buffer mechanism can make good use of the bitmap object. Dib is an object of the underlying WIN32 for efficient screen drawing. Also, it is important to note that the first version of GDI + is only related to hardware acceleration and some simple features can be used directly, and because of this limitation, screen-drawing methods such as anti-aliasing and translucency perform quite slowly. Although the dual buffer mechanism consumes some memory, its use undoubtedly enhances the execution performance of the program.
Smart redraw, you need to consider before you draw
"Smart Invalid" (smart redraw) is a hint that programmers should understand that only the areas that are not valid in the program should be redrawn, that the invalid area of the regions object can be redrawn to improve drawing performance, and that you can use regions objects to exclude or draw only parts of the control and form for better performance. Let's start with a look at the Basicclip sample program, which uses the ClipRectangle object stored in the PaintEventArgs object, which we've mentioned before, whenever the size of the program changes, the Paint event will be activated. The Basicclip sample program fills the clipped rectangular area with red and blue colors, adjusts the size of the form a few times, and you'll find that the rectangular area you draw is actually the invalid area of the form (including the area portion larger than the original form size and the less-indented area). The Paint event code for the sample program is as follows:
The following is a reference fragment: private void Basicclip_paint (object sender, PaintEventArgs e) { Graphics g = e.graphics; if (Currentbrush.color = = color.red) Currentbrush.color = Color.Blue; Else Currentbrush.color = color.red; G.fillrectangle (Currentbrush, E.cliprectangle); G.dispose (); } |
The only purpose of the sample program is to demonstrate how to plot only parts of the area.
The colored rectangular area in the Basicclip sample program is an invalid area that represents the lower and right sides of the form.
Regions is an object that is used to define a Windows Form or control area, and the regions you get when you resize a form is the smallest area that the form redraws. When a program needs to draw only special areas of interest, drawing smaller areas makes the program run faster.
For a better demonstration of the use of regions, please review the Textcliping sample program. The program overloads the OnPaintBackground and OnPaint methods, and overloading these methods directly is more secure than listening to events that the code is called before other drawing operations, and is more efficient for drawing custom controls. For clarity, the sample program provides a setup method that defines the global graphics object.
The following is a reference fragment: private void Setup () { GraphicsPath Textpath = new GraphicsPath (); Textpath.addstring (displaystring, Fontfamily.genericserif, 0, New Point (Ten), New StringFormat ()); Textregion = new Region (Textpath); Backgroundbrush = new TextureBrush (New Bitmap ("Coffeebeansmall.jpg"), Wrapmode.tile); Foregroundbrush = new SolidBrush (color.red); } |
The Setup method above first defines an empty GraphicsPath object variable Textpath, and the next string "Windows Forms" bounds are added to the path, creating region around the outline. In this way, a region that is drawn on the surface of the form with a string outline is created. Finally, the Setup method creates a background with a material brush and a solid color brush for the foreground to draw the form.
The following is a reference fragment: protected override void OnPaintBackground (PaintEventArgs e) { Base. OnPaintBackground (e); Graphics bggraphics = e.graphics; Bggraphics.setclip (Textregion, combinemode.exclude); Bggraphics.fillrectangle (Backgroundbrush, E.cliprectangle); Bggraphics.dispose (); } |
The OnPaintBackground method, defined above, calls the base class method immediately, which guarantees that all the code that is drawn at the bottom can be executed. Next, get the Graphics object from PaintEventArgs, and then define the clipping region of the Graphics object as a Textregion object. By specifying the Combinemode.exclude parameter, it is clear that no matter where the drawing is drawn or how the graphics object is drawn inside the textregion area.
The following is a reference fragment: protected override void OnPaint (PaintEventArgs e) { Base. OnPaint (e); Graphics fggraphics = e.graphics; Fggraphics.fillregion (Foregroundbrush, textregion); Fggraphics.dispose (); } |
Finally, the OnPaint event is responsible for accurately plotting the string. Can be easily implemented by invoking the FillRegion method of the graphics. By specifying the foreground brush Foregroundbrush and textregion and only the area is drawn. As a result, the Windows forms program does "think" about how to draw before it runs.
The Textclipping sample program, defined by region, is a Windows Forms string. Enables the program to avoid an area when drawing.
Appropriate combinations use area and smart redraw you can write out the drawing code that runs fast and does not cause flicker, and saves memory consumption more than using double buffer drawing alone.
Conclusion
If your program determines the drawing operation, several techniques can be used to enhance drawing performance. Ensuring that you are trying to set control properties and appropriate paint event handling is the start of writing a robust program. A double-buffer technique can be used to produce very "eye-protection" results after weighing the pros and cons. Finally, it is useful to think about exactly which customer areas or regions need to be drawn before actually drawing.
Hopefully this article will enable readers to better understand the. NET Framework of drawing technology and its applications.