Home

Microsoft Visual C++/CLI Programming: Events of Windows Controls

 

Fundamentals of Events

 

Introduction

A Windows control is an object that allows a person to interact with a computer. The object is made part if an application. A person can use to submit a number, to request a value, or to present a behavior. When a control A requests a value or service from another control B, control A is referred to as a client of control B. This relationship is important not simply because it ensures the flow of data between both controls but also because control B should be ready to provide the value or behavior that a client needs at a certain time.

While a control B is asked to provide some values to, or perform some assignment(s) for, another control A, many things could happen. In fact, there is an order that the actions should follow. For example, during the lifetime of a program, that is, while a program is running, a control may be holding a value it can provide to its client but at another time, that value may not be available anymore, for any reason; nothing strange, this is just the way it happens. Because different things can happen to a control B while a program is running, and because only control B would be aware of these, it must be able to signal to the other control when there is a change. This is the basis of events: An event is an action that occurs on an object and affects it in a way that its clients must be made aware of.

As mentioned already, an event is an action that occurs. For example, suppose you are spaghetti and the red sauce regularly draws some lines on your lips. You know this because your brain sends a signal that your mouth is dirty. To appear fine, you must wipe your mouth regularly. Every time you have wiped your mouth, another signal is sent to the brain to let it know that your mouth is fine now (and when the mouth becomes dirty again, another signal lets the brain know). These signals prompt you to do something. Signaling an event is also referred to as firing it.

Based on its concept, an event is carried by a delegate. This means that, in order to fire an event, you must have defined an appropriate delegate. For good habits, the name of a delegate that signals an event includes EventHandler. For example, if you are declaring a delegate that would carry the signal when your mouth has been wiped, you may call it WipeMouthEventHandler. The WipeMouth part indicates the possible type of signal. The EventHandler part specifies that this delegate is primarily used to handle an event.

A delegate may need additional information, as argument(s) in order to carry its signal. You can declare a delegate that doesn't take an argument. For example, when the mouth has been wiped, if you simply want to signal that it has been, you can fire a simple event accordingly. The delegate of such an event may not take any argument. It could be declared as follows:

delegate void WipeMouthEventHandler();

You can also have a delegate that takes one argument. For example, if you want to define a delegate that would carry the signal that your mouth has been wiped, the delegate can take as arguments the name of the hand that wiped the mouth (unless you can afford an assistant who would do that for you). Such a delegate could be declared as follows:

delegate void WipeMouthEventHandler(int LeftOrRightHand);

You can also have a delegate that takes more than one argument. For example, when you wipe your mouth, you may use the reverse of your hand, your shirt, or a napkin. To define your delegate, you can provide an additional argument that specifies what you would use to wipe your mouth.

As seen earlier, after declaring a delegate, you must define the method that implements it. Here is an example:

delegate void WipeMouthEventHandler(int LeftOrRightHand);

public ref class CExercise : public Form
{
public:
	CExercise(void)
	{
		InitializeComponent();
	}

private:
	void InitializeComponent()
	{
	}
	
	static void MouthWiper(int LeftOrRightHand)
	{
	}
};
 

