正文

GUI+英文教程2006-07-13 21:20:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/iamben250/16583.html

分享到:

The Graphics Object

All drawing in GDI+ takes place upon the Graphics object and there are several contexts in which you'll find one. During a Paint cycle the Graphics object will be provided in a PaintEventArgs object that is handed to your code in the OnPaint and OnPaintBackground methods of a Windows Forms control. This same event argument is passed to handlers that service the Paint event raised by the OnPaint methods. When printing, the PrintPageEventArgs provided in a PrintPage event will contain a Graphics object for the printer and you can obtain a Graphics object for certain types of image so that you can paint directly on an image in memory as if it were the screen.

Obtaining the Graphics object.

When you're writing programs that place graphics on screen the graphics object will be handed to you wrapped up in a PaintEventArgs object. There are two ways in which your code can get hold of the Graphics object. You can override the protected OnPaint or OnPaintBackground methods or you can add a handler to the Paint event. In all these cases the Graphics object is passed in a PaintEventArgs object. Listing 1 shows the various methods.

Listing 1

    Protected Overrides Sub OnPaint(e As PaintEventArgs)

     'get the Graphics object from the PaintEventArgs

     Dim g As Graphics = e.Graphics

     g.DrawLine(....)

     

     'or use it directly

     e.Graphics.DrawLine(....)

     

     'Remember to call the base class or the Paint event won't fire

     MyBase.OnPaint(e)

    End Sub 'OnPaint

    

    

    'This is the Paint event handler

    Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint

     'get the Graphics object from the PaintEventArgs

     Dim g As Graphics = e.Graphics

     g.DrawLine(....)

     

     'or use it directly

     e.Graphics.DrawLine(....)

    End Sub 'Form1_Paint

You can see in Listing 1 that you can get a reference to the Graphics object and save that for use in the code or use it directly from the PaintEventArgs. Remember not to save the Graphics object outside of the scope of the method.

What to do with it when you have it.

When your code has access to a Graphics object there are a number of things you can do. They fall into five general categories.

  • Stroke a shape. Shapes such as rectangles, ellipses and lines are drawn using a Pen object. The pen can have different thickness or colour and have many other attributes which you will see in another article.

  • Fill a shape. Shapes can be filled with a Brush object. Brushes have many complex settings in GDI+ but they all basically fill an area with colour.

  • Draw a string. Text can be placed on the Graphics surface using the DrawString method.

  • Draw an image. Images can be drawn in any scale using one of the DrawImage methods.

  • Modify the Graphics object. There are many methods that change the way the Graphics object performs. You can change the quality of graphics and have high-quality graphics at the expense of speed. You can change the way the graphics are output to create rotation, zooming or distortion effects.

To demonstrate the use of the Graphics object, the following listing shows the paint handler from a form that demonstrates stroking and filling of shapes. Figure 1 shows this simple application at work.

Figure 1. Stroking and filling.

    Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

      'Get the Graphics object

      Dim g As Graphics = e.Graphics

 

      'Draw a line

      g.DrawLine(Pens.Red, 10, 5, 110, 15)

 

      'Draw an ellipse

      g.DrawEllipse(Pens.Blue, 10, 20, 110, 45)

 

      'Draw a rectangle

      g.DrawRectangle(Pens.Green, 10, 70, 110, 45)

 

      'Fill an ellipse

      g.FillEllipse(Brushes.Blue, 130, 20, 110, 45)

 

      'Fill a rectangle

      g.FillRectangle(Brushes.Green, 130, 70, 110, 45)

 

      MyBase.OnPaint(e)

    End Sub 'OnPaint

 

Things to remember.

Generally, you should only ever use the Graphics object handed to you by the system.

GDI+ is an "Immediate Mode" system. This is to say that the Graphics object has no knowledge of objects, only areas of colour. Shapes and lines are only remembered until they are painted over by a different colour.

You should not store a Graphics object outside of the scope of the method that its given to. When drawing is done, the Graphics object is destroyed until another is needed.

 

Coordinate Systems

As with most graphics systems, the position of items on a Graphics surface is controlled by X and Y coordinates. A single coordinate is a pair of numbers that represent the distance across the surface from left to right and the distance down the surface from top to bottom. For example, a line may be drawn from place to place using the code shown in listing 1.

g.DrawLine(Pens.Black,0,0,100,200)

The coordinates are given in the last four parameters of the line drawing command as 0,0,100,200 and represent a line drawn from position 0,0 to position 100,200 as shown in figure 1.

Figure 1.

