During this hour you will learn
This lesson explains how to use the keyboard and mouse to exercise more user interface control. Although the controls you've seen provide for excellent I/O, your programs may need to respond to the keyboard differently from the ways you've seen so far. For example, you may want to know whether users have pressed a key, even if no keyboard-based control (such as a text box) now has the focus. You can determine exactly when users press a key and even when users release that key.
After you master the mouse, you'll not only be able to respond to mouse movements and clicks, you'll also be able to support drag-and-drop operations. Surprisingly, no mouse control exists. The mouse (as with the keyboard's keystrokes) generates events that your procedures can test for and respond to.
Keyboard events let your applications monitor the keyboard's input. After your application receives keyboard input, the application can then modify the input or ignore the pressed key if it isn't an expected keystroke. Keystroke testing is useful for triggering a splash screen's closing, validating input, and even playing some types of games.
Mastering the keyboard requires that you master the following events:
In addition to these events, the Form control's KeyPreview property determines the way your application responds to keystrokes. This topic section explains how to use these events and the KeyPreview property to manage the user's keyboard.
![]()
Users can combine certain keys, such as Alt, Shift, and Ctrl, with mouse clicks. This lesson's second topic explains how to check for these keystrokes if they happen at the same time as a mouse event.
The KeyPress Event
The KeyPress event occurs when users press any key that corresponds with one of these characters:
When describing the KeyPress event, most programmers say that KeyPress tests for ASCII characters (those characters that appear in Appendix B's ASCII table). As you can see, KeyPress doesn't test for all ASCII characters (such as the horizontal tab or the arrow keys), but it certainly does test for most of them. Use KeyPress to determine exactly which key users pressed. For example, KeyPress will return a letter A if users press that key.
![]()
The KeyPress event occurs on the downstroke and will repeat as the keyboard auto-repeats characters.
An event, as you know, is always associated with an object, such as a command button or the form. The KeyPress event always associates with whatever object now has the focus when users press the key. If no object has the focus, the KeyPress event associates with the form. (An exception can occur, depending on the KeyPreview property explained at the end of this topic section.)
![]()
Don't use a keystroke event to test for a menu shortcut key. The Menu Editor supports shortcut keys for you and sets up the response automatically by triggering the menu item's Click() event procedure. If you test for keystroke events, your program won't be able to respond to menu selections.
The KeyPress event procedure always contains an integer argument. Therefore, if you were to write a KeyPress event for a Text Box control, the event procedure might begin and end like this:
Private Sub Text1_KeyPress (KeyAscii As Integer)
'
' Code goes here to test and respond to keystroke
'
End Sub
The KeyAscii argument is an integer that represents the ASCII code of the character the user pressed. You can use If or a Select Case statement to see whether the character is an expected keystroke.
One of the most important tasks you can perform with KeyPress is to change users' keystrokes. The KeyPress event occurs as soon as users press the key and before a control gets the keystroke. Normally, for example, a Text Box control immediately displays whatever key users pressed when the Text Box control has the focus. If, however, you write a KeyPress event procedure for a text box control, the KeyPress event procedure can change the key, as is done in the following code:
Private Sub txtTryIt_KeyPress(KeyAscii As Integer)
' Change any uppercase A to an uppercase B
If KeyAscii = 65 Then ' 65 is ASCII for A
KeyAscii = 66 ' 66 is ASCII for B
End If
End Sub
If the text box named txtTryIt has the focus, the text box will accept and display any keystroke the user presses until the user presses an uppercase A with an ASCII code value of 65. The If statement changes the keystroke's KeyAscii value to a letter B (ASCII 66), and the Text Box control shows the B and not the A because the KeyPress event gets the keystroke before the text box gets the KeyAscii value.
![]()
Search VB's online help for Key Code Constants. The online help displays named literals that you can use in keyboard testing. For example, you can test for a Backspace press by checking KeyAscii for vbKeyBack, test for an Enter press by checking for vbKeyReturn, and test for Tab press by checking for vbKeyTab. (Remember that KeyPress tests for only these three controls, in addition to letters, numbers, and punctuation.) Although the text box will respect the other keystroke controls (such as Home and End), KeyPress reliably responds only to Enter, Tab, and Backspace.
The KeyDown and KeyUp Events
Whereas KeyPress tests for a wide range of keystrokes, the KeyDown event is more specific. KeyDown occurs when users press a key down just as KeyPress does, but KeyDown gives you a more detailed-albeit slightly more complicated-status of your keyboard. For example, KeyPress returns a different ASCII value for the uppercase T and the lowercase t keypresses. KeyDown returns the same value, as well as another value called the state argument that describes the state of the Shift key.
![]()
The KeyDown event occurs whenever users press a key. Therefore, both the KeyDown and KeyPress events can occur at the same time (assuming that users press an ASCII key).
![]()
Use KeyPress if you want to test for an ASCII keystroke, because KeyPress is simpler to program than KeyDown.
Here are the opening and closing statements of a KeyDown event procedure:
Private Sub txtTryIt_KeyDown(KeyCode As Integer,
[ccc]Shift As Integer)
'
' Keyboard code handler goes here
'
End Sub
KeyCode contains the keystroke, and the Shift argument determines the state of the control keys such as Shift, Ctrl, and Alt. The KeyCode matches the uppercase equivalent of the key pressed. Therefore, if users press a lowercase t, the KeyCode argument contains 84 (the ASCII value for an uppercase T).
![]()
KeyDown's ignorance of the lowercase keys can cause confusion if you're not careful. If you receive a number keypress, you must check the Shift argument. If Shift indicates that users pressed Shift at the same time as the number, users actually wanted the corresponding character above the number (such as the caret, ^, above the 6).
The primary advantage of KeyDown over KeyPress is that, despite KeyDown's Shift problems, you can check for virtually any keystroke, including the arrow keys, Home, End, and so on. Again, check online help for the key-code constants that VB uses to test these special keystrokes.
The shift state is the key-either Shift, Ctrl, Alt, or none-that users press with the other key. The internal binary pattern of the shift argument determines the kind of shift state. To check the shift state, you must perform an And against a number 7. (This special kind of And is called a bitwise And, as opposed to the more common logical And that works as a compound comparison operator.) The code in Listing 28.1 is the shell that performs the common shift state test.
Listing 28.1 Code That Tests for the Shift State
Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)
Dim intShiftState As Integer
intShiftState = Shift And 7 ' Special bitwise And
Select Case intShiftState
Case 1
' Code for Shift combinations
Case 2
' Code for Ctrl combinations
Case 4
' Code for Alt combinations
Case 3
' Code for Shift+Ctrl combinations
Case 5
' Code for Shift+Alt combinations
Case 6
' Code for Ctrl+Alt combinations
Case 7
' Code for Shift+Ctrl+Alt combinations
End Select
End Sub
The KeyUp event occurs whenever users release a pressed key. You can test for the specific key released (such as the A if users release half of a Shift+A keystroke) by analyzing the argument passed to KeyUp(). Therefore, KeyUp occurs after both KeyDown and KeyPress events.
Using SendKeys
The SendKeys statement sends keystroke to your application as though the user were typing those keystrokes. SendKeys is useful for controlling the placement of the text cursor because you can send keystrokes such as the Home and End keys to position the text cursor in a text box or other data-entry control. Here is the syntax of SendKeys:
SendKeys strKeystrokes[, blnWait]
strKeystrokes is often a string literal, such as "Widgets, Inc.", if you want to type the value for users. The Boolean blnWait option is usually omitted and, if False (the default if you omit blnWait), control returns to the executing procedure as soon as the keystrokes are sent. If blnWait is True, the system processes the keystrokes before the code continues, meaning that the keystroke events are active during the keystroke entry.
You must enclose the following special characters inside braces, ({}), if you send them with SendKeys: caret (^), plus sign (+), percent sign (%), tilde (~), and parentheses. Therefore, to simulate typing 7 + 6, the SendKeys statement must embed the plus sign in braces, like this:
SendKeys "7 {+} 6"
Several special keystroke characters, such as the Home and function keys, require a SendKeys code and the braces. For example, to send the Home keypress to an application, you must use the {Home} literal as follows:
SendKeys "{Home}"
All these special keys have code equivalents you can use. You can look up SendKeys in online help to learn which keystroke codes are defined for the special keys.
![]()
You can't send the Print Screen keystroke to an application with SendKeys.
Form or Control Response
When users press a key, either the form or the control with the active focus gets the keystroke. If no control currently has the focus, the form gets the keystroke event. If, however, a control has the focus, either the control or the form gets the focus, depending on the result of the form's KeyPreview property.
If the form's KeyPreview property is True, the form receives the keystroke event. Therefore, if you had coded two event procedures named frmAcct_KeyDown() and txtEntry_KeyDown(), and if the form's KeyPreview property contains True, the frmAcct_KeyDown() event procedure executes when users press a key. If the form's KeyPreview property contains False, the txtEntry_KeyDown() control executes (assuming that the text box has the current focus).
The following code shows an event procedure for a text box. The code converts any lowercase letters the user types into the Text Box control to uppercase:
Private Sub txtTry_KeyPress(KeyAscii As Integer)
' Convert any lowercase letters to uppercase
If (KeyAscii >= 97) And (KeyAscii <= 122) Then
KeyAscii = KeyAscii - 32 ' Adjust to upper
End If
End Sub
The ASCII value range for lowercase letters, as you can verify from Appendix B, is 97 (for a) to 122 (for z). The ASCII value difference between the uppercase letters and their lowercase counterparts is 32. Therefore, if the KeyPress event procedure successfully gets a lowercase letter ASCII value, the procedure subtracts 32 from the value to convert the value to its uppercase equivalent.
![]()
Don't use the keyboard events to write your own masked edit routine if you use the Professional or Enterprise edition of VB. Both editions let you add the Microsoft Masked Edit Controls 5.0 to the Toolbox, and the Masked Edit control lets you set up input fields, such as phone numbers with area codes and automatic parentheses and hyphens.
Hour 26, "Using Form Templates," described the Options dialog box form template that contained the code shown here in Listing 28.2.
Listing 28.2 Formtemp.bas: Handling Options Dialog Box Selections
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
Dim i As Integer
'handle ctrl+tab to move to the next tab
If Shift = vbCtrlMask And KeyCode = vbKeyTab Then
i = tbsOptions.SelectedItem.Index
If i = tbsOptions.Tabs.Count Then
'last tab so we need to wrap to tab 1
Set tbsOptions.SelectedItem = tbsOptions.Tabs(1)
Else
'increment the tab
Set tbsOptions.SelectedItem = tbsOptions.Tabs(i + 1)
End If
End If
End Sub
You can now understand this complete event procedure, whereas you really didn't posses all the tools before now. The code's purpose is to move the focus between tabbed pages in the Options dialog box. As users press Ctrl+Tab, the next tabbed page is to display and the previously displayed page is to disappear behind the new one. The If statement shows an interesting way to check for Ctrl+Tab. If users haven't pressed the Ctrl+Tab combination, nothing executes and the event procedure ends.
Controlling the mouse is one fundamental task that Windows applications must be able to do. A number of events can result from user interaction with the mouse. By mastering the mouse events, you'll be able to sense the user's mouse movement, clicks, and double-clicks. Also, you'll be ready to master drag and drop.
This topic section teaches you how to monitor the mouse movements and button clicks. Before responding to the mouse, you may want to change the mouse cursor to reflect the current activity. For example, you might change the mouse cursor to an hourglass cursor during a long update or disk read. Also, you might want to change the mouse cursor to a different shape (such as the international Not symbol, the circle with a slash) if users move an object over a control that doesn't accept the moved object. After you set the mouse cursor, you can monitor the mouse-generated events so that you can respond to various mouse actions.
The Mouse Cursor
Table 28.1 lists the possible mouse cursors you can set. Almost every control that you place on the form contains a special property called MousePointer. The MousePointer property can take on any of Table 28.1's values. If you'd like to display an icon graphic in place of one of the predefined mouse pointers in Table 28.1, set the MouseIcon property to an icon file and then set the MousePointer property to 99 - Custom.
Table 28.1 Mouse Pointer Named Literals
Literal | Description |
VbArrow | Regular mouse-pointer arrow |
VbCrosshair | Cross hair |
VbIbeam | I-beam |
VbIconPointer | Small square within a square |
VbSizePointer | Four-pointed arrow pointing up, down, left, and right |
VbSizeNESW | Double-arrow pointing northeast and southwest |
VbSizeNS | Double-arrow pointing up and down |
VbSizeNWSE | Double-arrow pointing northwest and southeast |
VbSizeWE | Double-arrow pointing left and right |
VbUpArrow | Up arrow |
VbHourglass | Hourglass (indicating wait) |
VbNoDrop | No drop (the international Not sign) |
VbArrowHourglass | Arrow with an hourglass |
vbArrowQuestion | Arrow with a question mark |
vbSizeAll | Size all for resizing operations |
vbCustom | The shape indicated by the MouseIcon property |
![]()
You can set these values at runtime by assigning the named literals or at design time by selecting one of the values in a control's MousePointer property.
Mouse Moves and Clicks
You'll use mouse events to check for a mouse movement or click. Windows generates these events and sends them to your program. Although your program might choose to ignore the events, you can place code in any of the events that you want to respond to. Table 28.2 describes each mouse event.
Table 28.2 Windows Generates These Mouse Events
Event | Description |
Click | The user clicked a mouse button. |
DblClick | The user double-clicked a mouse button. |
MouseDown | The user pressed and held a mouse button. |
MouseMove | The user moved the mouse. |
MouseUp | The user released the mouse button. |
All the mouse events associate with controls. You'll find the mouse events listed for almost every control, as well as for forms. For example, if you wanted to test for a mouse button click event on your form that's named frmTest, the event procedure would be named frmTest_MouseDown().
When users double-click a mouse button, the DblClick and MouseUp events occur. (Windows doesn't trigger a MouseDown event if users double-click the mouse.)
The MouseDown, MouseMove, and MouseUp event procedures always require these four arguments:
Visual Basic generates a movement event after users move the mouse every 10 to 15 twips. Although 15 twips is an extremely small portion of the window, VB doesn't get a mouse movement event for each twip movement.
Suppose that you want the mouse cursor to change to a happy face when users move the mouse pointer over a command button named cmdHappy. From the cmdHappy Properties window, you would click the ellipses to select an icon file from the \VB\Graphics\Icons\Misc directory. Select the file named Face03.ico.
Now that you've displayed the mouse icon, change cmdHappy's MousePointer property to 99 - Custom. The customized value tells VB to check the MouseIcon property for the file to display if users move the mouse over the command button. Figure 28.1 shows the resulting happy mouse pointer.
The mouse pointer now looks happy.
Create a new project and then place an Image control named imgMouse on the form. Set the value of the image's Picture property to the bulls-eye icon, which can be found in the \VB\Graphics\Icons\Misc directory. Move the image to the upper-center portion of the Form window.
Add a text box named txtMouse to the form that lets a message be written on-screen. Adjust the text box to look something like Figure 28.2's Form window.
Users will click this image.
Blank the text box's Caption and add the code shown in Listing 28.3.
Listing 28.3 Caption.bas: Testing for Various Mouse Events
Private Sub Form_Click()
txtMouse.Text = "You clicked the form"
End Sub
Private Sub Form_DblClick()
txtMouse.Text = "You double-clicked the form"
End Sub
Private Sub Form_MouseDown(Button As Integer, Shift As Integer,
[ccc]X As Single, Y As Single)
' Clicked over the form
txtMouse.Text = "Clicked over the form at " & X & ", " & Y
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer,
[ccc]X As Single, Y As Single)
txtMouse.Text = "Moving the mouse..."
End Sub
Private Sub imgMouse_Click()
txtMouse.Text = "You clicked the image"
End Sub
Private Sub imgMouse_DblClick()
txtMouse.Text = "You double-clicked the image"
End Sub
Private Sub imgMouse_MouseDown(Button As Integer,
[ccc]Shift As Integer, X As Single, Y As Single)
' Clicked over the image
txtMouse.Text = "Clicked over the image at " & X & ", " & Y
End Sub
Private Sub imgMouse_MouseMove(Button As Integer,
[ccc]Shift As Integer, X As Single, Y As Single)
txtMouse.Text = "You moved over the image"
End Sub
The code tests for the various mouse-based event procedures and changes the text box according to user actions. If the MouseDown event doesn't seem to occur, click and hold your mouse button to read the MouseDown description. As you click, the x- and y-coordinates describe the mouse's twip location at the time of the click.
Now that you've mastered the standard mouse events, you're ready to master dragging and dropping. One of the most important features you can add to a visual graphics-based program is drag-and-drop support. Visual Basic makes drag-and-drop support extremely simple to implement.
Drag-and-drop is the process of the user, with the mouse, clicking an object on-screen, holding down the mouse button, and dragging that object to another location on-screen. Visual Basic gives you the choice of automatic drag-and-drop or manual drag-and-drop; the method you select depends on the needs your application has at the time.
Automatic Drag and Drop
Almost every control in the Toolbox contains the property named DragMode. This property lets users move the control with the mouse. When users move the control, Visual Basic displays an outline of the control. Your job is to move the control to the place where users release the mouse button. Although the automatic mode shows the moving control's outline, the automatic mode doesn't actually move the object.
The form's DragDrop event controls the placement of the drop. To set up the drag, you only need to change the control's DragMode property to 1 - Automatic. The control then can allow the drag and show the moving outline. The Form_DragDrop() event procedure takes care of the second half of the drag-and-drop operation by placing the dragged control in its new location.
Completing the Drag
Although the control's dragged outline appears as users move the mouse, you can change the outline to any icon file (such as the icon files in the \VB\Graphics\Icons directory). When you drag the control, the icon replaces the mouse pointer during the drag.
After users complete the drag, you should code the following Form_DragDrop() procedure to take care of moving the object to its final location. The DragDrop event takes care of removing the first location and moving to the placed location. Here's the code that performs the placement:
Private Sub Form_DragDrop(Source As Control, X As Single,
[ccc]Y As Single)
Source.Move X, Y
End Sub
![]()
The DragOver event procedure occurs when the user drags one control over another. DragOver receives four arguments:
- The control
- The mouse pointer's x-coordinate
- The mouse pointer's y-coordinate
- The state of the drag that takes on one of three possible values: 0 when the drag first covers the object, 1 when the drag leaves the object, and 2 when the control is being dragged through the object
Manual Drag-and-Drop
Manual drag-and-drop works just like automatic. except for these three differences:
The MouseDown event procedure can perform the special Drag method on the object if you want to continue the drag-and-drop process. The following code drags the image if the image control's DragMode property is set to 0 - Manual:
Private Sub imgMouse_MouseDown(Button As Integer,
[ccc]Shift As Integer, X As Single, Y As Single)
' Clicked over the image
txtMouse.Text = "Clicked over the image at " & X & ", " & Y
imgMouse.Drag
End Sub
The Drag method turns on drag-and-drop. Without the Drag method, the MouseDown() event procedure couldn't initiate the drag-and-drop operation. Use manual drag-and-drop operations if you want to perform processing and drag-and-drop limitations before and during the drag-and-drop process.
Open the project you created in the second topic section. This example modifies the project somewhat to let you drag the bulls-eye icon around the form and drop the icon somewhere else.
Perform these steps to add drag-and-drop capabilities to the project:
You can see how to easy it is to implement manual drag-and-drop by following these steps to turn the previous example into a manually controlled (via code) drag-and-drop application:
Because of this lesson, you can now analyze the keyboard and respond to keyboard events that don't associate with a specific control's events. Therefore, you can decide exactly which keystrokes to allow or ignore when users enter text in a Text Box control. The keyboard events also let you respond to immediate keystrokes.
Controlling a mouse is simple due to the mouse-related events that VB supports. The mouse events are relatively simple because you can perform only four basic tasks with a mouse: click, double-click, multi-button click, and move. The mouse events inform your code, with appropriate arguments, of the mouse pointer's location.
This lesson's final topic section explained how to implement drag-and-drop. VB's automatic drag-and-drop mode is the easiest kind of drag-and-drop to implement, although you can manually control drag-and-drop if you need more control over the operation.
In Hour 29, "Building a Help Subsystem," you'll learn how to add help files to your application so that your users can request assistance when needed.
© 1997, QUE Corporation, an imprint of Macmillan Publishing USA, a Simon and Schuster Company.