Practical LearningPractical Learning: Introducing Events

  1. Star Microsoft Visual C++
  2. To create a new application, on the main menu, click File -> New -> Project...
  3. In the Project Types list, click Visual C++ and, In the middle list, click Windows Forms Application
  4. In the Name box, replace the content with RectangleExercise2 and press Enter
  5. Design the form as follows:
     
    Control Text Name
    Label Length:  
    TextBox 0.00 txtLength
    Label Height:  
    TextBox 0.00 txtHeight
    Button Calculate btnCalculate
    Label Perimeter:  
    TextBox 0.00 txtPerimeter
    Label Area:  
    TextBox 0.00 txtArea
    Button Close btnClose
  6. To create a new class, on the main menu, click Project -> Add Class...
  7. In the Categories list, expand Visual C++ and click C++
  8. In the middle list, make sure C++ Class is selected and click Add
  9. Set the Class Name to CRectangle and click Finish
  10. Change the Rectangle.h header file as follows:
    #pragma once
    
    public ref class CRectangle
    {
    private:
        double len;
        double hgt;
    
    public:
        CRectangle(void);
        CRectangle(double length, double height);
    
        property double Length
        {
    	double get() { return len; }
    	void set(double L) { len = L; }
        }
    
    	property double Height
        {
            double get() { return hgt; }
            void set(double H) { hgt = H; }
        }
    
        property double Perimeter
        {
            double get() { return (len + hgt) * 2; }
        }
    
        property double Area
        {
            double get() { return len * hgt; }
        }
    };
  11. Change the Rectangle.cpp source file as follows:
    #include "StdAfx.h"
    #include "Rectangle.h"
    
    CRectangle::CRectangle(void)
        : len(0.00), hgt(0.00)
    {
    }
    
    CRectangle::CRectangle(double length, double height)
        : len(length), hgt(height)
    {
    }

Event Creation

An event is declared like a pseudo-variable but based on a delegate. To actually declare an event, you use the event keyword with the following formula:

Access Level event PointerToDelegate NameOfEvent;

The Access Level factor specifies whether the events will be used as private, public, or protected using the appropriate C++ keyword: public, private, or protected. You can omit the access level. If you do, the event is considered private.

The event keyword is required.

To define an event, you must specify the delegate that is used to carry the event. To do this, you must provide the delegate as a handle.

Like everything in a program, an event must have a name. This would allow the clients to know what (particular) event occurred. To be indicative, the name of an event starts with On and usually ends with the beginning name of its delegate without the EventHandler part. Here is an example:

delegate void WipeMouthEventHandler(int LeftOrRightHand);

public ref class CExercise : public Form
{
public:
	event WipeMouthEventHandler ^ OnWipeMouth;

	CExercise(void)
	{
	}
};

When the event occurs, its delegate would be invoked. This specification is also referred to as hooking up an event. As the event occurs (or fires), the method that implements the delegate runs. This provides the functionality of the event and makes the event ready to be used. Both the declarations of the delegate and of the event we have performed above are not related, we only gave them names that resemble each other. Before using an event, you must combine it to the delegate that will carry it. To do this, you must declare a handle to the event. To initialize it, you would call the constructor of the delegate, passing it the two arguments that we reviewed earlier. To combine the delegate and the event, you initialize the event using the += operator. Once this is done, you can call the event. Here is an example:

//#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public delegate void WipeMouthEventHandler(int LeftOrRightHand);

public ref class CExercise : public Form
{
public:
	event WipeMouthEventHandler ^ OnWipeMouth;

	CExercise(void)
	{
		InitializeComponent();
	}

private:
	void InitializeComponent()
	{
		OnWipeMouth += gcnew WipeMouthEventHandler(&MouthWiper);
	}
	
	static void MouthWiper(int LeftOrRightHand)
	{
	}
};

int APIENTRY WinMain(HINSTANCE hInstance,
		     HINSTANCE hPrevInstance,
		     LPSTR lpCmdLine,
                     int nCmdShow)
{
	Application::Run(gcnew CExercise());

	return 0;
}

Implementation of Events

 

Introduction

An application is made of various objects or controls. During the lifetime of an application, its controls regularly send messages to the operating system to do something on their behalf. These messages are similar to human messages and must be processed appropriately. Since most of the time more than one application is running on the computer, the controls of such an application also send messages to the operating system. As the operating system is constantly asked to perform these assignments, because there can be so many requests presented unpredictably, the operating system leaves it up to the controls to specify what they want, when they want it, and what behavior or result they expect. These scenarios work by the controls sending events.

Events in the .NET Framework are implements through the delegates. The most common events have already been created for the objects of the .NET Framework controls so much that you will hardly need to define new events, at least not in the beginning of your GUI programming adventure. Most of what you will do consists of implementing the desired behavior when a particular event fires. To start, you should know what events are available, when they are needed, how they work, and what they produce.