In the default mode, the coordinates used in GDI+ refer to pixel positions but GDI+ is a Resolution Independent drawing system. This means that you can represent abstract drawing units such as pixels or real-world drawing units such as inches and millimeters in GDI+.

Goodbye to integers

Many graphics systems and particularly old Windows GDI used integer values for the coordinates. This meant that you could not represent an inch and a half by the number 1.5. In GDI+ this is a thing of the past because the coordinates used to place colour on the drawing surface are floating point numbers. This means that if you wish to create a CAD drawing program and show designs in accurate inch or millimeter sizes then you can with GDI+.

Coordinate spaces

There are three distinct coordinate spaces in GDI+. These are;

  1. World coordinate space. This is where you put the coordinates that define lines, shapes and points in the 2 dimensional space of the graphics system. World coordinates are abstract values expressed as floating point numbers. Essentially, whenever you draw something it goes into this coordinate space.

  2. Page Coordinate Space. The Page space is where the world coordinates are transformed into some real-world value. You can make the Page Space represent pixels, inches millimeters and so-on. This is what makes GDI+ a resolution independent system. You control how the page space interprets the world space by telling the Graphics object what PageUnit is being used and adjusting the PageScale.

  3. Device Coordinate Space. This space is controlled by the system and enables the real-world values in the Page Space to be translated to your screen or printer. Device space ensures that a 1 inch long line looks an inch long on the screen and on the printer even though the two devices may have very different pixel resolutions. You have no direct control over this space.

The correct term for this type of system, where coordinates are transformed from one system to another over several steps, is a Graphics Pipeline. The GDI+ graphics pipeline takes the values you use and transforms them from an abstract floating point number to a real-world value and then to the hardware world of the monitor or printer.

Real-world values.

The actual real-world standards available to you for the Page Space are;

  • Pixel. Each unit in world space represents one pixel on the screen or printer. This is the default value for the page units. Artifacts drawn with this setting will be of different sizes on different devices such as screens and printers.

  • Millimeter. Each unit in world space represents one millimeter. This page unit setting will look the same on the printer as it does on the screen.

  • Inch. Each unit in world space represents one inch. This page unit setting will look the same on the printer as it does on the screen.

  • Point. Each unit in world space represents one printers point which is 1/72nd of an inch. Points are the preferred unit of measure for type-intensive applications. This page unit setting will look the same on the printer as it does on the screen.

  • Display. A world space unit will represent 1/75th of an inch. This is a holdover from the days when common CRT dot-pitch was 75 dots-per-inch (DPI). This page unit setting will look the same on the printer as it does on the screen.

  • Document. World space units will represent 1/300th of an inch. This value is a holdover from when laser-printers commonly had 300 DPI resolutions

  • World. Supposedly, this should work the same way a the Pixel system but in practice it often causes an error. Generally, you don't need to worry about this setting.

The following demonstration application shows how the real-world values can be used in your code. The application draws several rectangles that are created to inch, millimeter and pixel sizes. The application will print too so that you can check the sizes against a printed copy and on screen. If you have a plug and play monitor you'll see that the printed sizes and the screen sizes of the real-world values are identical but the pixel values aren't. Figure 1 shows the application at work.

Figure 1. Real-world drawing systems.

The bit that does the drawing of the rectangles is shown in the following listing.

    Private Sub DrawRectangles(ByVal g As Graphics)

      g.PageUnit = GraphicsUnit.Pixel

      Dim p As New Pen(Color.Black, 3) 'this pen will be 3 pixels wide

      g.DrawRectangle(p, 10, 10, 200, 100) 'draw a rectangle in Pixel mode (the default)

      p.Dispose()

 

      g.PageUnit = GraphicsUnit.Inch

      p = New Pen(Color.Blue, 0.05F) 'this pen will be 1/20th of an inch wide

      g.DrawRectangle(p, 0.1F, 1.5F, 4.0F, 1.0F) ' draw a rectangle 4" by 1"

      p.Dispose()

 

      g.PageUnit = GraphicsUnit.Millimeter

      p = New Pen(Color.Green, 1.0F) 'this pen will be 1 millimeter wide

      g.DrawRectangle(p, 4.0F, 80.0F, 80.0F, 60.0F) ' draw a rectangle 80 by 60 mm

      p.Dispose()

    End Sub 'DrawRectangles 

The same code, in DrawRectangles, is used for both printing and screen drawing. Note how, especially for the inch based drawing, floating point values with fractional numbers are used.

