[
Advertise | Submit Code | About us | Contact us | Link us
]
Go!
Membership Services
Login
Register

Home
C# General

General

C# Language

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting
C# Windows Forms

General

Combo and List boxes

Miscellaneous Controls

Button Controls

Edit Controls
Cutting Edge

ASP.NET 2.0

Visual Studio 2005

Windows Longhorn

SQL Server 2005
C# Multimedia and GDI+

General

DirectX

GDI+

Audio
Internet & Web

General

Images and multimedia

Database

Utilities

Security

ASP.NET Controls

Design and Architecture

Webservices
.NET

General

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting

ADO.NET

XML.NET

Tools

Enterprise

IDE
Visual Basic .NET

VB.NET General

VB.NET Controls
General Reading

.NET Books Review

Product Showcase

Book Chapters

Business Design & Strategy
Community

Discuss

Job Board

Discussion

CodeXchange
DeveloperLand

Advertise

Submit Code

About us

Contact us

Link us
Miscellaneous

Favorite Links

Downloads

Programming Sites

Top Stories
Regular Expressions

E-Mail

Date/Time
Home > C# Windows Forms > General
Responding to Mouse Events
Posted by on Saturday, August 21, 2004 (EST)

A Tic Tac Toe program is used to learn how to respond to mouse clicks, and more about drawing on a Form.

This article has been viewed: 2,870 times
Technology: General.

Contents

Introduction

This example is based on the program TicTac from the book Programming Windows 95 with MFC by Jeff Prosise.  There is a newer edition called
Programming Windows With MFC [^].

I chose this example to learn how to handle mouse events in C# and .NET.
 

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

namespace TicTac
{
   /// 
   /// Summary description for Form1.
   /// 
   public class FTicTac : System.Windows.Forms.Form
   {
      private int[] m_nGameGrid;
      private int m_nNextChar;
      private Rectangle[] m_rcSquares;
      private const int EX = 1;
      private const int OH = 2;
      private bool m_bDoubleClick = false;

      /// 
      /// Required designer variable.
      /// 
      private System.ComponentModel.Container components = null;

      public FTicTac()
      {
         //
         // Required for Windows Form Designer support
         //
         InitializeComponent();

         m_nNextChar = EX;
         m_nGameGrid = new int[9];
         m_rcSquares = new Rectangle[9];
         Size size = new Size( 96, 96 );
         for( int j = 0 ; j < 9 ; j++ )
         {
            m_rcSquares[j].Size = size;
         }
         m_rcSquares[0].Offset(  16,  16 );
         m_rcSquares[1].Offset( 128,  16 );
         m_rcSquares[2].Offset( 240,  16 );
         m_rcSquares[3].Offset(  16, 128 );
         m_rcSquares[4].Offset( 128, 128 );
         m_rcSquares[5].Offset( 240, 128 );
         m_rcSquares[6].Offset(  16, 240 );
         m_rcSquares[7].Offset( 128, 240 );
         m_rcSquares[8].Offset( 240, 240 );
      }

      /// 
      /// Clean up any resources being used.
      /// 
      protected override void Dispose( bool disposing )
      {
         if( disposing )
         {
            if (components != null) 
            {
               components.Dispose();
            }
         }
         base.Dispose( disposing );
      }

      #region Windows Form Designer generated code
      /// 
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// 
      private void InitializeComponent()
      {
         // 
         // FTicTac
         // 
         this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
         this.ClientSize = new System.Drawing.Size(292, 273);
         this.Name = "FTicTac";
         this.Text = "Tic Tac Toe";

      }
      #endregion

      /// 
      /// The main entry point for the application.
      /// 
      [STAThread]
      static void Main() 
      {
         Application.Run(new FTicTac());
      }

      protected override void OnMouseDown( MouseEventArgs e )
      {
         switch( e.Button )
         {
            case MouseButtons.Left:
               OnLButtonDown( new Point( e.X, e.Y ) );
               break;
            case MouseButtons.Right:
               OnRButtonDown( new Point( e.X, e.Y ) );
               break;
         }
         base.OnMouseDown( e );
      }