To process a message, it (the message) must provide at least two pieces of information: What caused the message and what type of message is it? Both values are passed as the arguments to the event. Since all controls used in the .NET Framework are based on the Object class, the first argument must be an Object type and represents the control that sent the message. 

As mentioned already, each control sends its own messages when necessary. Some messages are unique to some controls according to their roles. Some other messages are common to various controls, as they tend to provide similar actions. To manage such various configurations, the .NET Framework considers the messages in two broad categories.

Some messages don't require much information. This type of message would be sent without much detailed information. This type of message is carried by an argument of type EventArgs passed as the second parameter of the event.

Some messages must be accompanied by additional information. When a message must carry additional information, the control that sent the message specifies that information by the name of the second argument. Because there are various types of messages like that, there are also different types of classes used to carry such messages. We will introduce each class when appropriate.

Event Implementation

Although there are different means of implementing an event, there are three main ways you can initiate its coding. If the control has a default event and if you double-click it, the studio would initiate the default event and open the Code Editor. The cursor would be positioned in the body of the event's code, ready to receive your instructions. Another technique you can use consists of displaying the form first and clicking either the form or the control that will fire the event. Then, in the Properties window, click the Events button Events, and double-click the name of the event you want to use.

You can also manually code an event. To do this, first define the method that will carry the event. Here is an example:

public ref class CExercise : public Form
{
public:
	CExercise(void)
	{
		InitializeComponent();
	}

private:
	void InitializeComponent()
	{
	}
	
	Void WasClicked(Object ^ sender, EventArgs ^ e)
	{
		Close();
	}
};

Then, add the control if it is not added yet. Use the += operator to assign the type of delegate that handles the event, passing as the second argument the name of the method defined above. This assignment must be performed on the name of the event that will be fired. Here is an example:

#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class CExercise : public Form
{
private:
    Button ^ btnClose;
public:
    CExercise(void)
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	btnClose = gcnew Button;
	btnClose->Text = L"Close";
	btnClose->Click += gcnew EventHandler(this, &CExercise::WasClicked);
	Controls->Add(btnClose);
    }
	
private:
    void WasClicked(Object ^ sender, EventArgs ^ e)
    {
	Close();
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
    Application::Run(gcnew CExercise);
    return 0;
}

When a new control has been added to the application, the Control::ControlAdded event is fired. You will usually not be concerned with this event because you know when a control has been added and if the addition was successful. Nevertheless, this control exists and its syntax is:

public:
    event ControlEventHandler ^ ControlAdded;

The ControlAdded event is carried by a ControlEventHandler delegate through the ControlEventArgs class. The constructor of this class has the following syntax:

public:
    ControlEventArgs(Control^ control);

This class has only one property called Control and defined as follows:

public:
    property Control ^ get_Control();

The control argument of the constructor and the Control property specify the name of the control that fired this event.

Practical LearningPractical Learning: Generating an Event

  1. Display the form and double-click the Close button
  2. Notice that the caret is positioned in the Code Editor inside the code of the event
  3. Implement the event as follows:
    System::Void btnClose_Click(System::Object^  sender, System::EventArgs^  e)
    {
        Close();
    }
  4. Execute the application to test it and click the Close button
 
 
 

Controls Events

 

Control Painting

After a control has been added to a form, it can be used. For example, it can be displayed to the user at run time. While an application is opening on the screen or it needs to be shown, the operating system must display the form's controls. To do this, the controls colors and other visual aspects must be retrieved and restored. This is done by painting the control. If the form that hosts the controls was hidden somewhere such as behind another window or was minimized, when it comes up, the operating system needs to paint it (again).

When a control gets painted, it fires the Paint() event. The syntax of the Paint() event is:

public:
    event PaintEventHandler Paint;

This event is carried by a PaintEventHandler delegate declared as follows:

public:
    delegate void PaintEventHandler(Object^ sender, PaintEventArgs^ e)

