Button | control UI (user Interface) programming is an important part of the overall project development process, and any good solution that doesn't have a good user interface present to end users is not a good program even if the most advanced technology is included. UI programming is embodied in two aspects, one is the design of a beautiful user interface, and then is in line with the majority of user habits and easy to use the operating procedures, and the system to make exquisite, colorful user interface is to win the end user favorite first step. Let's make a crystal-style three-dimensional button for example to enrich. NET Interface Material library, to add highlights for Windows Forms programs.
first, technical points
It is undeniable that Windows programming has entered the. NET era, although the current programming platform is still a number of coexistence, but Microsoft's. NET Framework class library has been fully occupied the mainstream position. NET Framework provides us with very rich classes, functions, and methods, from the desktop to the web it can touch any area of programming, so that you can completely discard the Win32 API manual calls, because. NET Framework has prepared everything for us. In particular, the release of GDI +, WIN32 programmers should be very clear, in VC6 and Delphi5, 6, 7 to draw irregular graphics, design a unique style of the window control is how not easy thing, we need to return the current device pointer, and then coordinate mapping, and then call the standard Win32 GDI function to draw operations, and finally have to remember to release the device pointer, such as a series of memory cleanup operations, now there. NET class library, We simply return the graphics object through E.graphics in the control's OnPaint event, then create a custom Brush object brush to populate the graphics surface, and then create a region object that designs the outline of the control we need and assigns it to the control's Region property, which In the process, you can use GDI + to provide us with rich classes and methods to design beautiful control skins, so that a new control is created.
Our example control is a crystal-style three-dimensional button, design such a button control is not complicated, we only need to capture the OnPaint event, and in the event to follow different button states such as: mouse into the mouse, hover, mouse clicks and mouse left and so redraw the appearance of the button. The three-dimensional style of the button is actually the superposition of three rectangular regions, that is, the shadow is at the bottom, the button itself and the top of the button head white bubble part, these three parts of the effective superposition is made into a vivid crystal-style button, as shown in the following figure:
The more critical classes used in this example are GraphicsPath, LinearGradientBrush, and PathGradientBrush. We already know that the GraphicsPath object is used for complex graphical drawing operations, and GraphicsPath provides us with a very convenient solution, consisting of a series of lines and curves, which make it easy to create arbitrary irregular graphics by creating complex closed paths The LinearGradientBrush and PathGradientBrush objects are the key classes in which we successfully created the sample program, all of which inherit the object defined by the base class Brush,brush object that fills the interior of the shape. LinearGradientBrush creates an instance of the class by starting and ending coordinates and the start and end colors of the gradient, which supports two-color gradients and custom multicolor gradients, all of which are defined along a line specified by the width of the rectangle or two points, and by default, A two-color gradient is a mixture of uniform horizontal lines along the specified line from the starting color to the end color, so we use the class to draw the white gradient portion of the button itself and the top of the button, and part of the code is as follows:
Create a graphic for the button itself
Rectangle rc = new Rectangle (Btnoffset, Btnoffset, this. Clientsize.width-8-Btnoffset, this. Clientsize.height-8-Btnoffset);
GraphicsPath path1 = this. Getgraphicspath (RC, 20);
LinearGradientBrush BR1 = new LinearGradientBrush (0, 0), new Point (0, RC. Height + 6), Color.Blue, Color.White);
Create a white gradient at the top of a button
Rectangle RC3 = RC;
Rc3. Inflate (-5,-5); //
Rc3. Height = 15;
GraphicsPath path3 = Getgraphicspath (RC3, 20);
LinearGradientBrush Br3 = new LinearGradientBrush (RC3, Color.FromArgb (255, Color.White), Color.FromArgb (0, Color.White ), lineargradientmode.vertical)
The PathGradientBrush class fills the interior of the GraphicsPath object with a gradient that allows a smooth color gradient from the midpoint of the path to the edge of the outer boundary of the path, which we use to create the shaded part of the button, The Centercolor property is used to set the center color of the path gradient, which is black, and the surroundcolors array is used to set the array of colors corresponding to the midpoint of the path, part of the code is as follows:
Rectangle RC2 = RC;
RC2. Offset (Shadowoffset, Shadowoffset);
GraphicsPath path2 = this. Getgraphicspath (RC2, 20);
PathGradientBrush Br2 = new PathGradientBrush (path2);
Br2. Centercolor = Color.Black;
Br2. Surroundcolors = new color[] {systemcolors.buttonface};
To be realistic, we set the gradient end color to the foreground color of the form, which you can adjust appropriately depending on the foreground color of the window
After creating an instance of the object, the interior of the shadow shape is filled with a radial gradient, and perhaps the reader asks, why do you have to fill the interior of the graphic with PathGradientBrush instead of LinearGradientBrush? In fact, the reason is very simple, is to ensure that the button below and the right shade gradient color and degree is consistent, otherwise if you also use linear gradient lineargradientbrush, the result is the following figure:
After the creation of the instance BR1, Br2, and Br3 of three brush objects, we need to draw them in the order of the shadow, the button itself, and finally the white gradient part at the top of the button. The FillPath method that calls the Graphics object uses three different brush objects to populate the GraphicsPath interior, so the three-dimensional, crystal-style buttons are basically created. Finally, we use it again. NET level two cache drawing technology draws the button and the text displayed on the button to the screen.
Second, realize
We use C # to make Crystal button controls.
First start Visual Studio 2005, create a new blank solution, we name it: Testcrystalbutton, then add a new project by right-clicking on the project navigation bar, adding a new C # Windows Control Library for this solution, named MyControls. The IDE creates a class that inherits from the UserControl name UserControl1, modifies the code to inherit from the button, and changes all references to the UserControl1 name in the original file to Crystalbutton. Rename UserControl1.cs to CrystalButton.cs in the project navigation bar, as in the following section of code:
Namespace MyControls
{
public partial class Crystalbutton:button
{
Public Crystalbutton ()
{
InitializeComponent ();
}
}
}
The InitializeComponent () method is then
This. AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
Statement, because there is no automatic scaling from the button control, it must depend on its parent control. Add a reference to the System.Drawing.Imaging and System.Drawing.Drawing2D assemblies in the header of the source file. First you need to create an enumerated type Mouseactiontype, which is drawn in different states depending on the position of the current mouse when it needs to be drawn, as in the following code:
......
Private Enum Mouseactiontype
{
None,
Hover,
Click
}
Private Mouseactiontype mouseaction;
Control captures the onmousedown, OnMouseUp, Onmousehover, Onmouseenter, and OnMouseLeave events and sets the mouseaction variable to a different enumeration value. To draw a different state based on the mouseaction variable when the OnPaint event occurs.
The OnPaint event for the control is the most important piece of code in the entire project, drawn separately by the three parts of the button, and finally the text of the button is drawn to the button surface, all of which use a level two cache drawing technique, as follows:
protected override void OnPaint (PaintEventArgs e)
{
Graphics g = e.graphics;
G.clear (Systemcolors.buttonface);
Color CLR = this. BackColor;
int shadowoffset = 8;
int btnoffset = 0;
Switch (mouseaction)
{
Case Mouseactiontype.click:
Shadowoffset = 4;
CLR = Color.lightgray;
Btnoffset = 2;
Break
Case Mouseactiontype.hover:
CLR = Color.lightgray;
Break
}
G.smoothingmode = Smoothingmode.antialias;
Create a graphic for the button itself
Rectangle rc = new Rectangle (Btnoffset, Btnoffset, this. Clientsize.width-8-Btnoffset, this. Clientsize.height-8-Btnoffset);
GraphicsPath path1 = this. Getgraphicspath (RC, 20);
LinearGradientBrush BR1 = new LinearGradientBrush (0, 0), new Point (0, RC. Height + 6), CLR, Color.White;
Create a button Shadow
Rectangle RC2 = RC;
RC2. Offset (Shadowoffset, Shadowoffset);
GraphicsPath path2 = this. Getgraphicspath (RC2, 20);
PathGradientBrush Br2 = new PathGradientBrush (path2);
Br2. Centercolor = Color.Black;
Br2. Surroundcolors = new color[] {systemcolors.buttonface};
To be realistic, we set the gradient end color to the foreground color of the form, which you can adjust appropriately depending on the foreground color of the window
Create a white gradient at the top of a button
Rectangle RC3 = RC;
Rc3. Inflate (-5,-5);
Rc3. Height = 15;
GraphicsPath path3 = Getgraphicspath (RC3, 20);
LinearGradientBrush Br3 = new LinearGradientBrush (RC3, Color.FromArgb (255, Color.White), Color.FromArgb (0, Color.White ), lineargradientmode.vertical);
Drawing graphics
G.fillpath (Br2, path2); Draw Shadow
G.fillpath (BR1, path1); Draw button
G.fillpath (Br3, path3); Draw Top White Bubbles
Set memory Bitmap object for two-level cache drawing operations
Buttonbitmaprectangle = new Rectangle (RC. Location, RC. Size);
Buttonbitmap = new Bitmap (buttonbitmaprectangle.width, buttonbitmaprectangle.height);
Graphics g_bmp = Graphics.fromimage (Buttonbitmap);
G_bmp. SmoothingMode = Smoothingmode.antialias;
G_bmp. FillPath (BR1, path1);
G_bmp. FillPath (Br3, path3);
Assign a region to a button
Region rgn = new Region (path1);
Rgn. Union (path2);
This. Region = RGN;
Draw the text of a button
GraphicsPath Path4 = new GraphicsPath ();
RectangleF path1bounds = path1. GetBounds ();
Rectangle rctext = new Rectangle (int) path1bounds. X + btnoffset, (int) path1bounds. Y + btnoffset, (int) path1bounds. Width, (int) path1bounds. Height);
StringFormat Strformat = new StringFormat ();
Strformat. Alignment = Stringalignment.center;
Strformat. LineAlignment = Stringalignment.center;
Path4. AddString (this. Text, this. font.fontfamily, (int) this. Font.style, this. Font.Size, Rctext, Strformat);
Pen Txtpen = new Pen (this. ForeColor, 1);
G.drawpath (Txtpen, PATH4);
G_bmp. DrawPath (Txtpen, PATH4);
}
Control is finished, Compiling the solution and control project build CrystalButton.dll, you can add a Windows Forms program project that uses the control in the current solution, or you can add a reference to the control in any solution simply by dragging the Crystalbutton from the Toolbox onto the form.
Third, summary
The. Net Framework's GDI + enhanced graphic image rendering technology provides us with a powerful graphical image rendering capability, which contains a wealth of classes and methods that provide a powerful guarantee for our full custom control appearance, simplifying program code and greatly saving programming time.
The sample controls and programs are compiled and run through the visual Studio, "Team Suite, Windows XP SP2."