Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Signature User Control: Graphics Programming in Smart Phones, PocketPCs, and PDAs

0.00/5 (No votes)
2 Jul 2008 1  
In this article we are going to see the use of graphics in Smart Phones and PDA applications.

Introduction

In this article we are going to see the use of graphics in Smart Phones and PDA applications. The goals of this application are:

  1. To allow users have a basic idea of the C# Graphics class.
  2. Create a signature control for a Smart Phone which uses the C# Graphics class.
  3. Create an Autograph application which uses the signature user control.

Graphics Programming Using C#

Before we go to code explanations, we will start with the C# Graphics class and its methods. With the help of the Graphics class of the System.Drawing namespace, you can render various kinds of shapes. These include Rectangle, Filled Rectangle, Lines, Ellipse, Filled Ellipse, Pie, Filled Pie, and Polygons. This class defines methods for painting these shapes. Each method differs according to the needs of the shapes:

  • Lines, simple shapes.
  • Images from bitmap and other image files.
  • Text.

Similar to a C# Windows application, Smart Phones or PDAs also use graphics classes. Graphics are extensively used in Smart Phone applications where there is a requirement for generating graphs or to get signatures from users.

Namespace Contains
System.Drawing Most of the classes, structs, enums, and delegates concerned with the basic functionality of drawing.

Every method on the Graphics class has to be accessed by creating an object (g) of the Graphics class. The table below shows some of the methods of this class:

Graphics Class Methods
Rectangle DrawRectangle (System.Drawing.Pen, float x, float y, float width, float height) g.DrawRectangle (new Pen(Color.Pink,2), 20,20,300,150);
Filled Rectangle FillRectangle(System.Drawing.Brush, float x, float y, float width, float height) g.FillRectangle (new SolidBrush(Color.Pink), 15,15,200,60);
Line DrawLine(System.Drawing.Pen, float x, float y, float width, float height) g.DrawLine(new Pen(Color.Pink,3), 20,20,300,150);
Ellipse DrawEllipse(System.Drawing.Pen, float x, float y, float width, float height) g.DrawEllipse(new Pen(Color.Pink,3), 15,15,200,150);
Filled Ellipse FillEllipse(System.Drawing.Brush, float x, float y, float width, float height) g.FillEllipse (new SolidBrush(Color.Pink), 20,20,300,150);
Pie DrawPie(System.Drawing.Pen, float x, float y, float width, float height) g.DrawPie(new Pen(Color.Black),120,20,170,160,110,100)
FilledPie FillPie(System.Drawing.Brush, float x, float y, float width, float height) g.FillPie(new Brush(Color.Black),120,20,170,160,110,100)
Polygon DrawPolygon(System.Drawing.Pen, new Point[] { new Point(x,y), new Point(x,y), new Point(x,y), new Point(x,y), new Point(x,y), new Point(x,y)}); g.DrawPolygon(new Pen(Color.Red,2), new Point[] { new Point(140,170), new Point(155,200), new Point(160,245), new Point(195,230), new Point(30,360), new Point(60,200)});
FilledPolygon FillPolygon(System.Drawing.Brush, new Point[] { new Point(x,y), new Point(x,y), new Point(x,y), new Point(x,y), new Point(x,y), new Point(x,y)}); g.FillPolygon(new Brush(Color.Red), new Point[] { new Point(140,170), new Point(155,200), new Point(160,245), new Point(195,230), new Point(30,360), new Point(60,200)});

Using the Pen class, you can specify the color of the border and also the thickness. From the example given above, it can be seen that the Pen class is to be applied for drawing shapes while the Brush class is applied for filling shapes. I hope you got some idea on the Graphics class and its methods from the above table.

Using the Code

Create Signature Control (Signature.dll)

Create a new Smart Device project and name it “SignatureControl”. Select Class Library as the project template.

Now, you have a Visual Studio project with the name "Signaturecontrol" and a class file named “Class1”. Rename the class file to “SignatureControl.cs”.

Include these namespaces:

using System.Windows.Forms;     // To inherit control class
using System.Drawing;           // To use graphics ,Pen class
using System.IO;                // to write the signature to a physical location

and add these references:

  • System.Windows.Forms
  • System.Drawing

The class “SignatureControl” inherits from the “Control” class. It defines the base class for controls, which are components with a visual representation.

public partial class SignatureControl : Control

Now, we will try to override the events and methods that are triggered while a signature is drawn.

/* *************Developed by Lison Jose P
 Software Engineer, Date:23-06-2008 ******************/