This means that the Paint event is performed using an object of type PaintEventArgs. The PaintEventArgs class is equipped with two valuable properties. The PaintEventArgs::Graphics property represents the object on which the painting must be performed. The PaintEventArgs::ClipRectangle represents the location and the area where the information about the area of the object to paint. Here is an example:

#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class CExercise : public Form
{
public:
    CExercise(void)
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	this->Paint += gcnew PaintEventHandler(this, &CExercise::DrawSomething);
    }

private:
    void DrawSomething(Object ^ sender, PaintEventArgs ^ e)
    {
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
	Application::Run(gcnew CExercise);
	return 0;
}

We mentioned that painting is done when (but only when) the operating system judges it necessary. For example, the operating system does this when you restore a previously minimized window. If the user changes the size of a form, the Paint event fires. In this case, if the user clicks somewhere else such as another application and then comes back to this form, this would then cause the Paint event again and would therefore repaint the form. There will be time when you want to paint the content of a control any time, regardless of the state of the control. To paint a control any time, the Control class provides the Invalidate() method overloaded in 6 different versions. The simplest version causes the control to be repainted. Its syntax is:

public:
    void Invalidate();

If you want the control to redraw its client area, call the Update() method after calling Invalidate(). Its syntax is:

public:
    void Update();

The Click Event

Probably the most regular actions a user performs on a control is to position the mouse on it and press a button. When this happens, the control fires a Click event. This is a simple event of type EventArgs that doesn't provide any other information than letting the operating system know that the control was clicked. Here is an example of implementing it:

#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class CExercise : public Form
{
public:
    CExercise(void)
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	this->Click += gcnew EventHandler(this, &CExercise::WasClicked);
    }

private:
    void WasClicked(Object ^ sender, EventArgs ^ e)
    {
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
    Application::Run(gcnew CExercise);
    return 0;
}

Practical LearningPractical Learning: Using the Click Event

  1. Display the form and double-click the Calculate button
  2. Scroll to the top of the file and type #include "Rectangle.h" under the #pragma once line
  3. In the Scope In combo box, select RectangleExercise::Form1
  4. In the Functions combo box, select btnCalculate_Click and implement the event as follows:
    System::Void btnCalculate_Click(System::Object^  sender, System::EventArgs^  e)
    {
    	 CRectangle ^ rect = gcnew CRectangle;
    
    	 rect->Length = double::Parse(txtLength->Text);
    	 rect->Height = double::Parse(txtHeight->Text);
    
    	 txtPerimeter->Text = rect->Perimeter.ToString();
    	 txtArea->Text      = rect->Area.ToString();
    }
  5. Execute the application to test it
  6. Enter some values in the Length and the Height text boxes then click the Calculate button. Here is an example:
     
  7. Close the form

The Double-Click Event

In some cases, the user may be asked to double-click a control. This action fires the DoubleClick event, which is of type EventArgs. Here is an example:

#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class CExercise : public Form
{
public:
    CExercise(void)
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	this->DoubleClick += gcnew EventHandler(this, &CExercise::DblClicked);
    }

private:
    void DblClicked(Object ^ sender, EventArgs ^ e)
    {
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
    Application::Run(gcnew CExercise);
    return 0;
}

Control Resizing

When using an application, one of the actions a user can perform on a form or a control is to change its size, provided the object allows it. Also, some time to time, if possible, the user can minimize, maximize, or restore a window. Whenever any of these actions occur, the operating system must keep track of the location and size of a control. For example, if a previously minimized or maximized window is being restored, the operating system must remember where the object was previously positioned and what its dimensions were in order to restore the window when the user gets back to it.

When the size of a control is changed, it fires the Resize event, which is an EventArgs type.

When the size of a control has been changed, the SizeChanged event is fired. This event is of type EventArgs. Here is an example:

#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class CExercise : public Form
{
public:
    CExercise(void)
    {
	InitializeComponent();
    }

private:
    void InitializeComponent()
    {
	this->Resize += gcnew EventHandler(this, &CExercise::FormResize);
    }

private:
    void FormResize(Object ^ sender, EventArgs ^ e)
    {
    }
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
    Application::Run(gcnew CExercise);
    return 0;
}

Control's Visibility

After adding a control to your application, it is made available to the user. A (visual) control is automatically visible upon creation. You can call the Visible property to hide a visible control or to display a hidden control. Besides the Visible property, you can also display a control using the Show() method. Its syntax is:

Public:
    void Show()

When you use this method, if the control is visible, nothing would happen. If it were hidden, then it would be revealed. The Show() method internally sets the Visible property to true. To hide a control, you can set its Visible property to False. In the same way, to hide a control, you call can the Control::Hide() method. Its syntax is:

public:
    void Hide()

Keep in mind that hiding a control does not close or destroy it. When the visibility aspect of a control is changed, the control fires the VisibleChanged event. This event is of type EventArgs.

Control Getting Focus

Once a control is visible, the user can use it. Some controls allow the user only to read their text or view what they display. Some other controls allow the user to retrieve their value or to change it. To perform such operations, the user must first give focus to the control. To move from one control to another, the user can press Tab or Shift+Tab. This is referred to as control navigation.

The focus is a visual aspect that indicates that a control is ready to receive input from the user. Various controls have different ways of expressing that they have received focus:

  • Button-based controls indicate that they have focus by drawing a dotted rectangle around their caption. In the following picture, the button on the right side has focus:
Focus
  • A text-based control indicates that it has focus by displaying a blinking cursor
  • A list-based control indicates that it has focus when one of its items has a surrounding dotted rectangle:
Focus

To give focus to a control, the user can press a key such as Tab. When the focus gets to a control but before the user uses it, the control fires the Enter event to let the operating system know that it (the control) is going to receive focus. The Enter event is of type EventArgs.

To programmatically give focus to a control, call the Focus() method. When a control receives focus, it fires the GotFocus event. This event is of type EventArgs.

Control Losing Focus

If a control A has focus but the user clicks or accesses another control B, the visual focus of the control A changes and, as we saw above, the new control B receives focus. When the focus is getting moved from a control A, the control fires a Leave event. This event is of type EventArgs.

When a control has lost focus, it fires a LostFocus event. The LostFocus event is of type EventArgs. A control that has lost focus doesn't show it, only the control that has focus indicates it.

The Z-Order of Controls

When you position controls on a form, in some cases, you end up with one control positioned on top of another. Of course the first solution that comes in mind would consist of moving one of the controls away from the other. This would also imply sometimes that you would have to enlarge and/or heighten the controls' container. There are situations that either you don't want to resize the parent or you can't: your only solution is to have one control on top of another. Fortunately, you can cope with this situation by specifying, when needed, what control at what time should be displayed to the user.

When one control is positioned on top of another, they use a third axis whose origin, like that or the other axes, is on the top-left corner of the parent. This third axis, also considered the z-axis, is oriented so that it moves from the monitor towards the user. The operating system is in charge of positioning and drawing the objects on the screen. You as the programmer can direct the operating system as to what object should be on top and what object should be behind. To support these changes the Control class uses two methods that its appropriate children derive also.

When a control A is positioned behind a control B, this causes control A to be either partially or completely hidden. If you want the control A to change its z-order and become on top of control B, you can call its BringToFront() method. The syntax of this method is:

public:
    void BringToFront();

On the other hand, if a control B is positioned on top of a control A, if you want control B to become positioned behind control A, you can call control B's SendToBack() method. Its syntax is:

public:
    void SendToBack();

After the controls have been positioned, at any time, when you access a control, if you want to know whether that control is the most top object, you can call its GetTopLevel() method.

Keyboard Messages

 

Introduction

A keyboard is a hardware object attached to the computer. By default, it is used to enter recognizable symbols, letters, and other characters on a control. Each key on the keyboard displays a symbol, a letter, or a combination of those, to give an indication of what the key could be used for.