The full listing of the code, shown in listing 2, includes the button click handler to print a single page with the rectangles drawn on it. Unless by some strange quirk of fate your printer resolution is identical to that of your screen you'll see two very different versions of the same code.

 

Imports System

Imports System.Drawing

Imports System.Collections

Imports System.ComponentModel

Imports System.Windows.Forms

Imports System.Data

Imports System.Drawing.Printing

 

 

Namespace RealWorld

   '/ <summary>

   '/ Summary description for Form1.

   '/ </summary>

  

   Public Class Form1

    Inherits System.Windows.Forms.Form

    Private WithEvents panel1 As System.Windows.Forms.Panel

    Private WithEvents button1 As System.Windows.Forms.Button

    '/ <summary>

    '/ Required designer variable.

    '/ </summary>

    Private components As System.ComponentModel.Container = Nothing

    

    

    Public Sub New()

     '

     ' Required for Windows Form Designer support

     '

     InitializeComponent()

    End Sub 'New

     

    '

    ' TODO: Add any constructor code after InitializeComponent call

    '

    

    '/ <summary>

    '/ Clean up any resources being used.

    '/ </summary>

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

      If disposing Then

        If Not (components Is Nothing) Then

          components.Dispose()

        End If

      End If

      MyBase.Dispose(disposing)

    End Sub 'Dispose

 

#Region "Windows Form Designer generated code"

 

    '/ <summary>

    '/ Required method for Designer support - do not modify

    '/ the contents of this method with the code editor.

    '/ </summary>

    Private Sub InitializeComponent()

      Me.panel1 = New System.Windows.Forms.Panel

      Me.button1 = New System.Windows.Forms.Button

      Me.SuspendLayout()

      '

      ' panel1

      '

      Me.panel1.Anchor = CType(System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles)

      Me.panel1.BackColor = System.Drawing.Color.White

      Me.panel1.Location = New System.Drawing.Point(8, 8)

      Me.panel1.Name = "panel1"

      Me.panel1.Size = New System.Drawing.Size(312, 320)

      Me.panel1.TabIndex = 0

      '

      ' button1

      '

      Me.button1.Anchor = CType(System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles)

      Me.button1.Location = New System.Drawing.Point(336, 40)

      Me.button1.Name = "button1"

      Me.button1.TabIndex = 1

      Me.button1.Text = "Print"

      '

      ' Form1

      '

      Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)

      Me.ClientSize = New System.Drawing.Size(416, 334)

      Me.Controls.Add(button1)

      Me.Controls.Add(panel1)

      Me.Name = "Form1"

      Me.Text = "Form1"

      Me.ResumeLayout(False)

    End Sub 'InitializeComponent

#End Region

 

 

    '/ <summary>

    '/ The main entry point for the application.

    '/ </summary>

    <STAThread()> _

    Shared Sub Main()

      Application.Run(New Form1)

    End Sub 'Main

 

 

    Private Sub DrawRectangles(ByVal g As Graphics)

      g.PageUnit = GraphicsUnit.Pixel

      Dim p As New Pen(Color.Black, 3) 'this pen will be 3 pixels wide

      g.DrawRectangle(p, 10, 10, 200, 100) 'draw a rectangle in Pixel mode (the default)

      p.Dispose()

 

      g.PageUnit = GraphicsUnit.Inch

      p = New Pen(Color.Blue, 0.05F) 'this pen will be 1/20th of an inch wide

      g.DrawRectangle(p, 0.1F, 1.5F, 4.0F, 1.0F) ' draw a rectangle 4" by 1"

      p.Dispose()

 

      g.PageUnit = GraphicsUnit.Millimeter

      p = New Pen(Color.Green, 1.0F) 'this pen will be 1 millimeter wide

      g.DrawRectangle(p, 4.0F, 80.0F, 80.0F, 60.0F) ' draw a rectangle 80 by 60 mm

      p.Dispose()

    End Sub 'DrawRectangles

 

 

    Private Sub panel1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles panel1.Paint

      DrawRectangles(e.Graphics)

    End Sub 'panel1_Paint

 

 

    Private Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles button1.Click

      Dim pd As New PrintDocument

      AddHandler pd.PrintPage, AddressOf pd_PrintPage

      pd.Print()

    End Sub 'button1_Click

 

 

    Private Sub pd_PrintPage(ByVal sender As Object, ByVal e As PrintPageEventArgs)

      DrawRectangles(e.Graphics)

      e.HasMorePages = False

    End Sub 'pd_PrintPage

  End Class 'Form1

End Namespace 'RealWorld

阅读(3060) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册