Learn VB .NET Through Game Programming [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Learn VB .NET Through Game Programming [Electronic resources] - نسخه متنی

Matthew Tagliaferri

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید





Using the BMPStitch Code

The BMPStitch utility contains a few code fragments worthy of discussion and study, especially for someone uninitiated with the .NET Framework. Some of the functionality may serve as a learning tool into this vast library.


Creating the ClipPictureBox Class


The most interesting part of the BMPStitch code is a class I developed for displaying the image and the clipping lines. This class is ClipPictureBox, and Listing C-1 shows the interface of the class.

Listing C.1: Public (and Protected) Interface of the ClipPictureBox Class



Public Class ClipPictureBox
Inherits PictureBox
Property ClipColor() As Color
Property ClipDisabled() As Boolean
Public Event ClippingRectChanged(ByVal r As Rectangle)
ReadOnly Property ClippingRect() As Rectangle
Shadows Property Image() As Image
Protected Overrides Sub OnPaint(ByVal pe As _
System.Windows.Forms.PaintEventArgs)
Protected Overrides Sub OnMouseDown(ByVal e As _
System.Windows.Forms.MouseEventArgs)
Protected Overrides Sub OnMouseMove(ByVal e As _
System.Windows.Forms.MouseEventArgs)
Protected Overrides Sub OnMouseUp(ByVal e As _
System.Windows.Forms.MouseEventArgs)
End Class



The ClipPictureBox class is an ancestor of the standard .NET Framework PictureBox class, meaning of course that it receives all of that ancestor’s functionality “for free.” This class extends the ancestor class by supporting the drawing and manipulation of the clipping lines. To that end, the OnPaint method and the three mouse-based methods OnMouseDown, OnMouseMove, and OnMouseUp are all overridden.

Another case of extended functionality occurs in the Image property, which is aproperty found in the base class. You can extend the functionality of the property so that you can initialize the location of the four clipping lines. You do this by using the Shadows keyword on the property, which indicates that this property replaces the functionality found in the base class. Listing C-2 shows the code for the Image property, as well as the private variables used to store the location of the four clipping lines.

Listing C.2: Shadowed Image Property on the ClipPictureBox



Private FClipInitialized As Boolean = False
Private FClipTop As Integer
Private FClipBottom As Integer
Private FClipLeft As Integer
Private FClipRight As Integer
Shadows Property Image() As Image
Get
Return MyBase.Image
End Get
Set(ByVal Value As Image)
MyBase.Image = Value
If Not FClipInitialized Then
FClipTop = Height \ 4
FClipBottom = (Height \ 4) * 3
FClipLeft = Width \ 4
FClipRight = (Width \ 4) * 3
FClipInitialized = True
End If
End Set
End Property



What’s interesting here is that you’ve specified to replace the Image property by using the Shadows keyword, but then you go ahead and use the base Image property to store the image. In effect, you’re declaring that you want to replace the base property, but then you go ahead and use the property for storage anyway. You then add some functionality to the Set portion of the property. This new functionality initialized the four clipping line variables (only if they haven’t already been set; the variable FClipInitialized acts as a flag to make sure the initialization happens only once).

This technique of shadowing a property and then using it anyway is a great way to “cheat” on a member that isn’t declared Overrideable. The standard way of replacing or extended functionality on a class member is to override it, but you can’t do this unless the base class explicitly declares the class Overrideable. You can shadow any member, though.

File Handling


The code within the utility’s form has some base file handling functionality that’s important. The first example of this functionality, shown in Listing C-3, occurs when the user clicks the Open button.

Listing C.3: Getting a File from the User, and Setting Up the ClipPictureBox Control



Public Class fBMPStitch
Inherits System.Windows.Forms.Form
Private FBaseFile As String
Dim FFrames As Integer
Dim pb As ClipPictureBox
Private Sub cbFile_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cbFile.Click
If oDialog.ShowDialog Then
FBaseFile = oDialog.FileName
If pb Is Nothing Then
pb = New ClipPictureBox
pb.SizeMode = PictureBoxSizeMode.AutoSize
pb.Location = New Point(10, 10)
pb.Visible = True
AddHandler pb.ClippingRectChanged, _
AddressOf pb_ClippingRectChanged
Me.Controls.Add(pb)
End If
pb.Image = Image.FromFile(FBaseFile)
Call CountFiles()
End If
End Sub
Private Sub CountFiles()
Dim f As New FileInfo(FBaseFile)
Dim d As New DirectoryInfo(f.DirectoryName)
Dim cExt As String = f.Extension
FFrames = 0
For Each f In d.GetFiles("*" & cExt)
FFrames += 1
Next
lbFrames.Text = FFrames & " frames"
nudAcross.Value = Math.Sqrt(FFrames)
nudDown.Value = nudAcross.Value
End Sub



The variable oDialog is an instance of the .NET Framework class named OpenFileDialog. As shown in Listing C-3, the method ShowDialog opens the dialog box that requests a file from the user and returns True if the user does indeed select a file (the method returns False if the end user selects Cancel).

If the user selects a file, the code initializes a ClipPictureBox variable and adds it to the form. You could’ve done this by putting the ClipPictureBox into its own project and adding it to the Visual Studio toolbox, but this method does it at runtime instead. Once the ClipPictureBox is added to the form, it’s loaded with the image from the selected file.

The routine CountFiles is called next. This routine uses some .NET Framework file and directory handling classes to count the number of files in the folder of the user-selected file. The first class, named FileInfo, encapsulates the functionality of any on-disk file. In this code, the class is initialized with the file selected by the user. The next line initializes a class named DirectoryInfo using the directory of the user-selected file as the constructor’s parameter. What this gives you is a representation of the folder in which the user-selected file lies. One of the things the DirectoryInfo class lets you do is loop through all the files in the represented directory, and this is exactly what the remainder of the code does. The purpose of this loop is to count the number of files in the folder that have the same extension as the originally selected file. Once the number of files is known, it’s stored in the variable FFrames, and the across/down controls are initialized to numbers that are the square root of this value. This works great when there are 36 frames because there would be six frames across and six down, but it doesn’t quite work with, say, 24 frames. It does provide a reasonable starting value for the across/down controls, though.


Creating the Bitmap Building Code


Listing C-4 shows the routine that takes the individual bitmap files, smashes them into a large single bitmap, and then saves the bitmap to disk.

Listing C.4: The “Meat” of the Bitmap Stitcher: The Stitching Code



Private Sub cbBuild_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cbBuild.Click
Dim b As Bitmap
Dim f As New FileInfo(FBaseFile)
Dim d As New DirectoryInfo(f.DirectoryName)
Dim x, y As Integer
Dim h, w As Integer
Dim iA, iD As Integer
Dim cExt As String
iA = nudAcross.Value
iD = nudDown.Value
If iA * iD <> FFrames Then
MsgBox("across * down must = frames", _
MsgBoxStyle.Critical + MsgBoxStyle.OKOnly, "Error")
Else
w = pb.ClippingRect.Width
h = pb.ClippingRect.Height
b = New Bitmap(w * iA, h * iD, Graphics.FromImage(pb.Image))
Dim g As Graphics
g = Graphics.FromImage(b)
Try
x = 0
y = 0
cExt = f.Extension
For Each f In d.GetFiles("*" & cExt)
pb.Image = Image.FromFile(f.FullName)
pb.Refresh()
Thread.CurrentThread.Sleep(100)
g.DrawImageUnscaled(pb.Image, x, y)
x += w
If x >= w * iA Then
x = 0
y += h
End If
Next
Finally
g.Dispose()
End Try
b.Save("c:\BMPStitch.bmp", System.Drawing.Imaging.ImageFormat.Bmp)
lbClip.Text = "c:\BMPStitch.bmp saved"
End If
End Sub




The first thing this routine does is check that the across/down control values, when multiplied together, actually add up to the number of frames found in the CountFrames routine discussed previously. If not, then the routine displays an error to the end user and exits.

If the math all works out, though, the bitmap stitching can begin. First, abitmap simply named b is created that has the width and height needed to store the frame bitmaps. The program then loops through all the image files in the folder again, just as in the routine CountFrames. This time, though, each file is loaded into the ClipPictureBox variable and then copied into the appropriate spot on the final bitmap. Finally, the bitmap is saved to the hard-coded filename c:\BMPStitch.bmp.

/ 106