The user typically presses a key, which sends a signal to a program. The signal is analyzed to find its meaning. If the program or control that has focus is equipped to deal with the signal, it may produce the expected result. If the program or control cannot figure out what to do, it ignores the action.

Each key has a code that the operating system can recognize.

The Key Down Message

When a user has pressed a key or a combination while using a control, the KeyDown event can be used to identify the key or the combination. A key is typically one of those you see on the keyboard. The keyboard also has special keys referred to as modifiers. These are Alt, Shift, and Ctrl. Only the Alt key can be used by itself to change something on the screen. For example, it is used to activate a menu. Otherwise, users press a modifier and an additional key to make something happen. The KeyDown event allows you to identify what key the user pressed.

The KeyDown event is of KeyEventArgs type interpreted through the KeyEventHandler delegate. The constructor of the KeyEventArgs class has the following syntax:

public:
    KeyEventArgs(Keys keyData);

The keyData argument represents the key or the combination of keys that was pressed.

This class provides the following properties through the second argument of the KeyDown event:

  • Handled: This Boolean property indicates whether the event was carried out. If its value is true, the event was carried. If its value is false, the event was not carried
  • KeyCode: This property specifies the key that was pressed. The recognized keys are members of the Keys enumerator
  • Alt: This Boolean property indicates whether an Alt key was pressed. If the Alt key was pressed, this property has a true value. Otherwise, its value is false
  • Control: This Boolean property indicates whether a Ctrl key was pressed. If a Ctrl key was pressed, this property has a true value. Otherwise, its value is false
  • Shift: This Boolean property indicates whether a Shift key was pressed. If a Shift key was pressed, this property has a true value. Otherwise, its value is false
  • Modifiers: This property allows you to identify the key modifier that was pressed.
  • KeyData: This property represents the key combined with a key modifier that were pressed
  • KeyValue: This property represents the resulting integral value of the key of the KeyData property that was pressed

The Key Up Message

After a user has pressed a key, he or she can release it. This causes the control to fire a KeyUp event, which is the opposite of the KeyDown event. Like KeyDown, the KeyUp event is of type KeyEventHandler. It is handled by a KeyEventArgs class with the same characteristics we reviewed for the KeyDown event.

The Key Press Message

When the user presses a key, the control that has focus fires the KeyPress event. Unlike the other two keyboard messages, the key pressed for this event should (must) be a character key. The KeyPress event is handled by the KeyPressEventHandler delegate. The event is of type KeyPressEventArgs. The constructor of the KeyPressEventArgs class is:

public:
    KeyPressEventArgs(__wchar_t keyChar);

The KeyPressEventArgs class has the following properties:

  • Handled: This property identifies whether this event was handled
  • KeyChar: The property identifies the key that was pressed. It must be a letter or a recognizable symbol. Lowercase alphabetic characters, digits, and the lower base characters such as ; , ‘ [ ] - = / are recognized as they are. For an uppercase letter or an upper base symbol, the user must press Shift + the key. The character would be identified as one entity. This means that the symbol % typed with Shift + 5 is considered as one character.

Mouse Events

 

Introduction

The mouse is another object that is attached to the computer and allows the user to interact with the machine. The mouse and the keyboard can each accomplish some tasks that are not normally available on the other or both can accomplish some tasks the same way.

The mouse is equipped with two, three, or more buttons. When a mouse has two buttons, one is usually located on the left and the other is located on the right. When a mouse has three buttons, one usually is in the middle of the other two. A mouse can also have a round object referred to as a wheel.

The mouse is used to select a point or position on the screen. Once the user has located an item, which could also be an empty space, a letter or a word, he or she would position the mouse pointer on it.

To actually use the mouse, the user would press either the left, the middle (if any), or the right button. If the user presses the left button once, this action is called Click. If the user presses the right mouse button, the action is referred to as Right-Click. If the user presses the left button twice and very fast, the action is called Double-Click.