      private void OnLButtonDown( Point p )
      {
         if( m_bDoubleClick )
         {
            m_bDoubleClick = false;
            return;
         }
         if( m_nNextChar != EX )
         {
            return;
         }
         int nPos = GetRectID( p );
         if( nPos == -1 )
         {
            return;
         }
         if( m_nGameGrid[nPos] != 0 )
         {
            return;
         }
         m_nNextChar = OH;
         m_nGameGrid[nPos] = EX;

         Graphics g = this.CreateGraphics();
         DrawX( g, nPos );
         g.Dispose();

         CheckForGameOver();
      }

      private void OnRButtonDown( Point p )
      {
         if( m_bDoubleClick )
         {
            m_bDoubleClick = false;
            return;
         }
         if( m_nNextChar != OH )
         {
            return;
         }
         int nPos = GetRectID( p );
         if( nPos == -1 )
         {
            return;
         }
         if( m_nGameGrid[nPos] != 0 )
         {
            return;
         }
         m_nNextChar = EX;
         m_nGameGrid[nPos] = OH;

         Graphics g = this.CreateGraphics();
         DrawO( g, nPos );
         g.Dispose();

         CheckForGameOver();
      }

      protected override void OnDoubleClick( EventArgs e )
      {
         m_bDoubleClick = true;

         ResetGame();
         
         base.OnDoubleClick( e );
      }

      protected override void OnPaint( PaintEventArgs pe )
      {
         Graphics g = pe.Graphics;
         DrawBoard( g );
      }

      private int GetRectID( Point p )
      {
         for( int i = 0 ; i < 9 ; i++ )
         {
            if( m_rcSquares[i].Contains( p ) )
            {
               return( i );
            }
         }
         return( -1 );
      }

      private void DrawBoard( Graphics g )
      {
         Pen myPen = new Pen( Color.Black, 16 );
         g.DrawLine( myPen, 120, 16, 120, 336 );
         g.DrawLine( myPen, 232, 16, 232, 336 );
         g.DrawLine( myPen, 16, 120, 336, 120 );
         g.DrawLine( myPen, 16, 232, 336, 232 );
         for( int i = 0 ; i < 9 ; i++ )
         {
            if( m_nGameGrid[i] == EX )
            {
               DrawX( g, i );
            }
            else if( m_nGameGrid[i] == OH )
            {
               DrawO( g, i );
            }
         }
         myPen.Dispose();
      }

      private void DrawX( Graphics g, int nPos )
      {
         Pen myPen = new Pen( Color.Red, 16 );
         g.DrawLine( myPen,
            m_rcSquares[nPos].Left+16, m_rcSquares[nPos].Top+16,
            m_rcSquares[nPos].Right-16, m_rcSquares[nPos].Bottom-16 );
         g.DrawLine( myPen,
            m_rcSquares[nPos].Left+16, m_rcSquares[nPos].Bottom-16,
            m_rcSquares[nPos].Right-16, m_rcSquares[nPos].Top+16 );
         myPen.Dispose();
      }

      private void DrawO( Graphics g, int nPos )
      {
         Pen myPen = new Pen( Color.Blue, 16 );
         Rectangle rect = new Rectangle();
         rect = m_rcSquares[nPos];
         rect.Inflate( -16, -16 );
         g.DrawEllipse( myPen, rect );
         myPen.Dispose();
      }

      private void ResetGame()
      {
         m_nNextChar = EX;
         for( int j = 0 ; j < m_nGameGrid.Length ; j++ )
         {
            m_nGameGrid[j] = 0;
         }
         this.Invalidate();
      }

      private void CheckForGameOver()
      {
         int nWinner = IsWinner();
         
         switch( nWinner )
         {
            case 0:
               if( IsDraw() )
               {
                  MessageBox.Show( "It's a draw!", "Tic Tac Toe" );
                  ResetGame();
               }
               break;
            case EX:
               MessageBox.Show( "X Wins!", "Tic Tac Toe" );
               ResetGame();
               break;
            case OH:
               MessageBox.Show( "O Wins!", "Tic Tac Toe" );
               ResetGame();
               break;
         }
      }

