Mouse Events

All Control objects support several mouse events, listed in Table 8-2. Three of themMouseEnter, MouseHover, and MouseLeaveare raised, respectively, every time the mouse cursor goes from being outside to inside the control, stays stationary over a control (or at least does not move outside the control; only a single MouseHover event is raised for every MouseEnter/MouseLeave pair, even if the cursor hovers, moves a bit, then hovers again), or leaves the control's airspace. Each event passes an event argument of type EventArgs, which carries no information about the event. No coordinates are passed, for example. These three events tell you only that the mouse cursor has interacted with a control.

Four low level events, also listed in Table 8-2, pass significant information about the event, in a structure of type MouseEventArgs: MouseDown, MouseMove, MouseWheel, and MouseUp. From the properties of the MouseEventArgs argument, listed in Table 8-3, you can tell which button was pressed on the mouse, and the coordinates of the hot spot of the mouse cursor (relative to the top left corner of the control) when the event was raised, in addition to other information.

Finally, there are two high level events: Click and DoubleClick. These events also take an event argument of type EventArgs, meaning that the event has no additional information. (Additional Control properties, listed in Table 8-5, provide information such as the coordinates and the mouse buttons pressed.) A Click event occurs when there is a single press and release of a mouse button while the mouse cursor is over the Control. A DoubleClick event occurs when the mouse button is clicked twice in succession, with the time interval between the clicks less than the number of milliseconds in SystemInformation.DoubleClickTime and the mouse movement between clicks less than the number of pixels in SystemInformation.DoubleClickSize.

Table 8-2. Mouse-related events

Event

Event argument

Description

Click

EventArgs

Raised when the control is clicked.

DoubleClick

EventArgs

Raised when the control is double-clicked.

MouseEnter

EventArgs

Raised when the mouse cursor enters the control.

MouseHover

EventArgs

Raised when the mouse cursor hovers over the control.

MouseLeave

EventArgs

Raised when the mouse cursor leaves the control.

MouseDown

MouseEventArgs

Raised when the mouse cursor is over the control and a mouse button is pressed.

MouseMove

MouseEventArgs

Raised when the mouse cursor is moved over the control.

MouseWheel

MouseEventArgs

Raised when the control has focus and the mouse wheel is rotated.

MouseUp

MouseEventArgs

Raised when the mouse cursor is over the control and a mouse button is released.

Although all Forms controls inherit from System.Windows.Forms.Control, not all controls necessarily expose all the events contained in Control. For example, the Windows user interface does not support the concept of double-clicking a Button control. Yet the Button class inherits from Control via the ButtonBase class, and thus inherits the DoubleClick event In fact, even though Visual Studio .NET does not expose a DoubleClick event for a Button control in the Properties window (in C#) or the VB.NET drop-down event list, you can hook it up manually. Your program will compile and run, but the DoubleClick event will never be raised because the Windows event model does not raise that event for Buttons.

.NET can suppress the Click and DoubleClick events on selected controls by setting the StandardClick and StandardDoubleClick values, respectively, of the ControlStyles enumeration. For example, if StandardDoubleClick is set to false, the control will not fire Double-click events.

Only one mouse button is represented in each event. If you try pressing two mouse buttons simultaneously, you will get two separate Mouse events. (While the Button property of MouseEventArgs is of type MouseButtons, and while theoretically you can use bit-wise combinations to combine two Button enumerated values, you can have only one mouse button per event.) See Table 8-4 for MouseButtons enumeration values.

Table 8-3. MouseEventArgs properties

Property

Description

Button

Returns the pressed mouse button. Must be one of the members of the MouseButtons enumeration (listed in Table 8-4).

Clicks

Returns the integer number of times the mouse button was pressed and released. Resets after two clicks.

Delta

Returns the signed integer number of detents the mouse wheel was rotated. A positive value indicates that the wheel was rotated forward, i.e., away from the user, and a negative value indicates the wheel was rotated backward, i.e., toward the user.

X

The X coordinate, in pixels, of the mouse cursor's hot spot when the button was clicked, relative to the top-left corner of the control.

Y

The Y coordinate, in pixels, of the mouse cursor's hot spot when the button was clicked, relative to the top-left corner of the control.

The documentation in both Versions 1 and 1.1 incorrectly says that the X and Y MouseEventArgs properties are relative to the client area of the form.

Table 8-4. MouseButtons enumeration

Member

Description

Left

Left, or primary, mouse button pressed.

Middle

Middle mouse button pressed.

None

No mouse button pressed.

Right

Right, or secondary, mouse button pressed.

Xbutton1

First XButton of five button Microsoft IntelliMouse Explorer pressed.

Xbutton2

Second XButton of five button Microsoft IntelliMouse Explorer pressed.

The programs listed in Example 8-3 (in C#) and in Example 8-4 (in VB.NET) demonstrate the MouseEnter, MouseHover, and MouseLeave events. These events are handled both for a Button control (which performs no other function in these programs other than acting as a typical control) and for the form. When the mouse cursor enters, hovers over, or leaves either the button or the form, a text string is painted on the form client area with that information. In addition, if the button raises any of these three events, the Text property of the button is changed.

Example 8-3. MouseEnter, MouseHover, and MouseLeave event handling in C# (MouseEnterHoverLeave.cs)

using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class MouseEnterHoverLeave : Form { private Button btn; string str = ""; public MouseEnterHoverLeave( ) { Text = "Mouse Enter / Hover / Leave"; Size = new Size(400,400); btn = new Button( ); btn.Parent = this; btn.Location = new Point(50,50); btn.Size = new Size(150,25); btn.MouseEnter += new System.EventHandler(btn_MouseEnter); btn.MouseHover += new System.EventHandler(btn_MouseHover); btn.MouseLeave += new System.EventHandler(btn_MouseLeave); } static void Main( ) { Application.Run(new MouseEnterHoverLeave( )); } private void btn_MouseEnter(object sender, EventArgs e) { btn.Text = "MouseEnter"; str += " Button MouseEnter"; Invalidate( ); } private void btn_MouseHover(object sender, EventArgs e) { btn.Text = "MouseHover"; str += " Button MouseHover"; Invalidate( ); } private void btn_MouseLeave(object sender, EventArgs e) { btn.Text = "MouseLeave"; str += " Button MouseLeave"; Invalidate( ); } protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); str += " Form MouseEnter"; Invalidate( ); } protected override void OnMouseHover(EventArgs e) { base.OnMouseHover(e); str += " Form MouseHover"; Invalidate( ); } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); str += " Form MouseLeave"; Invalidate( ); } protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.DrawString(str, Font, Brushes.Black, 50, 75); } } }