If the mouse is equipped with a wheel, the user can position the mouse pointer somewhere on the screen and roll the wheel. This usually causes the document or page to scroll up or down, slow or fast, depending on how it was configured.

Mouse Enter

Before using a control with the mouse, the user must first position the mouse on it. When this happens, the control fires a MouseEnter event. This event is carried by an EventArgs argument. This means that the argument doesn't provide much information, only to let you know that the mouse was positioned on a control.

Mouse Move

Whenever the mouse is being moved on top of a control, a MouseMove is fired. This event is of type MouseEventArgs and handled by the MouseEventHandler delegate. The constructor of the MouseEventArgs class is:

public:
    MouseEventArgs(MouseButtons Button, int Clicks,
		   int X, int Y, int Delta);

The properties of the MouseEventArgs class, accessible through the second argument of the MouseMove event, and that are the same as those of the constructor, are:

  • X: This is the left location of the mouse cursor on the control
  • Y: This is the top location of the mouse cursor on the control
  • Button: This property identifies the button that was pressed. The available buttons (Left, Middle, None, Right, XButton1, and XButton2) are stored in the MouseButtons enumerator.
  • Clicks: This property identifies the number of times the Button was pressed and released
  • Delta: This property identifies number of times the mouse wheel has been rotated

Mouse Hover

If the user positions the mouse on a control and moves it over, a MouseHover event is fired. This event is carried by an EventArgs argument that doesn't provide further information than the mouse is hovering over the control.

Mouse Down

Imagine the user has located a position or an item on a document and presses one of the mouse buttons. While the button is pressed and is down, a button-down message is sent. This event is called MouseDown and is of type MouseEventArgs. It uses the same characteristics as those we reviewed for the MouseMove event.

Mouse Up

After pressing a mouse button, the user usually releases it. While the button is being released, a button-up message is sent and it depends on the button, left or right, that was down. The event produced is MouseUp. Like the MouseDown message, the MouseUp event is of type MouseEventArgs which is passed to the MouseEventHandler delegate for processing. This event uses the same characteristics as those we reviewed for the MouseMove event.

Mouse Leave

When the user moves the mouse pointer away from a control, the control fires a MouseLeave event. The MouseLeave event is of type EventArgs. This means that it is only meant to let you know that the mouse is leaving the control.

Anytime Events

 

Introduction

All of the events we have reviewed so far are fired at specific and appropriate times. In some cases, you may want an event to be fired even if it is at the wrong time. We also saw that each control is responsible for firing the necessary event(s) at the right time. In some other cases, you may want one control to fire an event, or to process an event, of another control. In Win32 programming, this is usually performed using the SendMessage() function. In the .NET Framework, this is made possible by calling either the Control::Invoke() method or an event-associated method.

Specific Event Invocation

We mentioned that one of the most regularly performed actions on a control is to click it, which causes the Click event to be fired. If for some reason you want to fire this event any time, you can call the InvokeOnClick() method. Its syntax is:

protected:
    void InvokeOnClick(Control^ toInvoke, EventArgs^ e);

The first argument, toInvoke, is the control you want to assign the focus event to. The e argument is simply an EventArgs object.

Besides, or instead of, the InvokeOnClick() method, to fire the Click event any time, you can call the OnClick() method. Its syntax is:

protected:
    virtual void OnClick(EventArgs^ e);

We saw that you can call the Focus() method to give focus to a control and a user can press Tab continuously to transfer focus from one control to another. We also saw that, when a control receives focus, it fires the GotFocus event. If you want to fire this event at any time, whether the user has pressed Tab or not, you can call the InvokeGotFocus() method. Its syntax is:

protected:
    void InvokeGotFocus(Control^ toInvoke, EventArgs^ e);

Calling this method causes the GoFocus event event to be fired.

We also saw that, when a control loses focus, it fires the LostFocus event. If you want to fire this event any time, you can call the InvokeLostFocus() method. Its syntax is:

protected:
    void InvokeLostFocus(Control^ toInvoke, EventArgs^ e);