#region Namespace
using System;
using System.Collections;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
#endregion
namespace SignatureManipulation
{
    public partial class SignatureControl : Control
    {
        #region Variable declaration
        //GDI object 
        Bitmap bmp;
        //Graphics object 
        Graphics graphics;
        //Pen object
        Pen pen = new Pen(Color.Black);
        // Array List of line segments
        ArrayList signCoord = new ArrayList();
        //Point object
        Point lastPoint = new Point(0, 0);
        // if drawing signature or not
        bool drawSign = false;
        #endregion
        #region Constructor
        public SignatureControl()
        {
            //Default Constructor
        }
        #endregion
        #region Override Events
        #region OnPaint
        /// <summary>
        /// Create GDI object.Initilize memory bitmap where we draw the
        /// signature.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            // we draw on the memory bitmap on mousemove so there
            // is nothing else to draw at this time 
            CreateGdiObjects();
            e.Graphics.DrawImage(bmp, 0, 0);
        }
        #endregion
        #region OnPaintBackground
        /// <summary>
        /// Override OnPaintBackground to avoid flashing
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // don't pass to base since we paint everything, avoid flashing
        }
        #endregion
        #region OnMouseDown
        /// <summary>
        /// OnMouseDown, get the new X,Y  coordinates
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            // process if currently drawing signature
            if (!drawSign)
            {
                // start collecting points
                drawSign = true;
                // use current mouse click as the first point
                lastPoint.X = e.X;
                lastPoint.Y = e.Y;
            }
        }
        #endregion
        #region OnMouseUp
        /// <summary>
        /// Set bool drawsign to false
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            // process if drawing signature
            if (drawSign)
            {
                // stop collecting points
                drawSign = false;
            }
        }
        #endregion

        #region OnMouseMove
        /// <summary>
        /// Draw line and get new X,Y coordinates
      /// Each drawn coordinates are added in to an arrayList (signCoord )
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            // process if drawing signature
            if (drawSign)
            {
                if (graphics != null)
                {
                    // draw the new segment on the memory bitmap
                    graphics.DrawLine(pen, lastPoint.X, lastPoint.Y, e.X,e.Y);
                    signCoord .Add(lastPoint.X + " " + lastPoint.Y + " " + e.X + " " + e.Y);
                    // update the current position
                    lastPoint.X = e.X;
                    lastPoint.Y = e.Y; 
                    // Invalidates the entire surface of the control and
                    //causes the control to be redrawn. 
                    Invalidate();
                }
            }
        }
        #endregion
        #endregion


        #region Methods
        #region Clear
        /// <summary>
        /// Clear the signature.
        /// </summary>
        public void Clear()
        {
            signCoord .Clear();
            InitBitMap();
            Invalidate();
        }
        #endregion
        #region CreateGdiObjects
        /// <summary>
        /// Create an bitMap objects, required to draw signature.
        /// </summary>
        private void CreateGdiObjects()
        {
            if (bmp == null || bmp.Width != this.Width || bmp.Height != this.Height)
            {
                // memory bitmap to draw on
                InitBitMap();
            }
        }
        #endregion
        #region InitBitMap
        /// <summary>
        ///Initilize the bitmap that is used to draw the signature.
        /// </summary>
        private void InitBitMap()
        {
            // load the background image            
            bmp = new Bitmap(this.Width, this.Height);
            graphics = Graphics.FromImage(bmp);
            graphics.Clear(Color.SlateGray);
        }
        #endregion
        #region StoreSigData
        /// <summary>
        /// Get each set of coordinates from the arrayList and concatinate  
        /// in to a single string. 
        /// </summary>
        /// <param name="fileName">file name 
        /// (physical position to store the signature coordinates)</param>
        public void StoreSigData(String fileName)
        {
            string sigData = "";
            for (int i = 0; i < signCoord .Count; i++)
            { 
                sigData = sigData + signCoord [i].ToString() + "\n";
            }
            CreateFile(fileName, sigData);
        }
        #endregion
        #region CreateFile
        /// <summary>
        /// To create signature file in a physical location. (System.IO)
        /// File consist of each co-ordinates of the signature
        /// </summary>
        /// <param name="fileName">file name</param>
        /// <param name="fileContent">file contents (signature 
        /// coordinates</param>
        private void CreateFile(String fileName, String fileContent)
        {
            StreamWriter sr = File.CreateText(fileName);
            sr.WriteLine(fileContent);
            sr.Close();
        }
        #endregion
        #region getSignCoord 
        /// <summary>
        /// Get all signature coordinates that are stored in arrayList
        /// Return the signature arraylist to the calling form.
        /// On the calling Form, this coordinates can be stored in to
        /// database.
        /// </summary>
        /// <returns>arraylist of signature co-ordinates</returns>
        public ArrayList getSignCoord ()
        {
            return signCoord ;
        }
        #endregion
        #region GetSignData
        /// <summary>
        /// Calling Form take the signature coordinates from file or database
        /// and send as string array to this method.
        /// This method retrive each coordinates from string array 
        /// and send
        /// </summary>
        /// <param name="result">signature co-ordinates</param>
        public void GetSignData(string[] result)
        {
            Graphics graphics;
            // load the background image            
            bmp = new Bitmap(this.Width, this.Height);
            graphics = Graphics.FromImage(bmp);
            graphics.Clear(Color.SlateGray);
            for (int i = 0; i < result.Length - 2; i++)
            {
                string[] strArr = new string[4];
                strArr = ((result[i].ToString()).Split(' '));
                graphics.DrawLine(pen, Convert.ToInt32(strArr[0].ToString()),
                                  Convert.ToInt32(strArr[1].ToString()),
                                  Convert.ToInt32(strArr[2].ToString()),
                                  Convert.ToInt32(strArr[3].ToString()));
                Invalidate();
                strArr = null;
            }
        }
        #endregion
        #endregion
   }
}