      private int IsWinner()
      {
         int[,] nPattern = 
         {
            { 0, 1, 2 },
            { 3, 4, 5 },
            { 6, 7, 8 },
            { 0, 3, 6 },
            { 1, 4, 7 },
            { 2, 5, 8 },
            { 0, 4, 8 },
            { 2, 4, 6 }
         };
         for( int i = 0 ; i < 8 ; i++ )
         {
            if( ( m_nGameGrid[nPattern[i,0]]== EX )
               && ( m_nGameGrid[nPattern[i,1]] == EX )
               && ( m_nGameGrid[nPattern[i,2]] == EX ) )
            {
               return( EX );
            }
            if( ( m_nGameGrid[nPattern[i,0]]== OH )
               && ( m_nGameGrid[nPattern[i,1]] == OH )
               && ( m_nGameGrid[nPattern[i,2]] == OH ) )
            {
               return( OH );
            }
         }
         return( 0 );
      }

      private bool IsDraw()
      {
         for( int i = 0 ; i < 9 ; i++ )
         {
            if( m_nGameGrid[i] == 0 )
            {
               return( false );
            }
         }
         return( true );
      }
   }
}

The properties for the Form which appear in InitializeComponent() were set using the Properties Window.  When modifying these, or other properties, use the Properties Window instead of editing the code.

The OnMouseDown() event occurs twice during a double click, in addition to OnDoubleClick().  The second OnMouseDown() occurs after OnDoubleClick(), so I set a flag to cause the OnLButtonDown() and OnRButtonDown() functions to return immediately.  This code could be moved to OnMouseDown(), but needs to be done so as not to skip the base.OnMouseDown( e ) call.

To zero my array in the ResetGame() function, I tried m_nGameGrid.Initialize, but this did not work.  Checking the documentation, I found this:

CAUTION   This method can only be used on value types that have constructors, and value types that are native to C# do not have constructors.

If you want to trigger a call to OnPaint() use this.Invalidate().  To draw outside the OnPaint() function, obtain a graphics object using Graphics g = this.CreateGraphics().

Top Go to Table of Contents

About Bill Burris

3D Graphics, OpenGL AI Python, C#, C++

Click here if you want to know more about .

Other articles that may interest you

  • Write a Word Add-In – Part 0
  • Write a Word Add-In – Part I
  • Lengthy Operations on Single Thread in .NET Application
  • Learning Draughts
  • Exceptions and Performance
  • Average Rating :

    Discussion Forums
    Got a programming related question? Hopefully someone has the answer... Want to help out other developers? Visit our discussion forums.

    Sponsored by:

    New Articles

  • Exceptions and Performance
    Almost every time exceptions are mentioned in mailing lists and newsgroups, people say they're really expensive.Let's examine that claim, shall we?

  • Creating multilingual websites - Part 1
    Extend the existing globalization capabilities of .NET to create flexible and powerful multilingual web sites. First, create a custom ResourceManager, and then create custom localized-capable server controls to easily deploy multilingual functionality.

  • Parameter passing in C#
    Many people have become fairly confused about how parameters are passed in C#, particularly with regard to reference types. This page should help to clear up some of that confusion

  • Most Popular Articles

  • LDAP, IIS and WinNT Directory Services
    This article explains how to use .NET Directory Services to retrieve and search directory objects, create new directory objects and edit or delete existing directory objects. Describes Active Directory Application Mode (ADAM) and how to use the IIS, WinNT and LDAP directory (ADSI) provider.

  • An in-depth look at WMI and instrumentation, Part II
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article is the second part of a two-part series.

  • An in-depth look at WMI and instrumentation, Part I
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article provides an in-depth look at WMI and MOM 2005

  • New Books

  • Murach's ASP.NET 2.0 Upgrader's Guide: VB Edition
    What’s new and how to use it! That’s what this book delivers if you’re a VB developer who’s interested in upgrading from ASP.NET 1.x to ASP.NET 2.0.

  • C# in easy steps
    Learn to program with Microsoft’s premier programming language. No previous programming knowledge is assumed. With numerous easy-to-follow examples, this title explains the essentials of object-oriented programming with C#.

  • Murach's ASP.NET web programming with VB.NET
    Murach's ASP.NET web programming with VB.NET by Doug Lowe and Anne Prince is a in depth training and reference book for ASP.NET programming using VB.NET. The book builds upon Murach's previous books and covers more advanced concepts for programming ASP.NET pages.

  • Got Code?

    if you have any article , source code , or anything else you'd like to share with this community that you think others might find useful, please submit it here and we will gladly make it available on this site. submit@developerland.com.
    Partners

    All articles are copyrighted by their individual authors unless otherwise specified , everything else Copyright ©2004-2006 DeveloperLand