In both cases, the first argument, toInvoke, is the control you want to assign the focus event to. The e argument is simply an EventArgs object.

Using the same approach, you can call the:

  • InvokePaint() method to fire a Paint event. This method takes as argument a PaintEventArgs object
  • InvokePaintBackground() method to fire a PaintBackground event. This method takes as argument a PaintEventArgs object
 

Any Event Invocation

The InvokeOnClick(), InvokeLostFocus(), InvokeGotFocus(), InvokePaint(), and InvokePaintBackground() methods are used to fire specific and known events. If you want to fire another event, you can call the Control::Invoke() method. It is overloaded in two versions. One of the syntaxes is:

public:
    Object^ Invoke(Delegate^ method);

The method argument is the delegate that handles the event. You must make sure you know the particular delegate to use. This means that it can be EventHandler or another specific event.

Custom Message Implementation

 

Introduction

It is possible, but unlikely, that none of the available events featured in the controls of the .NET Framework suits your scenario. If this happens, you can implement your own event. To do this, you should first consult the Win32 documentation to identify the type of message you want to send.

There are various techniques you can use to create or send a message that is not available in a control. You may also want to provide your own implementation of a message.

Sending a Custom Windows Message

In order to send a customized version of a Windows message from your control, you must first be familiar with the message. A message in the .NET Framework is based on the Message structure that is defined in the System::Windows::Forms namespace as follows:

public value class Message
{
public:
	property IntPtr HWnd
	{
	    IntPtr get ();
	    void set (IntPtr value);
	}

	property IntPtr LParam
	{
	    IntPtr get ();
	    void set (IntPtr value);
	}

	property int Msg
	{
	    int get ();
	    void set (int value);
	}

	property IntPtr Result
	{
	    IntPtr get ();
	    void set (IntPtr value);
	}

	property IntPtr WParam
	{
	    IntPtr get ();
	    void set (IntPtr value);
	}

	static Message Create(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam);
	bool Equals(Object^ o);
	int GetHashCode();
	Object^ GetLParam(Type^ cls);
	String^ ToString();
};

One of the properties of this structure is Msg. This property holds a constant integer that is the message to send. The constant properties of messages are defined in the Win32 library. To send a message, you can declare a variable of type Message and define it. Once the variable is ready, you can pass it to the DefWndProc() method. Its syntax is:

protected:
    virtual void DefWndProc(Message ^m);

To know the various messages available, you can consult the Win32 documentation. Imagine you want to send a message to close a form when the user clicks a certain button named Button1. You can launch Microsoft Visual Studio 2005(any version) or Microsoft Visual C++ 2005 installed in your computer, open the Drive:\Program Files\Microsoft Visual Studio\VC98\Include\WINUSER.H file and see the names of the available messages:

Win User

You can then initialize the Message::Msg property with it. Here is an example:

#pragma once
#include <windows.h>

#using <System.dll>
#using <System.Windows.Forms.dll>

using namespace System;
using namespace System::Windows::Forms;

public ref class CExercise : public Form
{
public:
	CExercise(void)
	{
		InitializeComponent();
	}

private:
	void InitializeComponent()
	{
		this->Click += gcnew EventHandler(this, &CExercise::FormWasClicked);
	}
	
private:
	Void FormWasClicked(System::Object ^ sender, EventArgs ^ e)
	{
		Message msg;

		msg.HWnd = this->Handle;
		msg.Msg = WM_CLOSE;
		DefWndProc(&msg);
	}
};

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR    lpCmdLine,
                     int       nCmdShow)
{
	Application::Run(gcnew CExercise);

	return 0;
}

Creating a Custom Event

To process a Windows message that is not available for a control you want to use in your application, you can implement its WndProc() method. The syntax of this method is:

protected:
    virtual void WndProc(Message ^m);

In order to use this method, you must override it in your own class. Once again, you must know the message you want to send. This can be done by consulting the Win32 documentation.

 
 
   
 

Home Copyright © 2010-2016, FunctionX