Now, select the output type as ClassLibrary from the project properties and build the project. The SignatureControl.dll file is created in the project bin folder.

Create Autograph Application Using Signature Control (Signature.dll)

Sample Screen (Autograph .exe)

Create a new Smart Device project and select Device Application template. Name the project as “Autograph”. First, we create the database for this application. Add a new SQL Mobile Database (.SDF) to the project. Name it SignatureDB.sdf. Add a table named tblSignature. Include these fields in the table: signName (nvarchar), signRegard (nvarchar), and signSignature (ntext).

Now, create a class file for our Autograph application. Add a new class file inside a folder named “Component” and name the class file as Signature.cs.

Signature.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlServerCe;
using System.Reflection;
using System.IO;

namespace Autograph.Component
{
    class Signature
    {
        private string _name=string.Empty;
        private string _signature=string.Empty;
        private string _regards = string.Empty;

        public string Name
        {
            set { _name = value; }
            get { return _name; }
        }

        public string Sign
        {
            set { _signature = value; }
            get { return _signature; }
        }

        public string Regards
        {
            set { _regards = value; }
            get { return _regards; }
        }

        #region GetSqlCeConnection
        /// <summary>
        /// Method to connect to sql Server
        /// </summary>
        ///<returns>SqlCeConnection</returns>
        public static SqlCeConnection GetSqlCeConnection()
        {
            SqlCeConnection cnMindNet = null;
            String connString = Assembly.GetExecutingAssembly().GetName().CodeBase;
            connString = connString.Replace("Autograph.exe", "SignatureDB.sdf");
            cnMindNet = new SqlCeConnection(String.Format("Data Source={0}", connString));
            return cnMindNet;
        }
        #endregion

        #region SetSign
        /// <summary>
        /// Set the signature deails to database
        /// </summary>
        public void SetSign()
        {
            using (SqlCeConnection conn = GetSqlCeConnection())
            {
                conn.Open();

                string query = "insert into tblSignature (signName,signRegards," + 
                               "signSignature) values " +
                               " ( @name,@regards,@sign )";
                SqlCeCommand cmd = new SqlCeCommand(query, conn);
                cmd.CommandType = CommandType.Text;
                cmd.Parameters.Add("@name", SqlDbType.NVarChar).Value = _name;
                cmd.Parameters.Add("@regards", SqlDbType.NVarChar).Value = _regards;
                cmd.Parameters.Add("@sign", SqlDbType.NText).Value = _signature;
                cmd.ExecuteNonQuery();
            }
        }
        #endregion
        #region GetSign 
        /// <summary>
        /// Get the Signature details from database
        /// </summary>
        /// <returns>Table of signature details</returns>
        public DataTable GetSign()
        {
            using (SqlCeConnection conn = GetSqlCeConnection())
            {
                conn.Open();
                DataTable dt = new DataTable();
                string query = "select signName,signRegards," + 
                               "signSignature from tblSignature";

                SqlCeCommand cmd = new SqlCeCommand(query, conn);
                cmd.CommandType = CommandType.Text;
                SqlCeDataAdapter da = new SqlCeDataAdapter(cmd);
                da.Fill(dt);
                return dt;
            }
        }
        #endregion

    }
}

The database type is SQL Mobile Database (.SDF), so add this namespace:

using System.Data.SqlServerCe;

Now, add two forms to this project: one to add signature and the other to view the signatures. Name them as frmSignature.cs and frmViewAll.cs. Design the form as in the above sample screenshots. The code for the forms follows.