Example 8-4. MouseEnter, MouseHover, and MouseLeave in VB.NET (MouseEnterHoverLeave.vb)

Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class MouseEnterHoverLeave : inherits Form private btn as Button dim str as string = "" public sub New( ) Text = "Mouse Enter / Hover / Leave" Size = new Size(400,400) btn = new Button( ) btn.Parent = me btn.Location = new Point(50,50) btn.Size = new Size(150,25) AddHandler btn.MouseEnter, AddressOf btn_MouseEnter AddHandler btn.MouseHover, AddressOf btn_MouseHover AddHandler btn.MouseLeave, AddressOf btn_MouseLeave end sub public shared sub Main( ) Application.Run(new MouseEnterHoverLeave( )) end sub private sub btn_MouseEnter(ByVal sender as object, _ ByVal e as EventArgs) btn.Text = "MouseEnter" str = str + vbNewLine + "Button MouseEnter" Invalidate( ) end sub private sub btn_MouseHover(ByVal sender as object, _ ByVal e as EventArgs) btn.Text = "MouseHover" str = str + vbNewLine + "Button MouseHover" Invalidate( ) end sub private sub btn_MouseLeave(ByVal sender as object, _ ByVal e as EventArgs) btn.Text = "MouseLeave" str = str + vbNewLine + "Button MouseLeave" Invalidate( ) end sub protected overrides sub OnMouseEnter(ByVal e as EventArgs) myBase.OnMouseEnter(e) str = str + vbNewLine + "Form MouseEnter" Invalidate( ) end sub protected overrides sub OnMouseHover(ByVal e as EventArgs) myBase.OnMouseHover(e) str = str + vbNewLine + "Form MouseHover" Invalidate( ) end sub protected overrides sub OnMouseLeave(ByVal e as EventArgs) myBase.OnMouseLeave(e) str = str + vbNewLine + "Form MouseLeave" Invalidate( ) end sub protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim g as Graphics = e.Graphics g.DrawString(str, Font, Brushes.Black, 50, 75) end sub end class end namespace

In the constructor of the programs in Example 8-3 and Example 8-4, in addition to setting the Form Text and Size properties, the Button control is instantiated and specified, including the addition of event handlers for the MouseEnter, MouseHover, and MouseLeave events.

btn.MouseEnter += new System.EventHandler(btn_MouseEnter); btn.MouseHover += new System.EventHandler(btn_MouseHover); btn.MouseLeave += new System.EventHandler(btn_MouseLeave);

AddHandler btn.MouseEnter, AddressOf btn_MouseEnter AddHandler btn.MouseHover, AddressOf btn_MouseHover AddHandler btn.MouseLeave, AddressOf btn_MouseLeave

Each event handler changes the Text property of the button and then concatenates a new line character and some appropriate text to the member string variable str. The Invalidate method is called, which causes a Paint event to be raised for the Form. The btn_MouseEnter looks like:

private void btn_MouseEnter(object sender, EventArgs e) { btn.Text = "MouseEnter"; str += " Button MouseEnter"; Invalidate( ); }

private sub btn_MouseEnter(ByVal sender as object, _ ByVal e as EventArgs) btn.Text = "MouseEnter" str = str + vbNewLine + "Button MouseEnter" Invalidate( ) end sub

When the Form's Paint event is raised, the OnPaint method is invoked. This is overridden by a method that first chains up to the base method, ensuring that any other methods registered with the delegate will be invoked. The overridden OnPaint method then instantiates a Graphics object and draws the str text string.This overridden OnPaint method looks like:

protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); Graphics g = e.Graphics; g.DrawString(str, Font, Brushes.Black, 50, 75); }

protected overrides sub OnPaint(ByVal e as PaintEventArgs) myBase.OnPaint(e) dim g as Graphics = e.Graphics g.DrawString(str, Font, Brushes.Black, 50, 75) end sub

Notice that there is only a single string being drawn, which is built up of all the event messages. This obviates the need to keep track of the vertical coordinate, as was done in Example 8-1 and Example 8-2.

Compiling and running the program, and then moving the mouse over the button, hovering a bit, and moving the mouse off of the form results in the screenshot shown in Figure 8-1.

The sequence of events is interesting. The cursor first enters the Form, and then leaves the Form as it enters the Button. Next, the cursor hovers over the Button, and then leaves the Button and enters the Form once again. It finally leaves the Form for good, moving onto the desktop.

Figure 8-1. MouseEnterHoverLeave in action

The programs in Example 8-5 (in C#) and Example 8-6 (in VB.NET) demonstrate all mouse events, including MouseEnter, MouseHover, MouseLeave, MouseDown, MouseMove, MouseUp, MouseWheel, Click, and DoubleClick.

Example 8-5 and Example 8-6 use a label (rather than a Button), and the event logging strings are displayed in a TextBox, rather than on the client area of the Form. These changes were implemented to facilitate scrolling through the log of events.

The code that differs from the previous example is highlighted.

Example 8-5. Mouse events in C# (MouseEvents.cs)

using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class MouseEvents : Form { private Label lbl; private Button btnReset; private TextBox txt; public MouseEvents( ) { Text = "Mouse Events"; Size = new Size(400,600); btnReset = new Button( ); btnReset.Parent = this; btnReset.Location = new Point(250,50); btnReset.Text = "Reset"; btnReset.Click += new System.EventHandler(btnReset_Click); lbl = new Label( ); lbl.Parent = this; lbl.Location = new Point(50,50); lbl.Size = new Size(150,25); lbl.BorderStyle = BorderStyle.Fixed3D; lbl.MouseEnter += new System.EventHandler(lbl_MouseEnter); lbl.MouseHover += new System.EventHandler(lbl_MouseHover); lbl.MouseLeave += new System.EventHandler(lbl_MouseLeave); lbl.MouseDown += new System.Windows.Forms.MouseEventHandler(lbl_MouseDown); // Comment out to reduce quantity of text generated. // lbl.MouseMove += new // System.Windows.Forms.MouseEventHandler(lbl_MouseMove); lbl.MouseUp += new System.Windows.Forms.MouseEventHandler(lbl_MouseUp); lbl.MouseWheel += new System.Windows.Forms.MouseEventHandler(lbl_MouseWheel); lbl.Click += new System.EventHandler(lbl_Click); lbl.DoubleClick += new System.EventHandler(lbl_DoubleClick); txt = new TextBox( ); txt.Parent = this; txt.Location = new Point(50,90); txt.Size = new Size(300,475); txt.BorderStyle = BorderStyle.FixedSingle; txt.Multiline = true; txt.ScrollBars = ScrollBars.Vertical; } static void Main( ) { Application.Run(new MouseEvents( )); } private void btnReset_Click(object sender, EventArgs e) { lbl.Text = ""; txt.Text = ""; } private void lbl_MouseEnter(object sender, EventArgs e) { lbl.Text = "MouseEnter"; TextBoxDraw("Label MouseEnter"); } private void lbl_MouseHover(object sender, EventArgs e) { lbl.Text = "MouseHover"; TextBoxDraw("Label MouseHover"); } private void lbl_MouseLeave(object sender, EventArgs e) { lbl.Text = "MouseLeave"; TextBoxDraw("Label MouseLeave"); } private void lbl_MouseDown(object sender, MouseEventArgs e) { lbl.Text = "MouseDown"; string str; str = "Label MouseDown"; str += " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); } private void lbl_MouseMove(object sender, MouseEventArgs e) { lbl.Text = "MouseMove"; string str; str = "Label MouseMove"; str += " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); } private void lbl_MouseUp(object sender, MouseEventArgs e) { lbl.Text = "MouseUp"; string str; str = "Label MouseUp"; str += " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); } private void lbl_MouseWheel(object sender, MouseEventArgs e) { lbl.Text = "MouseWheel"; string str; str = "Label MouseWheel"; str += " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); } private void lbl_Click(object sender, EventArgs e) { lbl.Text = "Click"; TextBoxDraw("Label Click"); } private void lbl_DoubleClick(object sender, EventArgs e) { lbl.Text = "DoubleClick"; TextBoxDraw("Label DoubleClick"); } protected override void OnMouseEnter(EventArgs e) { base.OnMouseEnter(e); TextBoxDraw("Form MouseEnter"); } protected override void OnMouseHover(EventArgs e) { base.OnMouseHover(e); TextBoxDraw("Form MouseHover"); } protected override void OnMouseLeave(EventArgs e) { base.OnMouseLeave(e); TextBoxDraw("Form MouseLeave"); } private void TextBoxDraw(String str) { txt.AppendText(" " + str); } } }

Example 8-6. Mouse events in VB.NET (MouseEvents.vb)

Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class MouseEvents : inherits Form private lbl as Label private txt as TextBox private WithEvents btnReset as Button public sub New( ) Text = "Mouse Events" Size = new Size(400,600) btnReset = new Button( ) btnReset.Parent = me btnReset.Location = new Point(250,50) btnReset.Text = "Reset" lbl = new Label( ) lbl.Parent = me lbl.Location = new Point(50,50) lbl.Size = new Size(150,25) lbl.BorderStyle = BorderStyle.Fixed3D AddHandler lbl.MouseEnter, AddressOf lbl_MouseEnter AddHandler lbl.MouseHover, AddressOf lbl_MouseHover AddHandler lbl.MouseLeave, AddressOf lbl_MouseLeave AddHandler lbl.MouseDown, AddressOf lbl_MouseDown ' Comment out to reduce quantity of text generated. ' AddHandler lbl.MouseMove, AddressOf lbl_MouseMove AddHandler lbl.MouseUp, AddressOf lbl_MouseUp AddHandler lbl.MouseWheel, AddressOf lbl_MouseWheel AddHandler lbl.Click, AddressOf lbl_Click AddHandler lbl.DoubleClick, AddressOf lbl_DoubleClick txt = new TextBox( ) txt.Parent = me txt.Location = new Point(50,90) txt.Size = new Size(300,475) txt.BorderStyle = BorderStyle.FixedSingle txt.Multiline = true txt.ScrollBars = ScrollBars.Vertical end sub public shared sub Main( ) Application.Run(new MouseEvents( )) end sub private sub btnReset_Click(ByVal sender as object, _ ByVal e as EventArgs) _ Handles btnReset.Click lbl.Text = "" txt.Text = "" end sub private sub lbl_MouseEnter(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "MouseEnter" TextBoxDraw("Label MouseEnter") end sub private sub lbl_MouseHover(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "MouseHover" TextBoxDraw("Label MouseHover") end sub private sub lbl_MouseLeave(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "MouseLeave" TextBoxDraw("Label MouseLeave") end sub private sub lbl_MouseDown(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseDown" dim str as string str = "Label MouseDown" str = str + vbNewLine + vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) end sub private sub lbl_MouseMove(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseMove" dim str as string str = "Label MouseMove" str = str + vbNewLine + vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) end sub private sub lbl_MouseUp(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseUp" dim str as string str = "Label MouseUp" str = str + vbNewLine + vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) end sub private sub lbl_MouseWheel(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseWheel" dim str as string str = "Label MouseWheel" str = str + vbNewLine + vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) end sub private sub lbl_Click(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "Click" TextBoxDraw("Label Click") end sub private sub lbl_DoubleClick(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "DoubleClick" TextBoxDraw("Label DoubleClick") end sub protected overrides sub OnMouseEnter(ByVal e as EventArgs) TextBoxDraw("Form MouseEnter") end sub protected overrides sub OnMouseHover(ByVal e as EventArgs) TextBoxDraw("Form MouseHover") end sub protected overrides sub OnMouseLeave(ByVal e as EventArgs) TextBoxDraw("Form MouseLeave") end sub private sub TextBoxDraw(str as string) txt.AppendText(vbNewLine + str) end sub end class end namespace

Figure 8-2 illustrates the output from Example 8-5 and Example 8-6. As the mouse interacts with either the Form or the Label control, the log of mouse events, including the MouseEventArgs property values, is displayed in the TextBox. Clicking the Reset button clears the TextBox and the Label.

When the mouse cursor is moved from a position over the Form (but not over any child controls) to a position over any of the child controls, a Form MouseLeave event is raised. If this program were tracking the mouse events for the child control (as it is for the Label control), then you would see a concomitant MouseEnter for the child control that the cursor just passed over. This is an effect of the z-order of the controls, a topic covered in Chapter 7. In short, the control on top receives the mouse events.

Figure 8-2. MouseEvents program

The code in this example is very straightforward. The Reset button adds a method called btnReset_Click to the Click event delegate, which sets the values of the Label and TextBox controls to empty strings.

As with the previous example, the Form MouseEnter, MouseHover, and MouseLeave events are overridden. Similar to before, each overridden method appends a string onto the output TextBox. Now, however, rather than call the Invalidate method, which raises a Paint event for the Form, the method TextBoxDraw is called.

TextBoxDraw is a simple method that takes a string as an argument and appends that string to the Text property of the TextBox using the TextBox AppendText method. It is:

private void TextBoxDraw(string str) { txt.AppendText(" " + str); }

private sub TextBoxDraw(str as string) txt.AppendText(vbNewLine + str) end sub

The C# code requires both a carriage return escape character ( ) and a new line escape character ( ) to force a new line in a TextBox control. (Most other controls require only a .)

To track these events, begin by instantiating the Label control lbl:

lbl = new Label( ); lbl.Parent = this; lbl.Location = new Point(50,50); lbl.Size = new Size(150,25); lbl.BorderStyle = BorderStyle.Fixed3D;

lbl = new Label( ) lbl.Parent = me lbl.Location = new Point(50,50) lbl.Size = new Size(150,25) lbl.BorderStyle = BorderStyle.Fixed3D

Then add event handlers to the relevant delegates for all the different mouse events. In C#, the type of event argument is indicated by the name of the event handler delegate to which the event handler method is added (in this example, System.EventHandler and System.Windows.Forms.MouseEventHandler are the delegates).

lbl.MouseEnter += new System.EventHandler(lbl_MouseEnter); lbl.MouseHover += new System.EventHandler(lbl_MouseHover); lbl.MouseLeave += new System.EventHandler(lbl_MouseLeave); lbl.MouseDown += new System.Windows.Forms.MouseEventHandler(lbl_MouseDown); // Comment out to reduce quantity of text generated. // lbl.MouseMove += new // System.Windows.Forms.MouseEventHandler(lbl_MouseMove); lbl.MouseUp += new System.Windows.Forms.MouseEventHandler(lbl_MouseUp); lbl.MouseWheel += new System.Windows.Forms.MouseEventHandler(lbl_MouseWheel); lbl.Click += new System.EventHandler(lbl_Click); lbl.DoubleClick += new System.EventHandler(lbl_DoubleClick);

In VB.NET, the AddHandler syntax is used:

AddHandler lbl.MouseEnter, AddressOf lbl_MouseEnter AddHandler lbl.MouseHover, AddressOf lbl_MouseHover AddHandler lbl.MouseLeave, AddressOf lbl_MouseLeave AddHandler lbl.MouseDown, AddressOf lbl_MouseDown ' Comment out to reduce quantity of text generated. ' AddHandler lbl.MouseMove, AddressOf lbl_MouseMove AddHandler lbl.MouseUp, AddressOf lbl_MouseUp AddHandler lbl.MouseWheel, AddressOf lbl_MouseWheel AddHandler lbl.Click, AddressOf lbl_Click AddHandler lbl.DoubleClick, AddressOf lbl_DoubleClick

Notice that the event handler for the MouseMove event is commented out. MouseMove events fire every time the mouse moves at all. This generates a lot of output. To see this, uncomment the MouseMove event and rebuild the application.

In the instantiation and specification of the output TextBox, the BorderStyle is set to the FixedSingle BorderStyle enumeration, the Multiline property is set to true, and a vertical scrollbar is added. Here is the code:

txt.BorderStyle = BorderStyle.FixedSingle txt.Multiline = true txt.ScrollBars = ScrollBars.Vertical

The MouseEnter, MouseHover, and MouseLeave event handlers are essentially the same as in the previous example. The events that take an event argument of type MouseEventArgs (MouseDown, MouseMove, MouseUp, and MouseWheel) each output text that displays the values of the event argument properties. The tab character escape sequence ( ) enhances the output.

private void lbl_MouseDown(object sender, MouseEventArgs e) { lbl.Text = "MouseDown"; string str; str = "Label MouseDown"; str += " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); }

The VB.NET event handler uses VB.NET constants to achieve the same effects.

private sub lbl_MouseDown(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseDown" dim str as string str = "Label MouseDown" str = str + vbNewLine + vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) end sub

Experimenting with the program coded in this example and shown in Figure 8-2, you can see that the low-level mouse events occur in the following order for any given control:

The MouseDown and MouseUp events are rolled up into a Click or DoubleClick event. A Click event comes after the MouseDown but before the Mouse Up. A DoubleClick first registers a Click event (with its surrounding MouseDown and MouseUp), followed by a second MouseDown and MouseUp. The events and MouseEventArgs.Click property for a DoubleClick are shown in Figure 8-3. Notice that the Clicks property shows 2 only for the second MouseDown event; the first MouseDown Clicks property value is 1.

Figure 8-3. DoubleClick constituent events

8.2.1 Mouse Properties

In addition to the mouse events described earlier, several useful mouse related properties of the Control class are listed in Table 8-5.

Table 8-5. Mouse related Control properties

Property

Type

Description

Capture

Boolean

Read/write. true if the control has captured the mouse. When captured, the control receives mouse input even if the mouse is not within the borders of the control. Typically the mouse is captured for you automatically while a mouse button is depressed (e.g., during drag operations).

Cursor

Cursor

Read/write. The Cursor object to display when the mouse is over the control. The Cursor object is a member of the Cursors class, which provides a collection of Cursor objects (listed in Table 8-6).

MouseButtons

MouseButtons

Read-only. Static (Shared in VB.NET) bitwise combination of values from MouseButtons enumeration (listed in Table 8-4).

MousePosition

Point

Read-only. Static (Shared in VB.NET) point that contains the screen coordinates of the mouse cursor relative to the upper-left corner of the screen. Can use the Control PointToClient method to convert to client coordinates.

ModifierKeys

Keys

Read-only. Static (shared in VB.NET) bitwise combination of Keys values, indicating status of Shift, Ctrl, and Alt keys.

Many controls automatically change the mouse cursor as necessary. For example, when the cursor hovers over a Splitter control, the cursor changes to either the horizontal or vertical splitter symbol, as appropriate. If the mouse cursor hovers over any border of a Form, it will change to the appropriate resizing symbol.

You can use the Cursor property to control the mouse cursor that displays when the mouse cursor hot spot is over a control. The Cursor property is of type Cursor. The Cursor objects are provided by the Cursors class (note the plural), which contains a collection of Cursor objects. The members of the Cursors class are listed in Table 8-6. All Cursors except the panning and no-move cursors can have their appearance modified systemwide by going to Control Panel Mouse Pointers.

Table 8-6. Cursors members

Member

Default Appearance

Description

AppStarting

Cursor that appears when an application starts, typically a combination of an arrow and an hourglass.

Arrow

Arrow cursor.

Cross

Crosshair cursor.

Default

Default cursor, usually an arrow cursor.

Hand

Hand cursor, typically used when hovering over a link.

Help

Help cursor.

HSplit

Horizontal splitter cursor.

IBeam

I-beam cursor, usually used to represent a text cursor.

No

Cursor that indicates current region is invalid for current operation.

NoMove2D

Cursor used during wheel button operations when the mouse is not moving but the window can be scrolled both horizontally and vertically.

NoMoveHoriz

Cursor used during wheel operations when the mouse is not moving but the window can be scrolled horizontally.

NoMoveVert

Cursor used during wheel operations when the mouse is not moving but the window can be scrolled vertically.

PanEast

Cursor used during wheel operations when the mouse is moving and the window is scrolling horizontally to the right.

PanNE

Cursor used during wheel operations when the mouse is moving and the window is scrolling horizontally and vertically upward to the right.

PanNorth

Cursor used during wheel operations when the mouse is moving and the window is scrolling vertically upward.

PanNW

Cursor used during wheel operations when the mouse is moving and the window is scrolling horizontally and vertically upward to the left.

PanSE

Cursor used during wheel operations when the mouse is moving and the window is scrolling horizontally and vertically downward to the right.

PanSouth

Cursor used during wheel operations when the mouse is moving and the window is scrolling vertically downward.

PanSW

Cursor used during wheel operations when the mouse is moving and the window is scrolling horizontally and vertically downward to the left.

PanWest

Cursor used during wheel operations when the mouse is moving and the window is scrolling horizontally to the left.

SizeAll

Four-headed sizing cursor.

SizeNESW

Two-headed diagonal (northeast/southwest) sizing cursor.

SizeNS

Two-headed diagonal (north/south) sizing cursor.

SizeNWSE

Two-headed diagonal (northwest/southeast) sizing cursor.

SizeWE

Two-headed diagonal (west/east) sizing cursor.

UpArrow

UpArrow cursor, typically used to indicate an insertion point.

VSplit

Vertical splitter cursor.

WaitCursor

Wait cursor, typically an hourglass.

The mouse properties are demonstrated in the MouseProperties program, listed in Example 8-7 (in C#) and in Example 8-8 (in VB.NET). The code that is different from the previous example is highlighted. When these examples are run, they look similar to the program shown previously in Figure 8-2.

Example 8-7. Mouse properties in C# (MouseProperties.cs)

using System; using System.Drawing; using System.Windows.Forms; namespace ProgrammingWinApps { public class MouseProperties : Form { private Label lbl; private Button btnReset; private TextBox txt; int i = 0; Cursor[ ] theCursors = {Cursors.AppStarting, Cursors.Arrow, Cursors.Hand, Cursors.Help, Cursors.No}; public MouseProperties( ) { Text = "Mouse Properties"; Size = new Size(400,600); btnReset = new Button( ); btnReset.Parent = this; btnReset.Location = new Point(250,50); btnReset.Text = "Reset"; btnReset.Click += new System.EventHandler(btnReset_Click); lbl = new Label( ); lbl.Parent = this; lbl.Location = new Point(50,50); lbl.Size = new Size(150,25); lbl.BorderStyle = BorderStyle.Fixed3D; lbl.MouseEnter += new System.EventHandler(lbl_MouseEnter); lbl.MouseHover += new System.EventHandler(lbl_MouseHover); lbl.MouseLeave += new System.EventHandler(lbl_MouseLeave); lbl.MouseDown += new System.Windows.Forms.MouseEventHandler(lbl_MouseDown); // Comment out to reduce quantity of text generated. // lbl.MouseMove += new // System.Windows.Forms.MouseEventHandler(lbl_MouseMove); lbl.MouseUp += new System.Windows.Forms.MouseEventHandler(lbl_MouseUp); lbl.MouseWheel += new System.Windows.Forms.MouseEventHandler(lbl_MouseWheel); lbl.Click += new System.EventHandler(lbl_Click); lbl.DoubleClick += new System.EventHandler(lbl_DoubleClick); txt = new TextBox( ); txt.Parent = this; txt.Location = new Point(50,90); txt.Size = new Size(300,475); txt.BorderStyle = BorderStyle.FixedSingle; txt.Multiline = true; txt.ScrollBars = ScrollBars.Vertical; } static void Main( ) { Application.Run(new MouseProperties( )); } private void btnReset_Click(object sender, EventArgs e) { lbl.Text = ""; txt.Text = ""; } private void lbl_MouseEnter(object sender, EventArgs e) { lbl.Text = "MouseEnter"; EventArgsStrings( ); TextBoxDraw("Label MouseEnter"); lbl.Cursor = Cursors.WaitCursor; } private void lbl_MouseHover(object sender, EventArgs e) { lbl.Cursor = theCursors[i % 5]; i++; lbl.Text = "MouseHover"; EventArgsStrings( ); TextBoxDraw("Label MouseHover"); } private void lbl_MouseLeave(object sender, EventArgs e) { lbl.Text = "MouseLeave"; EventArgsStrings( ); TextBoxDraw("Label MouseLeave"); } private void lbl_MouseDown(object sender, MouseEventArgs e) { lbl.Text = "MouseDown"; MouseEventArgsStrings(e); TextBoxDraw("Label MouseDown"); } private void lbl_MouseMove(object sender, MouseEventArgs e) { lbl.Text = "MouseMove"; MouseEventArgsStrings(e); TextBoxDraw("Label MouseMove"); } private void lbl_MouseUp(object sender, MouseEventArgs e) { lbl.Text = "MouseUp"; MouseEventArgsStrings(e); TextBoxDraw("Label MouseUp"); } private void lbl_MouseWheel(object sender, MouseEventArgs e) { lbl.Text = "MouseWheel"; MouseEventArgsStrings(e); TextBoxDraw("Label MouseWheel"); } private void lbl_Click(object sender, EventArgs e) { lbl.Text = "Click"; EventArgsStrings( ); TextBoxDraw("Label Click"); } private void lbl_DoubleClick(object sender, EventArgs e) { lbl.Text = "DoubleClick"; EventArgsStrings( ); TextBoxDraw("Label DoubleClick"); } private void EventArgsStrings( ) { string str; str = " Cursor: " + lbl.Cursor.ToString( ); str += " Capture: " + lbl.Capture.ToString( ); str += " MouseButtons: " + MouseButtons.ToString( ); str += " MousePosition: " + MousePosition.ToString( ); str += " ModifierKeys: " + ModifierKeys.ToString( ); TextBoxDraw(str); } private void MouseEventArgsStrings(MouseEventArgs e) { string str; str = " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); EventArgsStrings( ); } private void TextBoxDraw(string str) { txt.AppendText(str); } } }

Example 8-8. Mouse properties in VB.NET (MouseProperties.vb)

Option Strict On imports System imports System.Drawing imports System.Windows.Forms namespace ProgrammingWinApps public class MouseProperties : inherits Form private lbl as Label private WithEvents btnReset as Button private txt as TextBox dim i as integer = 0 dim theCursors as Cursor( ) = {Cursors.AppStarting, _ Cursors.Arrow, _ Cursors.Hand, _ Cursors.Help, _ Cursors.No} public sub New( ) Text = "Mouse Properties" Size = new Size(400,600) btnReset = new Button( ) btnReset.Parent = me btnReset.Location = new Point(250,50) btnReset.Text = "Reset" lbl = new Label( ) lbl.Parent = me lbl.Location = new Point(50,50) lbl.Size = new Size(150,25) lbl.BorderStyle = BorderStyle.Fixed3D AddHandler lbl.MouseEnter, AddressOf lbl_MouseEnter AddHandler lbl.MouseHover, AddressOf lbl_MouseHover AddHandler lbl.MouseLeave, AddressOf lbl_MouseLeave AddHandler lbl.MouseDown, AddressOf lbl_MouseDown ' Comment out to reduce quantity of text generated. ' AddHandler lbl.MouseMove, AddressOf lbl_MouseMove AddHandler lbl.MouseUp, AddressOf lbl_MouseUp AddHandler lbl.MouseWheel, AddressOf lbl_MouseWheel AddHandler lbl.Click, AddressOf lbl_Click AddHandler lbl.DoubleClick, AddressOf lbl_DoubleClick txt = new TextBox( ) txt.Parent = me txt.Location = new Point(50,90) txt.Size = new Size(300,475) txt.BorderStyle = BorderStyle.FixedSingle txt.Multiline = true txt.ScrollBars = ScrollBars.Vertical end sub public shared sub Main( ) Application.Run(new MouseProperties( )) end sub private sub btnReset_Click(ByVal sender as object, _ ByVal e as EventArgs) _ Handles btnReset.Click lbl.Text = "" txt.Text = "" end sub private sub lbl_MouseEnter(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "MouseEnter" EventArgsStrings( ) TextBoxDraw("Label MouseEnter") end sub private sub lbl_MouseHover(ByVal sender as object, _ ByVal e as EventArgs) lbl.Cursor = theCursors(i mod 5) i = i + 1 lbl.Text = "MouseHover" EventArgsStrings( ) TextBoxDraw("Label MouseHover") end sub private sub lbl_MouseLeave(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "MouseLeave" EventArgsStrings( ) TextBoxDraw("Label MouseLeave") end sub private sub lbl_MouseDown(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseDown" MouseEventArgsStrings(e) TextBoxDraw("Label MouseDown") end sub private sub lbl_MouseMove(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseMove" MouseEventArgsStrings(e) TextBoxDraw("Label MouseMove") end sub private sub lbl_MouseUp(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseUp" MouseEventArgsStrings(e) TextBoxDraw("Label MouseUp") end sub private sub lbl_MouseWheel(ByVal sender as object, _ ByVal e as MouseEventArgs) lbl.Text = "MouseWheel" MouseEventArgsStrings(e) TextBoxDraw("Label MouseWheel") end sub private sub lbl_Click(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "Click" EventArgsStrings( ) TextBoxDraw("Label Click") end sub private sub lbl_DoubleClick(ByVal sender as object, _ ByVal e as EventArgs) lbl.Text = "DoubleClick" EventArgsStrings( ) TextBoxDraw("Label DoubleClick") end sub private sub EventArgsStrings( ) dim str as string str = vbTab + "Cursor: " + _ lbl.Cursor.ToString( ) str = str + vbNewLine + vbTab + "Capture: " + _ lbl.Capture.ToString( ) str = str + vbNewLine + vbTab + "MouseButtons: " + _ MouseButtons.ToString( ) str = str + vbNewLine + vbTab + "MousePosition: " + _ MousePosition.ToString( ) str = str + vbNewLine + vbTab + "ModifierKeys: " + _ ModifierKeys.ToString( ) TextBoxDraw(str) end sub private sub MouseEventArgsStrings(ByVal e as MouseEventArgs) dim str as string str = vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) EventArgsStrings( ) end sub private sub TextBoxDraw(str as string) txt.AppendText(vbNewLine + str) end sub end class end namespace

In the code in Example 8-7 and Example 8-8, the program creates a member array of Cursor objects:

Cursor[ ] theCursors = {Cursors.AppStarting, Cursors.Arrow, Cursors.Hand, Cursors.Help, Cursors.No};

dim theCursors as Cursor( ) = {Cursors.AppStarting, _ Cursors.Arrow, _ Cursors.Hand, _ Cursors.Help, _ Cursors.No}

This program uses only five different Cursor objects in the array. They are displayed in succession in the MouseHover event, using the member variable i as a counter, in conjunction with the modulus operator, to index into the array:

private void lbl_MouseHover(object sender, EventArgs e) { lbl.Cursor = theCursors[i % 5]; i++; lbl.Text = "MouseHover"; EventArgsStrings( ); TextBoxDraw("Label MouseHover"); }

private sub lbl_MouseHover(ByVal sender as object, _ ByVal e as EventArgs) lbl.Cursor = theCursors(i mod 5) i = i + 1 lbl.Text = "MouseHover" EventArgsStrings( ) TextBoxDraw("Label MouseHover") end sub

Each event trapped in this program displays the same information as in the previous example, plus the values of the mouse properties. This example is refined a bit from the previous example by moving all the common code for constructing the display string into helper methods. There are two of these helper methods: EventArgsStrings, which takes no arguments, and MouseEventArgsStrings, which takes the MouseEventArgs as an argument. Here are these two methods:

private void EventArgsStrings( ) { string str; str = " Cursor: " + lbl.Cursor.ToString( ); str += " Capture: " + lbl.Capture.ToString( ); str += " MouseButtons: " + MouseButtons.ToString( ); str += " MousePosition: " + MousePosition.ToString( ); str += " ModifierKeys: " + ModifierKeys.ToString( ); TextBoxDraw(str); } private void MouseEventArgsStrings(MouseEventArgs e) { string str; str = " Button: " + e.Button.ToString( ); str += " Clicks: " + e.Clicks.ToString( ); str += " Delta: " + e.Delta.ToString( ); str += " X: " + e.X.ToString( ); str += " Y: " + e.Y.ToString( ); TextBoxDraw(str); EventArgsStrings( ); }

private sub EventArgsStrings( ) dim str as string str = vbTab + "Cursor: " + _ lbl.Cursor.ToString( ) str = str + vbNewLine + vbTab + "Capture: " + _ lbl.Capture.ToString( ) str = str + vbNewLine + vbTab + "MouseButtons: " + _ MouseButtons.ToString( ) str = str + vbNewLine + vbTab + "MousePosition: " + _ MousePosition.ToString( ) str = str + vbNewLine + vbTab + "ModifierKeys: " + _ ModifierKeys.ToString( ) TextBoxDraw(str) end sub private sub MouseEventArgsStrings(ByVal e as MouseEventArgs) dim str as string str = vbTab + "Button: " + e.Button.ToString( ) str = str + vbNewLine + vbTab + "Clicks: " + e.Clicks.ToString( ) str = str + vbNewLine + vbTab + "Delta: " + e.Delta.ToString( ) str = str + vbNewLine + vbTab + "X: " + e.X.ToString( ) str = str + vbNewLine + vbTab + "Y: " + e.Y.ToString( ) TextBoxDraw(str) EventArgsStrings( ) end sub

Категории