|
WinForms |
|
|
|
Developing Windows Applications using VC++ involves a steep learning curve. Developing them using VB promotes RAD, but takes you farther from today's Object Oriented programming world. What is needed is a tool that promotes RAD and supports OO. .Net's WinForms is the answer. Precisely what the programmer ordered… For building Windows applications the .NET Framework provides two things—classes for managing the user-interface controls and an Integrated Development Environment (IDE) to design the Windows applications visually. Any window displayed in an application is created as a form. WinForms is a programming model used for building Windows applications through a form designer. Using the form designer we can create standard windows, borderless windows, MDIs, dialog boxes, etc. We can add controls, set properties, create event handlers, and add programming logic to our form. A separate class governs each control that is added to a form. All the control classes are derived from the Control class. The classes are present in the System.Windows.Forms namespace. The classes remain same no matter which .NET language we use. If you have used the Resource Editor of VB or VC++ you will have to spend little time to get familiar with the way the IDE works. You simply have to drag controls from a toolbox and drop them onto a form. Once inserted you can set the properties of the form as well as the controls using the IDE. The IDE generates only source code and not resource files as in VC++. The basic program to create a form looks like this: using System; using System.Window.Forms public class myform : Form { public myform ( ) { } static void Main ( ) { myform a = new myform( ) ; Application.Run ( a ) ; } } In Main( ) the Run( ) method of the Application class is called. To this method we have passed an instance of the form. The Application class provides static methods and properties to manage an application, such as methods to start and stop an application, to process Windows messages, and properties to get information about an application. The Run( ) method starts a standard application message loop on the current thread. If we execute this program it would merely show a blank form. Let us now see how to attach a menu to this blank form. Carry out the following steps:
The resultant form is shown in the following figure.
Each menu item is governed by a control variable of the type MenuItem. We can change the names of these variables through the 'Properties' window. For the program that follows we have used the names as filemenu that will hold the other menu items, newmenu, openmenu, savemenu, generatemenu and exitmenu. Let us now decide what should happen when these menu items are selected. When we select the ‘Generate’ menu item, shapes like rectangle, ellipse and line should get generated at random and in random colors. On selecting the ‘Save’ menu item these shapes should be saved in a file. We must be able to load this file and display the shapes again. This would be achieved through the ‘Open’ menu item. When we click the ‘New’ menu item the earlier shapes should vanish and we must get a new form to draw new shapes. While saving the shapes we should not save the image of the shape. Instead we should save the relevant information of the shape using which we should be able to regenerate the shape again when the file is loaded. This means we must write the object onto the disk while saving it and load it back while opening the file. This process of writing the state of an object is called serialization and reading it back is called deserialization. To make all these activities to happen we need to add handlers for these menu items. The Windows Forms programming model is event based. When we click on a menu item it raises an event. In order to handle an event, our application should register an event-handling method. For adding these handlers click on the menu item for which we wish to add the handler. Then go to the 'Properties' window and select the 'Events' tab (shown by a yellow lightening icon). From the list of events select 'Click'. As a result an event handler called say, openmenu_Click( ) would get added to our code. On similar lines rest of the handlers can be added. All these handlers will get added to the Form1 class, which is the default class name. Before we add code to these menu handlers let us insert four new classes. The first amongst these is an abstract class called shapes. In this class we will store the color of the shape in variables r, g, b, representing red, green and blue components of the color. The other three classes that we would add are line, rectangle and ellipse. These classes are derived from the shapes class. In these classes we will store the coordinates of the shapes. Each of these three classes would have a constructor to initialize the data members. Each class would have a function draw( ) which would contain the logic to draw the respective shape. This function would be declared as abstract in the base class shapes. To make all the classes capable of carrying out serialization/deserialization we need to add the attribute Serializable as shown in the program listing given below. using System ;
namespace myapp [Serializable] { protected int r, g, b ; r = rd.Next ( 255 ) ;
// put the thread to sleep for next 5 } public abstract void draw ( Graphics g ) ; }
[Serializable] int x1, y1 ;
public line ( int i, int j, int k, int l ) x1 = i ; }
public override void draw ( Graphics gg ) Color c = Color.FromArgb ( r, g, b ) ; } }
[Serializable] int x1, y1 ;
public rectangle ( int x, int y, int h, int w ) x1 = x ; } public override void draw ( Graphics gg ) Color c = Color.FromArgb ( r, g, b ) ; } }
[Serializable] int x1, y1 ;
public ellipse ( int x, int y, int h, int w ) x1 = x ; } public override void draw ( Graphics gg ) Color c = Color.FromArgb ( r, g, b ) ; }
public class Form1 : System.Windows.Forms.Form private System.Windows.Forms.MainMenu
public Form1( ) { InitializeComponent( ) ; }
protected override void Dispose ( bool disposing ) { if( disposing ) { if ( components != null ) components.Dispose( ) ; } } base.Dispose( disposing ) ; }
[STAThread] static void Main( ) { Application.Run ( new Form1 ( ) ) ; }
private void openmenu_Click ( object sender, System.EventArgs e ) OpenFileDialog od = new
if ( od.ShowDialog( ) == DialogResult.OK ) FileInfo f=new FileInfo (
od.FileName);
while ( st.Position != st.Length ) s.Add ( b.Deserialize ( st ) ) ;
st.Close ( ) ; } Invalidate( ) ; }
private void savemenu_Click ( object sender, System.EventArgs e ) { SaveFileDialog sd = new
if ( sd.ShowDialog( ) == DialogResult.OK ) FileInfo f = new
FileInfo(sd.FileName);
st.Close ( ) ; } }
private void generatemenu_Click ( object sender, System.EventArgs e )
Size sz = ClientSize ;
for ( int i = 0 ; i < 10 ; i++ ) int shapeno = rd.Next ( 3 ) ;
switch ( shapeno ) case 0: s.Add ( new line ( x1, y1, x2, y2 ) ) ; case 1: s.Add ( new rectangle ( x1, y1, x2, y2 ) ) ; case 2: s.Add ( new ellipse ( x1, y1, x2, y2 ) ) ; } } Invalidate( ) ; }
private void exitmenu_Click ( object sender, System.EventArgs e ) { Dispose( ) ; }
private void Form1_Paint ( object sender,
Graphics g = e.Graphics ; }
private void newmenu_Click ( object sender, System.EventArgs e ) s.Clear( ) ; } } }
When we click the ‘Generate’ menu item its handler gets called. In this handler an object of the Random class is created. The Next( ) method of this class generates a positive random number less than the specified number passed to it. We have used this function to not only decide which shape should be generated but also the coordinates of this shape. Using these coordinates we have created an object of rectangle, ellipse or line class. While creating these objects the constructors of the respective classes get called. Since all these classes are derived from the shapes class, firstly the base class constructor gets called. This constructor selects a random color. The references of objects of line, rectangle and ellipse are stored using a collection class called ArrayList. The object s of this class now consists of references of objects of the line, rectangle and ellipse classes. As these classes are derived from shapes, it is perfectly legitimate for a reference to shapes to be set up to point to either shapes or one of its derived classes. Next we have called the Invalidate( ) method which results in the Form1_Paint( ) method getting called. Here we have collected back each reference from the array s into a reference ss of type shapes. Using this reference it has then called the draw( ) method. Depending upon which (line, rectangle or ellipse) reference is present in ss the draw( ) function of that class gets called. The resulting form is shown below.
If we wish to save the file we can click on ‘Save’ menu item. When we do so savemenu_Click( ) gets called. We have created an object of the SaveFileDialog class and used a "*.dat" filter for it. When we type in a file name and click Ok, a FileInfo object gets created with the selected name. The Open( ) function returns a Stream object associated with the file. We have collected it in a Stream reference. We have used the BinaryFormatter object to serialize the objects. The BinaryFormatter serializes and deserializes an object, in binary format. We have added a BinaryFormatter object b to our class. The Serialize( ) method of this class serializes the object to the given stream. After serializing all the elements of the array we have closed the stream using the Close( ) method.When we click ‘Open’ menu item an OpenFileDialog is popped with the appropriate filter. Here also we have created a FileInfo object and collected the corresponding Stream of the specified file. Next we have used a while loop to deserialize the objects until the end of stream is reached. The Deserialize( ) method deserializes the specified stream into an object. We have collected these objects into our array, closed the stream and called Invalidate( ) function for painting these shapes. When we click ‘New’ menu item the array is cleared by deleting all the elements in the array. After this we have called Invalidate( ). This time the method Form1_Paint( ) draws nothing as the array is empty, thereby resulting a clean form. On clicking the ‘Exit’ menu item the Dispose( ) method gets called and the form is disposed. |
|
|
Designed and Managed by |
|