frmSignature.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace Autograph
{
    public partial class frmSignature : Form
    {
        #region Constructor
        public frmSignature()
        {
            InitializeComponent();
            txtName.Focus();
        }
        #endregion

        #region lnklProcess_Click
        private void lnklProcess_Click(object sender, EventArgs e)
        {
            
            Cursor.Current = Cursors.WaitCursor;
            ArrayList arrSign = new ArrayList();
            arrSign = uctrlSignature.getPVector();

            if (txtName.Text.Trim() == string.Empty)
            {
                MessageBox.Show(" Name please ", "Autograph", 
                       MessageBoxButtons.OK, MessageBoxIcon.Asterisk,
                       MessageBoxDefaultButton.Button1);
                Cursor.Current = Cursors.Default;   
                return;
            }

            if (arrSign.Count > 0)
            {
                string singature = "";

                for (int i = 0; i < arrSign.Count; i++)
                {
                    singature = singature + arrSign[i].ToString() + "*";
                }

                Component.Signature objSign = new Autograph.Component.Signature();
                objSign.Name = txtName.Text;
                objSign.Regards = txtNotes.Text;
                objSign.Sign = singature;
                objSign.SetSign();                           
                MessageBox.Show(" Thank You :) ", "Autograph", MessageBoxButtons.OK, 
                                MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
            }
            else
            {
                MessageBox.Show(" Signature please ", "Autograph", MessageBoxButtons.OK,
                                MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button1);
            }

            Cursor.Current = Cursors.Default;
        }
        #endregion

        #region lnklClear_Click
        private void lnklClear_Click(object sender, EventArgs e)
        {
            uctrlSignature.Clear();
        }
        #endregion

        #region lnklView_Click
        private void lnklView_Click(object sender, EventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            frmViewAll objView = new frmViewAll();
            objView.Show();
        }
        #endregion

        #region miAbout_Click
        private void miAbout_Click(object sender, EventArgs e)
        {
            frmAbout objAbout = new frmAbout();
            objAbout.Show();
        }
        #endregion

        #region miClose_Click
        private void miClose_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        #endregion

        #region frmSignature_Closing
        private void frmSignature_Closing(object sender, CancelEventArgs e)
        {
            Application.Exit();
        }
         #endregion
    }
}

frmViewAll.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Autograph
{
    public partial class frmViewAll : Form
    {
        bool flag = false;

        #region Constructor
        public frmViewAll()
        {
            InitializeComponent();
            txtLookUp.Focus();
        }
        #endregion

        #region frmViewAll_Load
        private void frmViewAll_Load(object sender, EventArgs e)      
        {            
            Component.Signature objSign = new Autograph.Component.Signature();
            DataTable dtSign = objSign.GetSign();

            if (dtSign.Rows.Count > 0)
            {
                flag = true;
                for (int i = 0; i < dtSign.Rows.Count; i++)
                {
                    DataRow dr = dtSign.Rows[i];
                    ListViewItem item = new ListViewItem(dr["signName"].ToString());
                    item.SubItems.Add(dr["signRegards"].ToString());
                    item.SubItems.Add(dr["signSignature"].ToString());
                    lsvItem.Items.Add(item);
                }
            }
            Cursor.Current = Cursors.Default;
        }
        #endregion

        #region lsvItem_SelectedIndexChanged
        private void lsvItem_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (flag)
            {
                Cursor.Current = Cursors.WaitCursor;
                if (lsvItem.FocusedItem != null)
                {
                    string[] arrStr = (lsvItem.FocusedItem.SubItems[2].Text).Split('*');
                    uctrlSignature.GetSignData(arrStr);
                }
                Cursor.Current = Cursors.Default;
            }
        }
        #endregion

        #region txtLookUp_TextChanged
        private void txtLookUp_TextChanged(object sender, EventArgs e)
        {
            string strLook = string.Empty;
            string check = string.Empty;
            string strLookUp = txtLookUp.Text;
            int resultRow = 0;
            if (strLookUp != "")
            {
                for (int i = 0; i < lsvItem.Items.Count; i++)
                {
                    strLook = lsvItem.Items[i].SubItems[0].Text.ToLower();

                    if (strLookUp.Length <= strLook.Length)
                    {
                        check = strLook.Substring(0, strLookUp.Length).ToLower();

                        if (check == strLookUp)
                        {
                            resultRow = i;
                            lsvItem.Items[resultRow].Focused = true;
                            lsvItem.Items[resultRow].Selected = true;
                            break;
                        }
                    }
                }
            }
        }
        #endregion

        #region miBack_Click
        private void miBack_Click(object sender, EventArgs e)
        {
            this.Close();
            this.Dispose();
        }
        #endregion

        #region miClose_Click
        private void miClose_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
        #endregion
        #region uctrlSignature_GotFocus
        private void uctrlSignature_GotFocus(object sender, EventArgs e)
        {
            uctrlSignature.Capture = false;
        }
        #endregion
    }
}

Run the application in your mobile device. Now you don’t need to go and search for paper and pen if there comes a celebrity or your loved one to have their “Autograph” with you. Just open this application on your mobile and have it electronically. It also helps you to store other details like, phone number, list of items etc., and it is easy to retrieve as well.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here