0% found this document useful (0 votes)
22 views

DMC1947

This document provides an overview of Visual Basic 6.0 and how to build applications in it. It discusses the Visual Basic integrated development environment and how to launch projects. Standard projects are selected from the new project dialog. The main programming environment contains a form design window, toolbox, property window, and project window. Building an application involves drawing the interface, setting properties, and writing event code. Basic "Hello World" examples are provided to demonstrate creating a project, writing code, and running the application. Forms and form events like Show, Hide, Load, and Unload are also explained.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views

DMC1947

This document provides an overview of Visual Basic 6.0 and how to build applications in it. It discusses the Visual Basic integrated development environment and how to launch projects. Standard projects are selected from the new project dialog. The main programming environment contains a form design window, toolbox, property window, and project window. Building an application involves drawing the interface, setting properties, and writing event code. Basic "Hello World" examples are provided to demonstrate creating a project, writing code, and running the application. Forms and form events like Show, Hide, Load, and Unload are also explained.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 242

PART I – VISUAL BASIC

CHAPTER 1

PROGRAMMING IN VISUAL BASIC 6.0

1.1 Introduction to Visual Basic

Microsoft Visual Basic development system version 6.0 is the most productive tool for
creating high-performance components and applications. Visual Basic 6.0 offers
developers the ability to create robust applications that reside on the client or server, or
operate in a distributed n-tier environment. Visual Basic 6.0 is the Rapid Application
Development (RAD) tool available either as a stand-alone product or as a part of the
Visual Studio 6.0 suite of tools.

1.2 The Integrated Development Environment

Visual Basic comes with its Integrated Development Environment (IDE). The IDE gives
you everything you need to create great applications, to write code for them, to test and
fine-tune them, and, finally, to produce executable files.

1.2.1 Running the IDE

You can choose from several ways to launch the Visual Basic IDE, as is true for any
Windows executable:
 You can run the Visual Basic 6 environment from the Start Menu (as given in
Figure 1.1); the exact path to the menu command depends on whether you have
installed Visual Basic as part of the Microsoft Visual Studio suite.
 You can create a shortcut to the IDE on your desktop and run it by simply double-
clicking on it.
 When Visual Basic is installed, it registers the .vbp, .frm, .bas, and a few other
extensions with the operating system. Therefore, you can run the environment by
double-clicking on any Visual Basic file.
 If you have installed Microsoft Active Desktop, you can create a shortcut to the
Visual Basic IDE on the system taskbar. This is probably the fastest way to run
the IDE: it's similar to a desktop shortcut, but you don't have to minimize other
windows to uncover it.

1
Figure 1.1 Selecting Microsoft Visual Basic 6.0 from Start

1.2.2 Selecting the Project Type

The first time you run the Visual Basic IDE, you're asked to select the type of project you
want to create, as you can see in Figure 1.2.

Figure 1.2 Types of projects in VB6.0

2
Select Standard EXE from the new project dialog (as in Figure 1.2) and what you'll be
confronted with is shown in Figure 1.3, which is the main programming environment.
You do all your form design and coding from this window. The main programming
environment has the following windows:

1.2.3 Form Design Window

This is where you design your form. A form is what you will present to a user of your
application. A form could be an introduction screen, it could be a dialog box giving the
user options, and it could be a box containing a warning. All of your VB programs will
revolve around a number of forms.

Figure 1.3 The Visual Basic 6 environment

The Toolbar provides quick access to commonly used commands. These will be
explained later in the document.

The Toolbox (Control Bar) is a floating window (Figure 1.4) which provides the tools
for designing/creating an application on your form. They can create buttons, text boxes,
labels, scroll bars and other commonly used windows items.

3
Figure 1.4 Tool Box (Control Bar)

The Property Window have properties such as the color of a button, what type of border
a text box has or what font a label is displayed in of all items placed on a form.

The Project Window includes all the forms, programming code and other files needed to
run this application.

1.3 Steps for building a Visual Basic Application

After designing the application, for building an application in Visual Basic following
steps are to be taken:

1. Draw the Interface - Create the form and the various objects on the form using
toolbox.

2. Set the Properties - Set the properties of the various objects on the form with the help
of properties window.

3. Write the events code - In the code window, write the code associated with each
object on the form and then run the application.

4
1.4 How to start with Visual basic?

Program1.1: A sample program highlighting the steps in creating a project and running
it.

1. Start the visual basic by clicking Start>>Programs>>Microsoft Visual Studio


6.0>>Microsoft Visual Basic

2. Choose Standard EXE from the available screen

3. Click Open.

4. A blank form will appear on the screen with Project Explorer Window,
PropertiesWindow and Tool Box as shown in Figure 1.5 and 1.4.

Figure 1.5 Project Explorer & Properties Window

5. With the help of Tool Box given on the left side of the interface, draw the interface as
shown in Figure 1.6.

Figure 1.6 Sample interface

5
6. Set the properties of the objects on the form as given in the table below:

Object Name Property Value


Text Box Text1 Text <Blank>
Command Button Command1 Caption Click here
Command Button Command2 Caption Stop

7. Double click First Command Button and write the following lines of code:

Private Sub Command1_Click()


Text1.Text = "Welcome to Visual Basic"
End Sub

8. Click View Object to come back at the form.

9. Double click Second Command Button and write the following lines of code:

Private Sub Command2_Click()


End
End Sub

10. Run the project by clicking Run>>Start or Press F5 and you’ll see an output as
shown in Figure 1.7.

Figure 1.7 Snapshot of the Output for Program 1.1

11. Save the project by clicking File>>Save Project.

12. Specify the folder in which all the files like form, reports etc. related with the project
along with the project name are to be saved.

Note: It is advised that one folder for each project should be created.

6
Program 1.2: This example is to calculate the simple interest to be paid on the given
principle amount, rate of interest and the number of years.

1. Create a new Standard EXE Project by clicking on File>>New Project.

2. Draw the interface as given in Figure 1.8 using the Tool Box.

Figure 1.8 Interface Creation for Program 1.2

3. Apply the following properties to the respective controls:

Object Property Value


Text1 Text <Blank>
Text2 Text <Blank>
Text3 Text <Blank>
Text4 Text <Blank>
Label1 Caption Principal Amount
Label2 Caption Rate of Interest
Label3 Caption Number of Years
Label4 Caption Interest to be paid
Command1 Caption Calculate

4. Double click Command1 and write the following line of code:

Text4.Text = Text1.Text * Text2.Text * Text3.Text / 100

5. Run the Project and enter the values and then click the “Calculate” command button to
see a result.

7
CHAPTER 2

FORMS AND FORM EVENTS

2.1 Understanding Forms and form events

2.1.1 The Show and Hide Methods

The Show method of a form displays that form on the screen. If the form to be shown is
not already loaded into memory, the Show method will load it before showing it. The
Show method is typically used to transfer control from one form to another. The syntax
is:

formname.Show

For example, if you are in Form1 and you want to display Form2, the syntax would be:

Form2.Show

When you display one form from another, you may want the user to complete work on
that form before returning to the first one. This does not happen automatically. By
default, VB will display the second form and then continue executing code from the first
form. To suspend execution of the first form until after the second form is done with, add
the keyword constant vbModal as an argument to the Show method. The syntax is:

Form2.Show vbModal

The Hide method of a form removes the form from the screen (makes it invisible), but
the form still remains in memory. The syntax is:

formname.Hide

To refer to the form in which code is currently running (i.e. the "current" form, or the
"active" form), you can of course refer to the form by its name, as in the example above:

Form1.Hide

As an alternative, you can use the keyword Me. The keyword "Me" refers to the form in
which code is currently running:

Me.Hide

8
Finally, any time you want to execute a method of the form on itself, you can simply
code the method name, omitting the "formname." or the "Me.", as in:

Hide

2.1.2 The Load and Unload Statements

The Load statement loads a form into memory, but does not display it. When you code
the Load statement for a form, the Form_Load event of that form will be triggered. The
syntax is:

Load formname

The Unload statement removes a form from memory and from the screen. When you
code the Unload statement for a form, the Form_Unload event of that form will be
triggered. The syntax is:

Unload formname

A form can unload itself, as in:

Unload Me

The Unload event is also triggered with the user clicks the Windows "close" button ("X")
on the form.

Program 2.1: A program using form unload event

1. Place a command button named cmdExit with the caption "Exit" on a form.
2. In the Click event for the command button, instead of coding "End", code:

Private Sub cmdExit_Click( )


Unload Me
End Sub

3. For the Form_Unload event, code the following:

Private Sub Form_Unload(Cancel As Integer)


If MsgBox("Are you sure you want to quit?", vbYesNo + _
vbQuestion, "Unload Test") = vbNo Then Cancel = 1
End Sub

4. Run the program and observe what happens either when you click the Exit button,
or when you try to close the form by clicking on the "X" button.

9
The program will prompt you with a message box as shown in Figure 2.1 which is a
snapshot of the program output when you try to click the Exit button, or when you try to
close the form by clicking on the "X" button.

Figure 2.1 Snapshot of the Output for Program 2.1

Note that VB supplies the Unload event with a built-in argument called "Cancel". If, in
the Unload event procedure, you set the Cancel argument to any non-zero value, the
Unload event will be cancelled (i.e., the form will not be unloaded) and processing will
continue. This event is where you might ask the user if they are sure they want to quit. If
they respond Yes, let the Unload event "do its thing"; if No, set Cancel to non-zero value.

Note: When all forms of a VB project are unloaded, the application ends. The End
statement automatically unloads all forms in a project, but will not trigger the Unload
event (so any code you have in the Unload event will not execute) therefore, ending an
application with "End" does not give the user a second chance to keep working with the
program. The End statement ends the program abruptly.

2.1.3 Centering a Form on the Screen

Program 2.2: Program to display the form exactly at the center of the screen using form
load event.

1. Create a new Standard EXE Project by clicking on File>>New Project.

2. Double click on the form and the following code in the Form_Load event.

Private Sub Form_Load( )


Me.Top = (Screen.Height - Me.Height) / 2
Me.Left = (Screen.Width - Me.Width) / 2

End Sub

10
3. Run the program and observe where the form gets displayed in the screen.

2.1.4 Form_Load vs. Form_Activate

In the Form_Load event, you would typically perform initialization-type tasks, as you
should. However, certain types of actions cannot be performed in the Load event, due to
the fact that the form is fully loaded only after the Load event completes. For one thing,
printing to the form will not work when done in the Load event. In addition, if you try to
set focus to a particular control on the form during the Load event, you will get the
message Run-time error '5': Invalid procedure call or argument. For example,
assume you had a textbox called Text1 on the form. The following code would result in
that error:

Private Sub Form_Load( )


' other initialization here…
Text1.SetFocus ' causes an error
End Sub

The reason for the error is that since the form is not fully loaded, neither are any of the
controls on it and you can't set focus to a control that is not yet available.

To remedy this problem, you should use one of the other Form events, such as the
Activate event. (When VB loads a form, it actually cycles through a number of events,
such as: Initialize, Load, Resize, Activate, GotFocus, and Paint. Of these, Load and
Activate are probably the ones most commonly used. ) Placing the code to set focus to a
control will work in the Form_Activate event:

Private Sub Form_Activate( )


' other statements
Text1.SetFocus ' no problem here
End Sub

A caution about the activate event: it will fire whenever your application switches to that
form. For example, if you switch back and forth between Form1 and Form2, be aware
that any code you might have in the Activate events for these forms will be executed
when you switch to that form. Therefore, if you have code in the Activate event that you
only want to execute "the first time", you will need to control execution with a Boolean
switch. For example, in the General Declarations of your form you could define the
following variable:

2.1.5 Adding Multiple Forms into a Project

Many projects will use more than one form. When you have more than one module (form
or standard) in a project, you must specify a "Startup object", which is done via the
Project menu, Properties item.

11
The startup object tells VB which form or standard module is to have its code run first (if
a standard module is the startup object, it must contain a public subroutine called "Main",
and "Sub Main" is specified for the Startup object). By default, the startup object is the
initial form that is supplied with every new VB Project.

Program 2.3: An application that uses three forms: Form1, Form2, and Form3. (To add
forms to a project, go to the Project menu and select Add Form.) Form1 serves as the
switchboard form, which contains three command buttons: cmdForm2, cmdForm3, and
cmdExit:

1. Create a StandardEXE project named Project1.

2. Project1 by default has one form named Form1.

3. Add two labels and three command buttons and edit the following properties:

Object Name Property Value


Label1 Label1 Caption Multi Form Application
Label2 Label2 Caption Main Menu
Command Button 1 cmdForm2 Caption Form&2 Stuff
Command Button 2 cmdForm3 Caption Form&3 Stuff
Command Button 3 cmdExit Caption E&xit

4. Add a new form named Form2 by following the below mentioned steps:
a. Right click on the Form1 in the Project Window
b. Select Add menu from the popup menu which in turn displays a submenu
and then click the Form menu as shown in Figure 2.2

5. Similarly add another form (Form3).

6. Add a command button with a name cmdExit and caption “Return to Main Form”
in Form2 and Form3 respectively.

7. Finally your forms will look like as shown in Figure 2.3.

12
Figure 2.2 Adding a new form to existing project

Figure 2.3 Forms creation for Program 2.3

8. Add the following command button logic in Form1:

Private Sub cmdForm2_Click( )


Form2.Show vbModal
End Sub

13
Private Sub cmdForm3_Click( )
Form3.Show vbModal
End Sub

Private Sub cmdExit_Click( )


Unload Me
End Sub

9. For the sake of the simplicity, add just one button with the caption "Return to
Main Menu" in Form2 and Form3 respectively with a name “cmdExit”. The code
behind the command button on each of these forms is simply Unload Me.

10. Finally Run the project and observe the results.

2.2 Fancy Collapsing Form Exit

You can always close your current form with the Unload Visual Basic command. When
that line is encountered your form will disappear. However, wouldn't it be more exciting
if instead of just disappearing your form collapsed in towards the center of itself and then
disappeared. The way we do this is by setting the forms width and height to a smaller
amount over and over again. This can be done easily with a Do while loop. The important
thing is to make sure you stop collapsing the form before it gets too small. You will get
an error if you set the width or height to anything less than 0.

Program 2.4: Program to collapse a form in fancy fashion while exiting.

1. Create a Visual Basic 6 project and a command button to your main form.

2. Double click on the command and enter the following code in the click event
handler for your button.

Private Sub Command1_Click( )


Do While Me.Width > 1800
Me.Width = Me.Width - 300
Me.Left = Me.Left + 150
If Me.Height - 400 Then
Me.Top = Me.Top - 1
Me.Height = Me.Height - 150
End If
Loop
Unload Form1: End
End Sub

3. Once you have the code entered run your program and click the button. You
should see your form leave with a little style.

14
CHAPTER 3

CONTROLS

3.1 Introduction to Visual Basic Controls

The Visual Basic toolbox as in Figure 3.1 contains the tools you use to draw controls on
your forms.

Figure 3.1 Visual Basic toolbox

3.1.1 Control Categories

There are three broad categories of controls in Visual Basic:

Intrinsic controls, such as the command button and frame controls. These controls are
contained inside the Visual Basic .exe file. Intrinsic controls are always included in the
toolbox, unlike ActiveX controls and insertable objects, which can be removed from or
added to the toolbox.

ActiveX controls, which exist as separate files with a .ocx file name extension. These
include controls that are available in all editions of Visual Basic (DataCombo, DataList
controls, and so on) and those that are available only in the Professional and Enterprise
editions (such as Listview, Toolbar, Animation, and Tabbed Dialog). Many third-party
ActiveX controls are also available.

Insertable Objects, such as a Microsoft Excel Worksheet object containing a list of all
your company's employees, or a Microsoft Project Calendar object containing the
scheduling information for a project. Since these can be added to the toolbox, they can be
considered controls. Some of these objects also support Automation (formerly called

15
OLE Automation), which allows you to program another application's objects from
within a Visual Basic application. See "Programming with Objects," for more
information on Automation.

This chapter discusses about a few most commonly used controls like label, text box,
button, check box, option button, list and combo box, etc.

Program 3.1: Displaying the mouse co-ordinates and changing the background color of a
form.

1. Start Visual Basic and pick "Standard Exe" from the list of new projects.
2. Go to the properties page (on the right) and find the caption property for the main
form (Form1). Change that to My First Example Program.
3. Add a Command Button to the form by clicking the tool and then drawing on
the form.
4. Now, click once on the button you just drew to select it and go to the properties
page on the right-hand side of the screen. Find the (name) property and change it
to cmdPressMe. Next, in the same properties page, find the caption property and
change its value to Press Me.
5. Now, double click the button. This will bring up the code-view window. Type in
the following code into the cmdPressMe_Click( ) event:

Private Sub cmdPressMe_Click( )


cmdPressMe.Caption = "You pressed me!"
End Sub

6. Next on the list is to add two labels. Labels are added with the tool. By
selecting each label in turn, change their (name) properties to lblCoordsA and
lblCoordsB, respectively. Now, change the caption property of lblCoordsA to
read Current mouse coordinates: and just leave the other one the way it is.

Figure 3.2 Selecting Form Event from event list box

16
7. At this point, just double click somewhere on the form, but not on any of the
controls or labels you have added. This should yield you the shell for the
Form_Load( ) subroutine. With Form as your active object, select the
MouseMove event from the event list as shown in Figure 3.2. When you click it,
you should get the shell for the Form_MouseMove( ... ) subroutine. Here's the
code you want for that routine:

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, _


X As Single, Y As Single)

lblCoordsB.Caption = "x = " & X & " y = " & Y

End Sub

8. Using the tool, draw a checkbox on the form. Change the (name) property of
the checkbox to chkBGColour. Then, change the caption property of the
checkbox to read Change Background Colour. Next, double click the checkbox to
give yourself a shell for the chkBGColour_Click() event handler. The code for
that routine looks like this:

Private Sub chkBGColour_Click( )


' If CheckBox checked then set background of form to red.
If (chkBGColour.Value = Checked) Then
Form1.BackColor = RGB(255, 0, 0)
' If CheckBox is unchecked then set background of form to grey.
ElseIf (chkBGColour.Value = Unchecked) Then
Form1.BackColor = RGB(210, 210, 210)
End If
End Sub

Figure 3.3 Output

17
9. Finally when you execute the application you’ll find a form similar to that of the
one shown in Figure 3.3. If you push the button, you'll see the text there change,
if you move your mouse around, it'll track your mouse movements by displaying
the coordinates and you can change the background color by clicking the
checkbox.

Program 3.2: Working with list box – adding and deleting items.

1. Start Visual Basic and pick "Standard Exe" from the list of new projects.
2. Add a button. Change its caption to &Add - note: the '&' will make the letter after
it a keyboard shortcut. Change its (name) to cmdAdd.
3. Add another button. Change this second button's caption to &Delete. Change that
button's (name) to cmdDelete.
4. Add a label. Change the label's caption to Text to add.
5. Add a textbox using the tool and change that textbox's (name) to txtAddText.
6. Add a listbox using the tool and change that listbox's (name) to lstTextList.
7. Now double-click on the form ... but be careful to not double-click on any of your
controls! This should get you the Form_Load( ) routine and enter the follwing
lines of code in the Form_Load( ) event to disable the list box control if it
contains no items:

'if there's nothing in the listbox, disable the delete button...


Private Sub Form_Load()
If (lstTextList.ListCount = 0) Then
cmdDelete.Enabled = False
End If
End Sub

8. Now, go back to the form design window and double-click the Add button. The
code for cmdAdd_click() is as follows:

Private Sub cmdAdd_Click()


' Add the string that is currently in the textBox to the List Box.
lstTextList.AddItem txtAddText.Text

' delete button disabled? enable it. :)


If (cmdDelete.Enabled = False) Then
cmdDelete.Enabled = True
End If
End Sub

9. Once that's done, get the form design and double-click the Delete button and add
the follwing lines of code in the cmdDelete_Click( ):

18
' This method contains the code for the click event for the delete button.
Private Sub cmdDelete_Click()
' if the listbox isn't empty, remove an item ...
‘ disable delete button if necessary...
If (Not (lstTextList.ListCount = 0)) Then
lstTextList.RemoveItem (lstTextList.ListCount - 1)
If (lstTextList.ListCount = 0) Then
cmdDelete.Enabled = False
End If
End If
End Sub

10. If you run the program now, you should be able to add and remove stuff from the
listbox depending on what you type in the textbox as shown in Figure 3.4.

Figure 3.4 Working with List box Control

3.2 Working with Combo Box Control

Combo boxes are so-named because they "combine" the features found in both text boxes
and list boxes. Combo boxes are also commonly referred to as "drop-down boxes" or
"drop-down lists". There are three combo box styles:
 0 Drop Down Combo
 1 Simple Combo
 2 Drop Down List

At design-time, you set the style of the combo box with its Style property.

Every system has many fonts on it. Visual Basic allows us access to these fonts through
its Screen object. The following program demonstrates this. It also demonstrates how you
can use for loop to loop through all the fonts. Lastly the source code demonstrates using a
combo box control.

19
Program 3.3: Fill a combo box with system fonts

1. Create a new Visual Basic program; add a command button and a combo box to
it.
2. Double click on the command button to get into its click event handler method
and add the code below.

Private Sub Command1_Click( )


Dim I As Integer
For I = 1 To Screen.FontCount - 1
Combo1.AddItem Screen.Fonts(I)
Next
End Sub

3. Run the project and find the content of the combobox.

Obviously this is just the start to a program. You may for example want to allow the user
to select a font and then apply that font to a text box or something else you have in your
program.

Let’s look at another program which narrates the working of various types combo box
controls.

Program 3.4: Combo Box Demo Program

1. Start Visual Basic and pick "Standard Exe" from the list of new projects.
2. Design a form as shown in Figure 3.5.
3. In the form draw three frames Frame1, Frame2 and Frame3 respectively. Set the
Caption property to 'Style "2 - Dropdown List"', 'Style "0 - Dropdown
Combo"' and 'Style "1 - Simple Combo"' for Frame 1, 2 and 3 respectivley.
4. Add a combo box named cboFood with its Style property set to 2 Dropdown List
in Frame 1. Also add three command buttons, named cmdLoadFoodCombo,
cmdSelect, and cmdDeterminewith and a checkbox named chkAuto in Frame
1.
5. Similarly add a combo box named cboStateAbbrev with its Style property set to
0 Dropdown Combo, two command buttons, named
cmdLoadStateAbbrevCombo and cmdAddNewAbbrev into Frame 2.
6. Finally add a combo box named cboStateName with its Style property set to 1
Simple Combo and two command buttons, named cmdLoadStateNameCombo
and cmdAddNewName to Frame 3.
7. Let’s first look at the code dealing with the Dropdown List style of the combo
box. In the cmdLoadFoodCombo_Click ( ) event first clear the cboFood combo
box, then manually add three food items along with their calorie count in the
corresponding ItemData property. We then inform the user that the combo box
has been loaded.

20
Private Sub cmdLoadFoodCombo_Click( )

cboFood.Clear
cboFood.AddItem "Orange"
cboFood.ItemData(cboFood.NewIndex) = 60
cboFood.AddItem "Apple"
cboFood.ItemData(cboFood.NewIndex) = 80
cboFood.AddItem "Banana"
cboFood.ItemData(cboFood.NewIndex) = 105

MsgBox "Food combo box has been loaded.", vbInformation, _


"Combo Box Demo"

End Sub

Figure 3.5 Combo Box Demo – Form at design Time

21
8. Next you need to show how to select a specific entry from a combo box in code.
Given an item to match against, you loop through the entries in the combo box
until you either find a matching entry or you go through the entire list without
finding the entry. If you find the desired entry, you set the ListIndex property to
that of the matching entry and exit the loop early. In this example, an InputBox
prompts the user to enter a food. We then loop through the entries of the combo
box, comparing the current List entry to the food item entered in the InputBox. If
and when the item is found, the ListIndex is set accordingly. To achieve the
above mentioned activities add the following lines of code in the click event of
the command button CmdSelect_Click( ) Event:

Private Sub cmdSelect_Click()

Dim strFood As String


Dim intX As Integer
Dim blnFound As Boolean

strFood = InputBox("Please enter the food to select (apple, _


orange, or banana).", "Combo Box Demo - Select with Code")

If strFood = "" Then Exit Sub


blnFound = False

For intX = 0 To cboFood.ListCount - 1


If UCase$(cboFood.List(intX)) = UCase$(strFood) Then
cboFood.ListIndex = intX
blnFound = True
Exit For
End If
Next

If Not blnFound Then


MsgBox "Item was not found in the list.", vbExclamation, _
"Combo Box Demo"
End If

End Sub

9. Next you need to show determine and obtain the value of the item that has been
selected in the combo box which is done in the cmdDetermine_Click( ) event.

Private Sub cmdDetermine_Click( )

If cboFood.ListIndex = -1 Then
MsgBox "There is no item currently selected.", vbInformation, _
"Combo Box Demo"

22
Exit Sub
End If

MsgBox "You have selected " & cboFood.List(cboFood.ListIndex) & _


"." & vbNewLine & "It has " & cboFood.ItemData(cboFood.ListIndex) _
& " calories.", vbInformation, "Combo Box Demo"

End Sub

10. Now to show that the value of the selected items can be obtained as soon as the
user selects it from the drop-down list, first you need to check the chkAuto
checkbox, and then by selecting an item from the cboFood combo box.

Private Sub cboFood_Click( )


If chkAuto.Value = vbChecked Then
Call cmdDetermine_Click
End If
End Sub

11. Next load the cboStateAbbrev combo box in the click event of the
cmdLoadStateAbbrevCombo command button with the state abbreviations of
states in India (e.g. ‘TN’ for Tamil Nadu, ‘AP’ for Andhra Pradesh, etc,.) from a
comma-delimited sequential file called STATES.DAT. You can open the file
using a text editor and save the file in your project folder. The records in the file
contain two fields, the state abbreviation and state name as shown in Figure 3.6;
only the abbreviations are loaded into the combo box. No values are added to the
optional ItemData property array of the combo box.

Figure 3.6 Contents of STATES.DAT

Private Sub cmdLoadStateAbbrevCombo_Click( )

Dim intStateFileNbr As Integer


Dim strBS As String

23
Dim strStateAbbrev As String
Dim strStateName As String

strBS = IIf(Right$(App.Path, 1) = "\", "", "\")

intStateFileNbr = FreeFile

Open (App.Path & strBS & "STATES.DAT") For Input As #intStateFileNbr

cboStateAbbrev.Clear

Do Until EOF(intStateFileNbr)
Input #intStateFileNbr, strStateAbbrev, strStateName
cboStateAbbrev.AddItem strStateAbbrev
Loop

Close #intStateFileNbr

MsgBox "State abbreviation combo box has been loaded.", _


vbInformation, "Combo Box Demo"

End Sub

12. When you want to add new items into a combo box, you can type in a new entry
in the textbox portion of the combo box. However, a new entry is not
automatically added to the list portion of the combo box. If you wish to do this,
you must do so with code, as the code in this event procedure demonstrates. When
the "Add New Item to List" button is clicked, this code runs to first check that the
item is not already in the list, and if not, adds it.

Private Sub cmdAddNewAbbrev_Click()

Dim intX As Integer

If cboStateAbbrev.Text = "" Then Exit Sub

For intX = 0 To cboStateAbbrev.ListCount - 1

If UCase$(cboStateAbbrev.Text) = UCase$(cboStateAbbrev.List(intX)) _
Then
MsgBox "Item '" & cboStateAbbrev.Text & "' is already in list.", _
vbExclamation, "Combo Box Demo"
Exit Sub
End If
Next

24
' if we get here, the item entered in text portion is not in the list

cboStateAbbrev.AddItem cboStateAbbrev.Text
MsgBox "Item '" & cboStateAbbrev.Text & "' has been added to the list.", _
vbExclamation, "Combo Box Demo"

End Sub

13. Finally, we will look at the code dealing with the Simple Combo style of the
combo box. Let’s load the state names of India from the same comma-delimited
sequential file called STATES.DAT. This is done in the
cmdLoadStateNameCombo_Click( ) event.

Private Sub cmdLoadStateNameCombo_Click()

Dim intStateFileNbr As Integer


Dim strBS As String
Dim strStateAbbrev As String
Dim strStateName As String

strBS = IIf(Right$(App.Path, 1) = "\", "", "\")

intStateFileNbr = FreeFile

Open (App.Path & strBS & "STATES.DAT") For Input As #intStateFileNbr

cboStateName.Clear

Do Until EOF(intStateFileNbr)
Input #intStateFileNbr, strStateAbbrev, strStateName
cboStateName.AddItem strStateName
Loop

Close #intStateFileNbr

MsgBox "State name combo box has been loaded.", _


vbInformation, "Combo Box Demo"

End Sub

14. To add new states into the simple combo box use the following code in the
cmdAddNewName_Click( ) event.

Private Sub cmdAddNewName_Click()

25
Dim intX As Integer

If cboStateName.Text = "" Then Exit Sub

For intX = 0 To cboStateName.ListCount - 1

If UCase$(cboStateName.Text) = UCase$(cboStateName.List(intX)) Then


MsgBox "Item '" & cboStateName.Text & "' is already in list.", _
vbExclamation, "Combo Box Demo"
Exit Sub
End If
Next

' if we get here, the item entered in text portion is not in the list

cboStateName.AddItem cboStateName.Text
MsgBox "Item '" & cboStateName.Text & "' has been added to the list.", _
vbExclamation, "Combo Box Demo"

End Sub

15. Run the application and try using the various combo boxes in your form. Try
adding new as well as existing state names and state abbreviations and observe
the results.

3.3 String Functions and Text Box Control

3.3.1 Count the number of words in a textbox control

Sometimes when entering text in an input field we want to know how many words we
have entered. For example: Please provide a description of the damage (Maximum 500
words). It is easy to find out the number of characters entered in a text box, but to get the
number of words using Visual Basic we need to put in a little more effort.

Program 3.5: Counting the number of words in a Text box

1. Create a new VB6 program.


2. Add a text box to the form and a command button.
3. Double click the command button to get into its click event handler. Inside this
method add the following code:

Dim Counter As Integer


Dim StartPos As Integer

If Trim(Text1) = "" Then


NumOfWords = 0

26
Exit Sub
End If

NumOfWords = 1
For Counter = 1 To Len(Text1)
If Mid(Text1, Counter, 1) = " " Then
NumOfWords = NumOfWords + 1
End If
Next Counter

MsgBox "Found " & NumOfWords & " Words"

4. Once you have added your code run the application and enter some text in the text
box. Click the button and you should see a message box that tells you exactly how
many words you have entered.

3.3.2 Replace Text in a Text Box control using String functions

Everyone has probably used or at least seen the find and replace feature in programs. This
allows the user to find everything that matches the specified text string and replace it. The
following program demonstrates the same functionality in Visual Basic. In general to find
a sub string in a parent string you can use the InStr function. However, in order to replace
the found strings with a new one you need to get a little bit trickier.

Program 3.6: Pattern replacement in a text box.

1. Create a new project, add a command button to the main form, add a text box as
well.
2. Double click the command button to into the click event handler for your button.
In this method add the following code.

Dim StartPos, Counter As Integer


Dim FindString, ReplaceText As String
FindString = "test"
ReplaceText = "MyString"

For Counter = 1 To Len(Text1.Text)


StartPos = InStr(Text1.Text, FindString)
If StartPos > 0 Then
Text1.SelStart = StartPos - 1
Text1.SelLength = Len(FindString)
Text1.SelText = "" + ReplaceText
End If
Next

27
3. Once you have the code in place run your application and add some text that has
the string test in it. Hit the button and you will see all of these instances of the
word test replaced with the string 'MyString'.

List Box Control

A list box control displays a list of items from which the user can select one or more. List
boxes present a list of choices to the user. By default, the choices are displayed vertically
in a single column, although you can set up multiple columns as well. If the number of
items exceeds what can be displayed in the list box, scroll bars automatically appear on
the control. The user can then scroll up and down, or left to right through the list.

A commonly seen action in Windows programs is one in which you have two ListBoxes,
where one ListBox contains all of the available items; the other is intended to contain
selected items from the list of all available items. The user adds and removes items by
selecting items from the ListBoxes and then clicking an appropriate command button.

Program 3.7: Adding and removing items from a list box control.

1. Create a new project and add two ListBoxes, named lstAvail and lstSelected. Both
have their Sorted property set to True and their MultiSelect property set to
Extended. Also ass two command buttons are named cmdAdd and cmdRemove.
Now your form will look like the one shown in Figure3.7.

Figure 3.7 List box Demo Interface

28
2. To move the selected items from lstAvail to lstSelected, place the following code
in the cmdAdd_Click event:

Private Sub cmdAdd_Click()


Dim intListX As Integer
For intListX = lstAvail.ListCount = 1 To 0 Step -1
If lstAvail.Selected(intListX) Then

lstSelected.AddItem lstAvail.List(intListX)

lstSelected.ItemData(lstSelected.NewIndex) = _
lstAvail.ItemData(intListX)
lstAvail.RemoveItem intListX
End If
Next
End Sub

If you are using the optional ItemData property array, this ItemData "baggage" is
not carried along automatically when you move an item from one list to another
with the AddItem method. If you were to omit the line

lstSelected.ItemData(lstSelected.NewIndex) = lstAvail.ItemData(intListX)

the ItemData data would be deleted with the RemoveItem method.

3. Now suppose the user wants to remove a few items from lstSelected and send
them back to lstAvail. The user selects the items to remove and then clicks the
Remove button, which contains the following code:

Private Sub cmdRemove_Click()


Dim intListX As Integer

For intListX = lstSelected.ListCount = 1 To 0 Step -1

If lstSelected.Selected(intListX) Then

lstAvail.AddItem
lstSelected.List(intListX)lstAvail.ItemData(lstAvail.NewIndex) = _
lstSelected.ItemData(intListX)
lstSelected.RemoveItem intListX
End If
Next
End Sub

4. When you run the project you can find that the items that were selected in
lstSelected were removed from lstSelected and added back to lstAvail.

29
Drag and Drop is an amazing feature to add to your application when you are trying to
create a slick and intuitive interface for your end users. Another great benefit of adding
drag and drop functionality to your application is that it is very logical for the user. In real
life if you want to move a piece of paper from one stack to another you simply pick it up,
move it, and place it in the new stack. This is the exact same gesture you go through with
Drag and Drop.

Program 3.8: Drag and Drop using List box control.

1. Create a new VB project, add a listbox control to the form and set its DragMode
property to Automatic.
2. Go to the code window and add the following code:

Dim ItemCount As Integer


Dim I As Integer

On Error Resume Next


ItemCount = Data.Files.Count

For I = 1 To ItemCount
List1.AddItem Data.Files(I)
Next

If Err Then Err.Clear

3. Once you have the code in place run your program (Press F5) and then you can
drag things into your list box. For example open up your My Computer explorer
and drag a folder from it onto your listbox. You will see it now is located in the
box. You can build upon this to add great drag and drop support to your
applications.

Understanding Check Boxes

The checkbox acts as a "toggle" control: if it's on, clicking it turns it off; if it's off,
clicking it turns it on. Unlike the option button, the operation of each checkbox on a form
or frame is independent of all other checkboxes; changing the status of one does not
affect other checkboxes.

The program can read or set the status of a checkbox with the Value property (which is
the default property of the checkbox). The Value property of a checkbox is of the Integer
type. A value of 0 means "off", a value of 1 means "on". You can use the VB constants
vbUnchecked or vbChecked for 0 or 1, respectively.

30
Program 3.9: Checkbox demo.

1. Create a new project.


2. Add a form and 6 checkboxes within a frame, named chkHobby1, chkHobby2, …,
chkHobby6. The form also contains a command button called cmdOK and a label
called lblInfo. The form at design time likes like the one shown in Figure3.8.

Figure 3.8 Combo Box Demo – Form at design time

3. Add the following lines of code in the command button’s click event:

Private Sub cmdOK_Click()

Dim strInfo As String


strInfo = "Items selected:"
If chkHobby1 = vbChecked Then strInfo = strInfo & " aerobics"
If chkHobby2 = vbChecked Then strInfo = strInfo & " reading"
If chkHobby3 = vbChecked Then strInfo = strInfo & " travel"
If chkHobby4 = vbChecked Then strInfo = strInfo & " movies"
If chkHobby5 = vbChecked Then strInfo = strInfo & " computers"
If chkHobby6 = vbChecked Then strInfo = strInfo & " sports"
lblInfo = strInfo

End Sub

4. Run the application. Select different hobbies and then click the command button.
Now you’ll find the hobbies selected by you being listed at the bottom of the form
as shown in Figure 3.9.

31
Figure 3.9 Sample Run for Checkbox demo

3.6 Common Dialog Controls

The common dialog control provides a standard set of dialog boxes for operations such as
opening and saving files, setting print options, and selecting colors and fonts. The control
also has the ability to display Help by running the Windows Help engine.

The common dialog control provides an interface between Visual Basic and the routines
in the Microsoft Windows dynamic-link library Commdlg.dll. To create a dialog box
using this control, Commdlg.dll must be in your Microsoft Windows \System directory.

You use the common dialog control in your application by adding it to a form and setting
its properties. The dialog displayed by the control is determined by the methods of the
control. At run time, a dialog box is displayed or the Help engine is executed when the
appropriate method is invoked; at design time, the common dialog control is displayed as
an icon on a form. This icon can't be sized.

The common dialog control allows you to display these commonly used dialog boxes:
 Open
 Save As
 Color
 Font
 Print

To use the common dialog control:

1. If you haven't already done so, add the common dialog control to the toolbox by
selecting Components from the Project menu. Locate and select the control in
the Controls tabbed dialog (Figure3.10), then click the OK button.

32
Common
Dialog
Control

Figure 3.10 Adding Common Dialog control from Components

2. On the toolbox, click the CommonDialog control and draw it on a form. When
you draw a common dialog control on a form, it automatically resizes itself. The
common dialog control is invisible at run time.
3. At run time, use the appropriate method, as listed in the following table, to display
the desired dialog.

Method Dialog displayed

ShowOpen Open

ShowSave Save As

ShowColor Color

ShowFont Font

ShowPrinter Print

ShowHelp Invokes Windows Help

33
Program 3.10: Working with Common dialog controls.

1. Create a new Project. Add a CommonDialog control named dlgDemo to the form.
2. Design a from as shown in Figure 3.11.

Figure 3.11 Form design involving CommonDialog Control

3. The form has the following controls and properties set as shown below:

Control Property Value


Text Box Name tstTestFile
MultiLine True
ScrollBars 2 – Vertical
Label1 Name lblColor
BorderStyle 1 – Fixed single
Label2 Name lblFont
BorderStyle 0 – None
Command Button1 Name cmdOpen
Caption Open
Command Button2 Name cmdSave
Caption Save
Command Button3 Name cmdPrint
Caption Print
Command Button4 Name cmdColor
Caption Color

34
Command Button5 Name cmdFont
Caption Font
Command Button6 Name cmdHelp
Caption Help
Command Button7 Name cmdExit
Caption Exit

4. Type the following lines of code in the general part of the code window:

Option Explicit
Private mstrLastDir As String

5. Initialize the mstrLastDir variable in the form load event;

Private Sub Form_Load( )


mstrLastDir = App.Path
End Sub

6. Write the following Open Dialog control logic in the click event of the cmdOpen
button:

Private Sub cmdOpen_Click( )

Dim strBuffer As String


Dim intDemoFileNbr As Integer
Dim strFileToOpen As String

On Error GoTo cmdOpen_Click_Exit

With dlgDemo
.CancelError = True
.InitDir = mstrLastDir
.Flags = cdlOFNHideReadOnly
.FileName = ""
.Filter = "Text Files(*.txt)|*.txt|All Files(*.*)|*.*"
.ShowOpen
strFileToOpen = .FileName
End With

On Error GoTo cmdOpen_Click_Error

intDemoFileNbr = FreeFile
Open strFileToOpen For Binary Access Read As #intDemoFileNbr
strBuffer = Input(LOF(intDemoFileNbr), intDemoFileNbr)
txtTestFile.Text = strBuffer
Close #intDemoFileNbr

35
mstrLastDir = Left$(strFileToOpen, InStrRev(strFileToOpen, "\") - 1)

Exit Sub

cmdOpen_Click_Error:

MsgBox "The following error has occurred:" & vbNewLine _


& "Err # " & Err.Number & " - " & Err.Description, _
vbCritical, _
"Open Error"

cmdOpen_Click_Exit:
End Sub

7. Write the following Save dialog control logic in the click event of the cmdSave
button:

Private Sub cmdSave_Click( )

Dim strBuffer As String


Dim intDemoFileNbr As Integer
Dim strFileToSave As String

On Error GoTo cmdSave_Click_Exit

With dlgDemo
.CancelError = True
.InitDir = mstrLastDir
.Flags = cdlOFNOverwritePrompt + cdlOFNPathMustExist
.FileName = ""
.Filter = "Text Files(*.txt)|*.txt|All Files(*.*)|*.*"
.ShowSave
strFileToSave = .FileName
End With

On Error GoTo cmdSave_Click_Error

intDemoFileNbr = FreeFile
Open strFileToSave For Binary Access Write As #intDemoFileNbr
strBuffer = txtTestFile.Text
Put #intDemoFileNbr, , strBuffer
Close #intDemoFileNbr

mstrLastDir = Left$(strFileToSave, InStrRev(strFileToSave, "\") - 1)

36
Exit Sub

cmdSave_Click_Error:
MsgBox "The following error has occurred:" & vbNewLine _
& "Err # " & Err.Number & " - " & Err.Description, _
vbCritical, _
"Save Error"

cmdSave_Click_Exit:
End Sub

8. Write the following Print Dialog control logic in the click event of the cmdPrint
button:

Private Sub cmdPrint_Click( )

Dim intX As Integer


Dim intCopies As Integer

On Error GoTo cmdPrint_Click_Exit

With dlgDemo
.CancelError = True
.Flags = cdlPDHidePrintToFile + cdlPDNoPageNums _
+ cdlPDNoSelection
.ShowPrinter
intCopies = .Copies
End With

On Error GoTo cmdPrint_Click_Error

For intX = 0 To Printer.FontCount - 1


If Printer.Fonts(intX) Like "Courier*" Then
Printer.FontName = Printer.Fonts(intX)
Exit For
End If
Next
Printer.FontSize = 10
For intX = 1 To intCopies
If intX > 1 Then
Printer.NewPage
End If
Printer.Print txtTestFile.Text
Next
Printer.EndDoc

37
Exit Sub

cmdPrint_Click_Error:
MsgBox "The following error has occurred:" & vbNewLine _
& "Err # " & Err.Number & " - " & Err.Description, _
vbCritical, _
"Print Error"

cmdPrint_Click_Exit:
End Sub

9. Write the following Color Dialog control logic in the click event of the cmdColor
button:

Private Sub cmdColor_Click( )

Dim lngColor As Long

On Error GoTo cmdColor_Click_Exit

With dlgDemo
.CancelError = True
.ShowColor
lngColor = .Color
End With

On Error GoTo cmdColor_Click_Error

lblColor.BackColor = lngColor

Exit Sub

cmdColor_Click_Error:
MsgBox "The following error has occurred:" & vbNewLine _
& "Err # " & Err.Number & " - " & Err.Description, _
vbCritical, _
"Color Error"

cmdColor_Click_Exit:
End Sub

38
10. Write the following Font Dialog control logic in the click event of the cmdFont
button:

Private Sub cmdFont_Click( )

Dim lngFont As Long

On Error GoTo cmdFont_Click_Exit

With dlgDemo
.CancelError = True
.Flags = cdlCFBoth + cdlCFForceFontExist + cdlCFEffects
.ShowFont
On Error GoTo cmdFont_Click_Error
lblFont.FontBold = .FontBold
lblFont.FontItalic = .FontItalic
lblFont.FontName = .FontName
lblFont.FontSize = .FontSize
lblFont.FontStrikethru = .FontStrikethru
lblFont.FontUnderline = .FontUnderline
lblFont.ForeColor = .Color
lblFont.Caption = .FontName & ", " & .FontSize & " pt"
End With

Exit Sub

cmdFont_Click_Error:
MsgBox "The following error has occurred:" & vbNewLine _
& "Err # " & Err.Number & " - " & Err.Description, _
vbCritical, _
"Font Error"

cmdFont_Click_Exit:
End Sub

11. Write the following Help Dialog control logic in the click event of the cmdHelp
button:

Private Sub cmdHelp_Click( )

On Error GoTo cmdHelp_Click_Error

With dlgDemo
.CancelError = True
.HelpCommand = cdlHelpForceFile
.HelpFile = App.Path & "\JETSQL35.HLP"

39
.ShowHelp
End With

Exit Sub

cmdHelp_Click_Error:
End Sub

12. Finally write the following code in the click event of the cmdExit button:

Private Sub cmdExit_Click( )


Unload Me
End Sub

13. Run the application. Click the various buttons to invoke the respective dialog
windows and observe what happens when you interact with the various options in
the dialog windows.

3.7 Control Arrays

You can group a set of controls together as an array. The following facts apply to control
arrays:

 The set of controls that form a control array must be all of the same type (all
textboxes, all labels, all option buttons, etc.)

 You set up a control array by naming one or more controls of the same type the
same name and set the Index property of each control in the array to a non-
negative value (i.e., the controls in the control array are usually indexed from 0 to
one less than the number of controls in the array).

 The properties of the controls in the control array can vary: i.e., some members
can be visible or not, they can be sized differently, they can have different fonts or
colors, etc.

 To refer to a member of a control array, the syntax is:

ControlName(Index)[.Property]

For example, to refer to the Text property of the first element of an array of
textboxes called txtField, you would use:

txtField(0).Text

 All the members of the control array share the same event procedure for example,
if you have a control array of 10 textboxes call txtField, indexed 0 to 9, you will

40
not have 10 different GotFocus events. You will just have one that is shared
amongst the 10 members. To differentiate which member of the control array is
being acted upon, VB will automatically pass an Index parameter to the event
procedure. For example, the GotFocus event procedure for the txtField control
array might look like this:

Private Sub txtField_GotFocus(Index As Integer)

txtField(Index).SelStart = 0
txtField(Index).SelLength = Len(txtField(Index).Text)

End Sub

Let’s have a look at how to create control arrays and their working using the following
program.

Program 3.11: Build a sample application that uses a control array.

1. Start a new VB project. Place a command button toward the bottom of the form
and set its properties as follows:

Property Value
(Name) cmdTest
Caption First

2. Click the command button once to select it. Then Copy it (press Ctrl-C, or right-
click the mouse and choose Copy).
3. Click on an open area of the form and Paste (press Ctrl-V, or right-click the
mouse and choose Paste). The following message will appear: You already have
a control named 'cmdTest'. Do you want to create a control array? Respond
Yes. The pasted control will appear in the upper left-hand corner of the form.
Move the pasted control toward the bottom, next the original. By answering yes to
the prompt, VB automatically set the Index property of the original command
button to 0 and set the Index of the pasted control to 1.
4. Paste two more times (VB will not prompt you any more now that it knows you
want to create a control array), moving the pasted controls next to the others. Set
the Captions of cmdTest(1), (2), and (3) to "Second", "Third", and "Fourth"
respectively. At this point your form should look like the one shown in Figure
3.12.

41
Figure 3.12 Form Design after copy and paste the controls.

5. Place the following code in the cmdTest_Click event:

Private Sub cmdTest_Click(Index As Integer)


Print cmdTest(Index).Caption
End Sub

6. Run the project and click the various buttons in any order. A sample run is shown
in Figure 3.13.

Figure 3.13 Sample Run of a Form involving Control Array

42
Now let’s see how to design and develop a simple calculator using control array.

Program 3.12: Developing a simple calculator using Control Array.

1. Start a new VB project. Design a form as shown in Figure 3.14. The form has a
label named lbldisplay with Backcolor = &H00000000& and BorderStyle = 1 –
Fixed single. Then create a control array cmdCal involving 12 command buttons
as explained in program3.3. Set the index property of the 12 command buttons
according to row wise order as shown in Figure3.9. (e.g. The backspace button’s
index is set to 0, CE button’s index is set to 1,…, and at last the equal to button is
set with an index 22.

Figure 3.14 Calculator form Design

2. Declare the following variables in the general part of your code window:

Option Explicit

Private mdblResult As Double


Private mdblSavedNumber As Double
Private mstrDot As String
Private mstrOp As String
Private mstrDisplay As String
Private mblnDecEntered As Boolean
Private mblnOpPending As Boolean
Private mblnNewEquals As Boolean
Private mblnEqualsPressed As Boolean
Private mintCurrKeyIndex As Integer

3. Adjust the form’s dimensions at the time display by setting the following form
properties in the form load event:

43
Private Sub Form_Load( )

Top = (Screen.Height - Height) / 2


Left = (Screen.Width - Width) / 2

End Sub

4. To allow the users give input through keyboard, we should map the command
buttons’ Index to corresponding keys on the keyboard. This mapping can be done
when a key is pressed by the user, i.e., in the KeyDown( ) event.

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)

Dim intIndex As Integer

Select Case KeyCode


Case vbKeyBack: intIndex = 0
Case vbKeyDelete: intIndex = 1
Case vbKeyEscape: intIndex = 2
Case vbKey0, vbKeyNumpad0: intIndex = 18
Case vbKey1, vbKeyNumpad1: intIndex = 13
Case vbKey2, vbKeyNumpad2: intIndex = 14
Case vbKey3, vbKeyNumpad3: intIndex = 15
Case vbKey4, vbKeyNumpad4: intIndex = 8
Case vbKey5, vbKeyNumpad5: intIndex = 9
Case vbKey6, vbKeyNumpad6: intIndex = 10
Case vbKey7, vbKeyNumpad7: intIndex = 3
Case vbKey8, vbKeyNumpad8: intIndex = 4
Case vbKey9, vbKeyNumpad9: intIndex = 5
Case vbKeyDecimal: intIndex = 20
Case vbKeyAdd: intIndex = 21
Case vbKeySubtract: intIndex = 16
Case vbKeyMultiply: intIndex = 11
Case vbKeyDivide: intIndex = 6
Case Else: Exit Sub
End Select

cmdCalc(intIndex).SetFocus
cmdCalc_Click intIndex

End Sub

5. Similarly assign the intIndex variable with index values of “sqrt”, “%”, “1/x” and
“=” buttons when the user presses the “S”, “P”, “R”, “X” and “=” keys
respectively on the keyboard.

44
Private Sub Form_KeyPress(KeyAscii As Integer)

Dim intIndex As Integer

Select Case Chr$(KeyAscii)


Case "S", "s": intIndex = 7
Case "P", "p": intIndex = 12
Case "R", "r": intIndex = 17
Case "X", "x": intIndex = 11
Case "=": intIndex = 22
Case Else: Exit Sub
End Select

cmdCalc(intIndex).SetFocus
cmdCalc_Click intIndex

End Sub

6. Finally enter the following lines of code in the click event of the command button
control array:

Private Sub cmdCalc_Click(Index As Integer)

Dim strPressedKey As String

mintCurrKeyIndex = Index

If mstrDisplay = "ERROR" Then


mstrDisplay = ""
End If

strPressedKey = cmdCalc(Index).Caption

Select Case strPressedKey

Case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
If mblnOpPending Then
mstrDisplay = ""
mblnOpPending = False
End If
If mblnEqualsPressed Then
mstrDisplay = ""
mblnEqualsPressed = False
End If
mstrDisplay = mstrDisplay & strPressedKey

45
Case "."
If mblnOpPending Then
mstrDisplay = ""
mblnOpPending = False
End If
If mblnEqualsPressed Then
mstrDisplay = ""
mblnEqualsPressed = False
End If
If InStr(mstrDisplay, ".") > 0 Then
Beep
Else
mstrDisplay = mstrDisplay & strPressedKey
End If

Case "+", "-", "X", "/"


mdblResult = Val(mstrDisplay)
mstrOp = strPressedKey
mblnOpPending = True
mblnDecEntered = False
mblnNewEquals = True

Case "%"
mdblSavedNumber = (Val(mstrDisplay) / 100) * mdblResult
mstrDisplay = Format$(mdblSavedNumber)

Case "="
If mblnNewEquals Then
mdblSavedNumber = Val(mstrDisplay)
mblnNewEquals = False
End If

Select Case mstrOp

Case "+"
mdblResult = mdblResult + mdblSavedNumber
Case "-"
mdblResult = mdblResult - mdblSavedNumber
Case "X"
mdblResult = mdblResult * mdblSavedNumber
Case "/"
If mdblSavedNumber = 0 Then
mstrDisplay = "ERROR"
Else
mdblResult = mdblResult / mdblSavedNumber
End If

46
Case Else
mdblResult = Val(mstrDisplay)
End Select

If mstrDisplay <> "ERROR" Then


mstrDisplay = Format$(mdblResult)
End If
mblnEqualsPressed = True

Case "+/-"
If mstrDisplay <> "" Then
If Left$(mstrDisplay, 1) = "-" Then
mstrDisplay = Right$(mstrDisplay, 2)
Else
mstrDisplay = "-" & mstrDisplay
End If
End If

Case "Backspace"
If Val(mstrDisplay) <> 0 Then
mstrDisplay = Left$(mstrDisplay, Len(mstrDisplay)- 1)
mdblResult = Val(mstrDisplay)
End If

Case "CE"
mstrDisplay = ""

Case "C"
mstrDisplay = ""
mdblResult = 0
mdblSavedNumber = 0
Case "1/x"
If Val(mstrDisplay) = 0 Then
mstrDisplay = "ERROR"
Else
mdblResult = Val(mstrDisplay)
mdblResult = 1 / mdblResult
mstrDisplay = Format$(mdblResult)
End If
Case "sqrt"
If Val(mstrDisplay) < 0 Then
mstrDisplay = "ERROR"
Else
mdblResult = Val(mstrDisplay)
mdblResult = Sqr(mdblResult)
mstrDisplay = Format$(mdblResult)

47
End If
End Select

If mstrDisplay = "" Then


lblDisplay = "0."
Else
mstrDot = IIf(InStr(mstrDisplay, ".") > 0, "", ".")
lblDisplay = mstrDisplay & mstrDot
If Left$(lblDisplay, 1) = "0" Then
lblDisplay = Mid$(lblDisplay, 2)
End If
End If

If lblDisplay = "." Then


lblDisplay = "0."

End Sub

7. Run the calculator application and test by providing different inputs.

Option Buttons

Option buttons, also called radio buttons, are typically used in a group of two or more. At
any one time, only one button in the group can be "on". Clicking an option button turns it
"on" and turns all other buttons in the group "off". Option button groups operate in a
container control, such as a frame. Therefore, different sets of option button groups
should be placed in their own frame on the form. If a group of option buttons is not
contained within a frame, then the form itself acts as their container.

In code, to perform an action based on which option button the user clicked, do one of
two things:

(1) To perform an action as soon as the user clicks an option button, place code in the
Click event of the option button.
(2) To perform a "delayed" action, such as when the user clicks a command button,
check the Value property of the option buttons in the group. If the Value = True, then
the button is "on".

Program 3.13: Setting the back color of a form using option buttons.

1. Create a new Project.


2. First, draw a frame and add three option buttons, named optRed, optGreen, and
optBlue respectively on the frame as shown in Figure3.15. Also add a command
button with caption “Change Color”.

48
Figure 3.15 Using option Buttons

3. If you want an immediate action write the following lines of code in the Click
event of each of the option buttons. The code causes the background color of the
form to change to the appropriate color when one of the option buttons is clicked:

Private Sub optRed_Click( )


Form1.BackColor = vbRed
End Sub

Private Sub optGreen_Click( )


Form1.BackColor = vbGreen
End Sub

Private Sub optBlue_Click( )


Form1.BackColor = vbBlue
End Sub

4. If the program was to be run at this point, you would get immediate results when
you clicked one of the option buttons as soon as you clicked one of the option
buttons, the form would change color.
5. To demonstrate the "delayed" action, delete the previously written code and add
the following lines of code in the click event of the command button:

Private Sub cmdChangeColor_Click()

If optRed.Value = True Then


Form1.BackColor = vbRed
ElseIf optGreen.Value = True Then
Form1.BackColor = vbGreen
Else
Form1.BackColor = vbBlue
End If

49
End Sub

6. If the program was to be run at this point, clicking on one of the option buttons
would not cause an immediate result it would simply set the Value of the clicked
button to True. Only when you clicked the "Change Color" button would the
background color of the form change, based on the code above.

50
CHAPTER 4

KEYBOARD AND MOUSE EVENTS


4.1 Mouse events

4.1.1 MouseDown, MouseMove and MouseUp Events

MouseDown is the most frequently used of the three mouse events. It can be used to
reposition controls on a form at run time or to create graphical effects, for instance. The
MouseDown event is triggered when a mouse button is pressed. The MouseUp event
occurs when the user releases the mouse button. The MouseMove event occurs when the
user moves the mouse.

The above mentioned three events takes the following 4 parameters as arguments: Button
As Integer, Shift As Integer, X As _ Single, Y As Single

The Button parameter tells us which mouse button went down. The predefined Visual
Basic Button parameter constants are:

• vbLeftButton = 1
• vbRightButton = 2
• vbMiddleButton = 4

Shift parameter is an integer that corresponds to the state of the SHIFT, CTRL, and ALT
keys when the button specified in the button argument is pressed or released. A bit is set
if the key is down. The shift argument is a bit field with the least-significant bits
corresponding to the SHIFT key (bit 0), the CTRL key (bit 1), and the ALT key (bit 2 ).
These bits correspond to the values 1, 2, and 4, respectively. The shift argument indicates
the state of these keys. For example, if both CTRL and ALT were pressed, the value of
shift would be 6.

X and Y specifies the current location of the mouse pointer.

Let’s work out some simple programs involving MouseDown events.

Program 4.1: Program that changes the position of a control on the form during the
MouseDown event.

1. Create a StandardEXE project file.


2. Add a command button to the form.
3. Enter following lines of code inside the MouseDown event of the Form object.

Private Sub Form_MouseDown (Button As Integer, _


Shift As Integer, X As Single, Y As Single)

51
Command1.Move X, Y

End Sub

4. Run the program and observe what happens when you click randomly on the
form.

Program 4.2: Drawing lines in the MouseDown event

1. Create a StandardEXE project file.


2. Enter following lines of code inside the MouseDown event of the Form object.

Private Sub Form_MouseDown (Button As Integer, _


Shift As Integer, X As Single, Y As Single)

Line -(X, Y)
End Sub

3. Run the program and click randomly on the form.

Program 4.3: Program to draw lines by clicking the mouse button and moving it and to
stop drawing the mouse button is released.

1. Create a StandardEXE project file.


2. To tell the application to turn drawing on and off, you must create a form-level
variable that represents the drawing state. Type the following statement in the
Declarations section of the form code module:

Dim DrawNow As Boolean

DrawNow will represent two values: True will mean "draw a line," and False will
mean "do not draw a line."

3. Set the DrawNow variable to TRUE in the MouseDown event when the user
clicks the mouse button. Also get the X and Y coordinates.

Private Sub Form_MouseDown (Button As Integer, Shift As Integer, _ X As Single, Y


As Single)
DrawNow = True
CurrentX = X
CurrentY = Y
End Sub

4. When the user releases the mouse button drawing must not be done. Hence set the
DrawNow variable to FALSE in the MouseUp event.

Private Sub Form_MouseUp (Button As Integer, Shift As Integer, _ X As Single, Y


As Single)
DrawNow = False

52
End Sub

5. The MouseMove procedure draws a line only if DrawNow is TRUE. Otherwise, it


takes no action:

Private Sub Form_MouseMove (Button As Integer, Shift As Integer, _ X As Single, Y


As Single)
If DrawNow Then Line -(X, Y)
End Sub

6. Run the application. Each time the user presses a mouse button, the MouseDown
event procedure is executed and turns drawing on. Then as the user holds the
Mouse button down, the MouseMove event procedure is executed repeatedly as
the pointer is dragged across the screen.

The next example demonstrates a simple paint application. The MouseDown event
procedure works with a related MouseMove event procedure to enable painting when any
mouse button is pressed and dragged. The MouseUp event procedure disables painting.

Program 4.4: Simple paint application.

1. Create a StandardEXE project file.


2. To tell the application to turn drawing on and off, you must create a form-level
variable that represents the drawing state. Type the following statement in the
Declarations section of the form code module:

Dim PaintNow As Boolean

PaintNow will represent two values: TRUE will mean "to paint," and FALSE
mean "not to paint".
3. Type the following lines of code in the form load event to specify the brush width
and color:

Private Sub Form_Load ( )

DrawWidth = 10 ' Use wider brush.


ForeColor = RGB(0, 0, 255) ' Set drawing color.

End Sub

4. Finally the include the following events and the corresponding logic:
Private Sub Form_MouseDown (Button As Integer, Shift As Integer, _ X As Single, Y
As Single)

PaintNow = True ' Enable painting.

End Sub

53
Private Sub Form_MouseUp (Button As Integer, Shift As Integer, _ X As Single, Y
As Single)

PaintNow = False ' Disable painting.

End Sub

Private Sub Form_MouseMove (Button As Integer, Shift As Integer, _ X As Single, Y


As Single)

If PaintNow Then
PSet (X, Y) ' Draw a point.
End If

End Sub

5. Press F5, click the form, and move the mouse while the mouse button is
pressed and observe the result.

4.2 The Key board events

4.2.1 KeyUp and KeyDown Events

The KeyDown and KeyUp events happen when the user respectively presses and releases
a key on the keyboard. Their event procedures take the following two parameters:
KeyCode and Shift.

KeyCode contains an integer code for the physical key that the user pressed. You can
check for a particular key by comparing KeyCode with one of the special VB internal
constants for physical key codes. Each constant name begins with the string "vbKey"
followed by an obvious name for the key (the letter of the key if it's an alphabetic key or
some other obvious name for other keys). Examples of vbKey constants would be
vbKeyA, vbKeyW, vbKeyF1, vbKeyPgUp, and so forth.

Shift parameter works in the same way as the Shift parameter for the MouseDown and
MouseUp event procedures.

Program 4.5: Detecting a shifted keystroke in the KeyDown event procedure of text box
control.

1. Open a new project and add the variable ShiftKey to the Declarations section of
the form:

Dim ShiftKey as Integer

2. Add a Textbox control to the form and this procedure in the KeyDown event:

Private Sub Text1_KeyDown(KeyCode As Integer, Shift As Integer)

54
ShiftKey = Shift And 7
Select Case ShiftKey
Case 1 ' or vbShiftMask
Print "You pressed the SHIFT key."
Case 2 ' or vbCtrlMask
Print "You pressed the CTRL key."
Case 4 ' or vbAltMask
Print "You pressed the ALT key."
Case 3
Print "You pressed both SHIFT and CTRL."
Case 5
Print "You pressed both SHIFT and ALT."
Case 6
Print "You pressed both CTRL and ALT."
Case 7
Print "You pressed SHIFT, CTRL, and ALT."
End Select

End Sub

3. Run the application and observe the results when you press the SHIFT, CTRL,
ALT and their combinations.

4.2.2 KeyPress Event

The KeyPress event happens after the KeyDown event but before the KeyUp event. It
detects the ASCII value of the character generated by the pressed key. The KeyPress
event procedure's single parameter is KeyAscii. KeyAscii is an integer representing the
ASCII value of the character generated by the user's key press.

For instance, if the user keys an uppercase "A," then the KeyPress event fires and the
KeyAscii parameter will have a value of 65 (since 65 is the ASCII code for uppercase
"A").
If you write code in the KeyPress event that changes the value of KeyAscii, then the
system will see the newly assigned character as the character that the user has just typed.
If you change the value of KeyAscii to 0, then the system will not see a keystroke, and
you have in effect discarded the keystroke.

In program4.6, all characters keyed in by the user are converted to lowercase in the
following steps:

Program 4.6: Changing the case of a character in the keypress( ) event procedure.

1. Open a new project.


2. Add a Textbox control named txtPassword to the form and add the following
lines of code in the KeyPress event:

55
Private Sub txtPassword_KeyPress(KeyAscii As Integer)

Dim KeyChar As String


KeyChar = LCase(KeyChar) 'change to lowercase

End Sub

3. Run the application and type some upper case character in the textbox and
observe the result.

Program4.7 uses a similar technique to allow the user to input only digits. The code
checks to see whether the user has keyed in a numeric character. If not, the code discards
the character by changing the value of KeyAscii to 0.

Program 4.7: Discarding selected keystrokes in the keypress( ) event procedure.

1. Open a new project.


2. Add a Textbox control named txtPassword to the form and add the following
lines of code in the KeyPress event:

Private Sub txtPassword_KeyPress(KeyAscii As Integer)


Dim KeyChar As String
If KeyAscii > 31 Then 'ignore low-ASCII characters like BACKSPACE
KeyChar = Chr(KeyAscii)
If Not IsNumeric(KeyChar) Then
KeyAscii = 0
End If
End If
End Sub

3. When you run the project you may find the KeyPress event getting fired only if
the key that is pressed generates an ASCII character. There are many keys on the
keyboard that do not generate ASCII characters including all of the function keys
and most of the cursor movement keys. To detect those key presses, you must use
the KeyUp and KeyDown events.

Program 4.8: Search wile you type in a combo box.

1. Open a new project.


2. Add a Combo box control named Combo1 to the form and add the following lines
of code in the general section of your code window:

Option Explicit

Private Const CB_FINDSTRING = &H14C

56
Private Const CB_SHOWDROPDOWN = &H14F
Private Const LB_FINDSTRING = &H18F
Private Const CB_ERR = (-1)

Private Declare Function SendMessage Lib "user32" Alias _


"SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, _
ByVal wParam As Long, lParam As Any) As Long

3. At the time of form load event fill up the combo box with items. To achieve this
add the following lines of code in the Form_Load( ) function:

Private Sub Form_Load()


Combo1.AddItem "DBMS"
Combo1.AddItem "Visual Programming"
Combo1.AddItem "Data Mining"
Combo1.AddItem "Algorithms"
Combo1.AddItem "Software Engineering"
Combo1.AddItem "Computer Networks"
End Sub

4. Add the following combo box logic into the GotFocus( ) and KeyPress( ) event of
the combo box respectively:

Private Sub Combo1_GotFocus()


SendMessage Combo1.hwnd, CB_SHOWDROPDOWN, 1, ByVal 0&
End Sub

Private Sub Combo1_KeyPress(KeyAscii As Integer)

Dim CB As Long
Dim FindString As String

If KeyAscii < 32 Or KeyAscii > 127 Then Exit Sub

If Combo1.SelLength = 0 Then
FindString = Combo1.Text & Chr$(KeyAscii)
Else
FindString = Left$(Combo1.Text, Combo1.SelStart) & Chr$(KeyAscii)
End If

SendMessage Combo1.hwnd, CB_SHOWDROPDOWN, 1, ByVal 0&

CB = SendMessage(Combo1.hwnd, CB_FINDSTRING, -1, ByVal _


FindString)

If CB <> CB_ERR Then

57
Combo1.ListIndex = CB
Combo1.SelStart = Len(FindString)
Combo1.SelLength = Len(Combo1.Text) - Combo1.SelStart
End If

KeyAscii = 0

End Sub

5. When you run the application and type any character in the combo box it will
display all matching items.

58
CHAPTER 5

WORKING WITH FILES & FILE ACCESS CONTROLS

5.1 File System Controls

VB provides three native toolbox controls for working with the file system: the
DriveListBox, DirListBox, and FileListBox. You can use these controls independently,
or in concert with one another to navigate the file system.

5.1.1 DriveListBox

The DriveListBox control is a specialized drop-down list that displays a list of all the
valid drives on the user's system. The most important property of the DriveListBox is the
Drive property, which is set when the user selects an entry from the drop-down list or
when you assign a drive string (such as "C:") to the Drive property in code. You can also
read the Drive property to see which drive has been selected.

To make a DirListBox display the directories of the currently selected drive, you would
set the Path property of the DirListBox control to the Drive property of the DriveListBox
control in the Change event of the DriveListBox, as in the following statement:

Dir1.Path = Drive1.Drive

5.1.2 DirListBox

The DirListBox control displays a hierarchical list of the user's disk directories and
subdirectories and automatically reacts to mouse clicks to allow the user to navigate
among them. To synchronize the path selected in the DirListBox with a FileListBox,
assign the Path property of the DirListBox to the Path property of the FileListBox in the
Change event of the DirListBox, as in the following statement:

File1.Path = Dir1.Path

5.1.3 FileListBox

The FileListBox control lists files in the directory specified by its Path property. You can
display all the files in the current directory, or you can use the Pattern property to show
only certain types of files.

Similar to the standard ListBox and ComboBox controls, you can reference the List,
ListCount, and ListIndex properties to access items in a DriveListBox, DirListBox, or
FileListBox control. In addition, the FileListBox has a MultiSelect property which may
be set to allow multiple file selection.

59
Program 5.1: A program to create a Text File Viewer using file system controls

5. Create a StandardEXE project file.

6. Design a form as shown in the Figure 5.1. Also set the names and property
settings for each control on the form, as well as for the form itself, as indicated in
the callouts in Figure 4.1:

Figure 5.1 Form Design

7. Set the following properties to the TextBox:

Properties Values Remarks

MultiLine True

60
ScrollBars 3 – Both meaning we will get both a Vertical and Horizontal
scroll bar on the textbox, as needed

Locked True prevents the user from entering data into the
textbox, but still allows them to scroll

Font Courier New which is a mono-spaced font, more suitable for


displaying plain-text files than the default MS Sans
Serif font, which is a proportional font

8. Enter the following statements in form general purpose area of the code window,
where mstrDrive is Form-level variable to indicate last valid drive selected:

Option Explicit
Private mstrDrive As String

9. Initialize the DriveListBox to point to the C drive and set the path of the
DirListBox to point to the root of C drive. This can be done using the following
code in the Form_Load( ) event:

Private Sub Form_Load( )


drvSelDrive.Drive = "C:"
mstrDrive = "C:"
dirSelDir.Path = "C:\"
End Sub

10. If the Drive change was OK, update the mstrDrive variable with the newly
selected drive. On the other hand an error might occur if you attempted to change
to a CD or floppy drive where the media was not ready and hence a warning
message may be given to the user. For achieve this enter the following lines of
code in the drvSelDrive_Change( ) event:

Private Sub drvSelDrive_Change( )


On Error Resume Next
dirSelDir.Path = drvSelDrive.Drive
If Err.Number <> 0 Then
MsgBox "Drive selected is unavailable", _
vbInformation, "Drive Unavailable"
drvSelDrive.Drive = mstrDrive
Else
mstrDrive = drvSelDrive.Drive
End If
End Sub

61
11. When the path of the DirListBox has changed, set the path of the FileListBox
to point to the new path of the DirListBox. This action alone will cause the
contents FileListBox to refresh. Test the ListCount property of the FileListBox to
see if there are any files in the current path. If there is at least one file in the
current path, then highlight (select) the first file by setting ListIndex to 0. This will
invoke the TextFileViewer_Click event. If there is no files in the current path
display this information to the user. Write the code given below to achieve the
above mentioned tasks in the dirSelDir_Change( ) event:

Private Sub dirSelDir_Change()


filTextFileViewer.Path = dirSelDir.Path
lblCurrentDir.Caption = dirSelDir.Path
If filTextFileViewer.ListCount > 0 Then
filTextFileViewer.ListIndex = 0
Else
lblSelectedFileName.Caption = "(None)"
txtFileContent.Text = " "
End If
End Sub

8. Code the click event of the DirListBox to force the dirSelDir_Change event (by
setting the Path property to the List property of the currently clicked item).
Without doing this, the change event would only occur when user DOUBLE-
CLICKS a new directory in the DirListBox. Invoking the Change on a single-click
seems more natural.

Private Sub dirSelDir_Click()


With dirSelDir
.Path = .List(.ListIndex)
End With
End Sub

9. Now code the final and overall logic to file display.

Private Sub filTextFileViewer_Click( )

Dim strFileExt As String


Dim strCurrFile As String
Dim strFileContent As String
Dim intFreeFile As Integer
Dim lngFileLen As Long
Dim lngX As Long
Dim blnIsTextFile As Boolean
' If no files are selected from the FileListBox, then get out because there's nothing to do ...
If filTextFileViewer.ListIndex = -1 Then Exit Sub

62
' Form a fully-qualified file name by concatenating the Path property of the FileListBox with the
' text of the currently selected entry (which is the filename). If the path already has a backslash at
' the end of it (as it would for a root directory), fine, otherwise add a backslash to the end of it
' before concatenating it with the filename...
With filTextFileViewer
strCurrFile = IIf(Right$(.Path, 1) = "\", .Path, .Path & "\") _
& .List(.ListIndex)
End With

' Update the label caption to reflect the new filename ...
lblSelectedFileName.Caption = strCurrFile

' Use the FileLen function to get the length of the current file ...
lngFileLen = FileLen(strCurrFile)

' Test the file length ...


If lngFileLen >= 65536 Then

' Too big for the textbox, so just display the message ...
txtFileContent.Text = "Selected file is too large to be displayed"

Else
' Read the entire contents of the file into a string variable ("strFileContent") ...
intFreeFile = FreeFile
Open strCurrFile For Binary Access Read As #intFreeFile
strFileContent = Input(LOF(intFreeFile), intFreeFile)
Close #intFreeFile
' Loop thru the file content byte-by-byte to test for characters that would "disqualify" the file from
' being regarded as a "plain-text" file. For our purposes, the ASCII characters 0 thru 8, 11 thru 12,
' and 14 thru 31 would disqualify the file.
blnIsTextFile = True
For lngX = 1 To lngFileLen
Select Case Asc(Mid$(strFileContent, lngX, 1))
Case 0 To 8, 11 To 12, 14 To 31
blnIsTextFile = False
Exit For
End Select
Next
' Done with the loop, so test the result ...
If blnIsTextFile Then

' All characters were valid, so assign the contents of the file to the Text property
' of the textbox ...
txtFileContent.Text = strFileContent

Else

63
' We encountered a disqualifying character, so dispaly a message rather
' than the contents of the file ...
txtFileContent.Text = "Selected file is not a plain text _
file.”
End If
End If
End Sub

10. Run the application and observe the results by selecting different file.

5.2 Working with files

There are three main ways to access files in Visual Basic: as sequential files, as random
access files, and as binary files.

5.2.1 Sequential Access Files

Sequential files are like tape cassettes—you read data from them in a sequential manner.
Here are the Visual Basic statements and functions you use with sequential files (the #
symbol refers to an open file):

• Open
• Line Input #
• Print #
• Write #
• Input$
• Input #
• Close

In addition, Visual Basic supports TextStream objects to make working with sequential
files easier, as we’ll see later in this chapter. Here are the major TextStream methods:

• Read
• ReadAll
• ReadLine
• Write
• WriteBlankLines
• WriteLine
• Close
When do you use sequential files? If you’ve got a text file full of variable-length strings,
you usually treat that file as sequential. You can also use sequential files to store binary-
format items like numbers.

5.2.2 Random Access Files

If sequential files are like cassettes, random access files are more like CDs. Random files
are organized into records (usually of the same length), and you can read a particular

64
record without having to read all the intervening data—you can move to that record in a
file directly, just as you can move to a CD track.
Here are the Visual Basic statements and functions you use with random access files:

• Type…End Type (to create and format records)


• Open
• Put #
• Len
• Seek
• LOC
• Get #
• Close

When do you use random access files? If you want to create your own database files,
formatted as you want them, you’d organize them into records. In fact, any file that you
want to organize into records is best formatted as a random access file.

5.2.3 Binary Files

Binary files are simply unformatted binary data, and Visual Basic does not interpret (such
as looking for text strings) or organize the contents (into records) of such files at all.
These files are just bytes to Visual Basic, and the statements and functions you usually
use with these files include the following:

• Open
• Get
• Put
• Seek
• Close

Binary files include EXE files, graphics files, and so on.

5.2.4 The FileSystemObject

Besides the preceding file types, Visual Basic includes the FileSystemObject for easy file
manipulation on disk. This object includes a number of methods for copying, moving,
and deleting files such as these:

• GetFile
• CopyFile
• DeleteFile
• MoveFile
• FileExists
• CreateFolder
• CreateTextFile
• OpenTextFile

65
Now let’s see an example. Here, we’ll let users write the text in a text box, to a file on
disk, file.txt, when you press a button. Because file operations are prone to error (we
might run into missing diskettes, locked files, and so on), we start by checking for errors.
Next, we create file.txt as file #1. Then write the text in to the file with the Print #
method and finally we close the file.

Program 5.2: Writing contents in a text box to a file.

1. Create a new StandardEXE project.


2. Add a text box to it and a command button.
3. Double click on the command button with a caption “Write to File” and add the
code below to its click event handler.

Private Sub Command1_Click()


On Error GoTo FileError
Open "c:\file.txt" For Output As #1
Print #1, Text1.Text
Close #1
MsgBox "The file is" & Str(FileLen("c:\file.txt")) & " bytes long."
Exit Sub

FileError:
MsgBox "File Error!"

End Sub

4. Run the application and you’ll find the file size in bytes displayed in a
message box.

Program 5.3: Save the contents of a list box to a file.

The source sample below adds some data to a list box. Then open a file, add all the items
from the list into the file and then save the file.

1. Create a new StandardEXE project.


2. Add a list box to it and a command button.
3. Double click on the command button with a caption “Press Me to add items”
and add the code below to its click event handler.

Private Sub Command1_Click( )


Dim I As Integer
List1.AddItem "Apple"
List1.AddItem "Banana"
List1.AddItem "Fig"
List1.AddItem "Orange"
Open "C:\list.txt" For Append As #1

66
For I = 0 To List1.ListCount - 1
Print #1, List1.List(I)
Next
Close #1
End Sub

4. When you run the application you’ll find an empty list box and the command
button. When you click the command button the fruit names will be added into
the list box and the same will be appended into a file named list.txt in the C drive.
The number of times you click the command button that many times the fruits
names will be appended into the list.txt file.

The following program demonstrates some of VB's File IO operations such as Open, Get,
and Put. The way it does this is by pulling the whole file into memory and then writing it
back out to the second file name. It also demonstrates how you can declare a variable
array and then change its size using the ReDim construct.

Program 5.4: Copy one file into another.

1. Create a new StandardEXE project.


2. Add a button to the form, double click the button to get into its click event handler
method, and add the following code within that method.

Private Sub Command1_Click( )

Dim mByte() As Byte


Open "C:\Command.com" For Binary As #1
Open "C:\Backup.com" For Binary As #2
ReDim mByte(0 To LOF(1))
Get #1, , mByte()
Put #2, , mByte()
Close #1
Close #2
MsgBox "Done", vbInformation

End Sub

3. After running this program and clicking the button you should see a copy of the
command.com file created on the C drive with a name of Backup.com.

The next program allows you to loop through every item in a set. This code sample
demonstrates how to interact with the File system. Specifically we see how to loop
through all the files in a given folder.

67
Program 5.5: Looping through files and putting them in a control.

1. Create a new StandardEXE project.


2. Drag a button onto the form. Double click the button. This will take you to the
buttons click event handler method. Inside this method add the following code.

Private Sub Command1_Click( )

Dim TPath As String


Dim Filename As String

TPath = "C:\Windows\"
Filename = Dir(TPath)

Do While Filename <> ""


Filename = Dir
List1.AddItem TPath & Filename
Loop

End Sub

3. Run the application, click the button, and check it out.

Now let’s try out a program involving FileSystemObject. This program displays the
drives available in your system and also indicates the free space available in the selected
drive.

Program 5.6: Working with FileSystemObject.

1. Create a new StandardEXE project.


2. Design the form as shown in Figure 5.2.

Figure5.2 Form Design

68
3. The form has the following controls:

Object Control Name Property Value


Label Label1 Caption System Drives:
Lable Label2 Caption Click a Drive in the list above to find
out how much disk space is free:
Label Label 2 Border Style 1 – Fixed Single
ListBox List1

4. Write following lines of code in the form_load event:

Private Sub Form_Load( )


Dim fso As New FileSystemObject
Dim dr As Drive
Dim drs As Drives
Dim s As String
Dim n As String

Set drs = fso.Drives


Form1.MousePointer = vbHourglass
Show

DoEvents

Form1.Caption = "Search Environment"


For Each dr In drs
Form1.Caption = Form1.Caption & ".."
s = dr.DriveLetter & " - "
If dr.DriveType = 3 Then
n = dr.ShareName
ElseIf dr.IsReady Then
n = dr.VolumeName
End If
List1.AddItem s & n
Next
Form1.MousePointer = vbDefault
Form1.Caption = "Search Complete"
End Sub

5. Now include the below lines of code in the click event of the list box:

Private Sub List1_Click( )


Dim strDrive As String
Dim fso As New FileSystemObject
Dim dr As Drive
Dim strAvail As String

69
'Get the drive letter from the list box
strDrive = Left(List1.List(List1.ListIndex), 1) & ":"

'Get a drive object using the GetDrive method of the FileSystemObject


Set dr = fso.GetDrive(strDrive)

'If the drive is ready


If dr.IsReady Then
'Make a string that reports how many kilo bytes are free on the disk
strAvail = Format(CStr(dr.AvailableSpace _
/ 1024), "###,###")
If strAvail = "" Then strAvail = "0"
Label3.Caption = strAvail & " Kbytes"
Else
'If the drive is not ready, the send a message
MsgBox "Drive not ready", vbCritical, "Drive Error"
End If
End Sub

6. Run the application and check the free spaces in the drives in your system.

70
CHAPTER 6

DATABASE CONNECTIVITY
6.1 Introduction

6.1.1. Database Access with the Data Control

Data Controls provides access to data stored in databases using any one of three types of
the following Recordset objects:

i) Table
ii) Dynaset
iii) Snapshot

The Data control enables you to move from record to record and to display and
manipulate data from the records in bound controls. Without a Data control or an
equivalent data source control like the RemoteData control, data-aware (bound) controls
on a form can't automatically access data.

You can perform most data access operations using the Data control without writing any
code at all. Data-aware controls bound to a Data control automatically display data from
one or more fields for the current record or, in some cases, for a set of records on either
side of the current record. The Data control performs all operations on the current record.

If the Data control is instructed to move to a different record, all bound controls
automatically pass any changes to the Data control to be saved in the database. The Data
control then moves to the requested record and passes back data from the current record
to the bound controls where it's displayed.

6.1.2 Bound Controls

The DataList, DataCombo, DataGrid, and MSHFlexGrid controls are all capable of
managing sets of records when bound to a Data control. All of these controls permit
several records to be displayed or manipulated at once.

The intrinsic Picture, Label, TextBox, CheckBox, Image, OLE, ListBox and ComboBox
controls are also data-aware and can be bound to a single field of a Recordset managed
by the Data control.

The intrinsic Data control is geared toward MS-Access 97 and earlier databases, although
a later VB service pack added connectivity for Access 2000 databases. The programs
discussed in this chapter use the two sample Access databases provided with Visual Basic
(BIBLIO.MDB and NWIND.MDB). These databases are provided in Access 97 format.

71
On a default installation of VB6, these databases can be found in the folder: C:\Program
Files\Microsoft Visual Studio\VB98.

To do these exercises, you should make a folder into which you will copy the two
database files mentioned above. Then, within the folder you have created, make separate
subfolder for each exercise, one level below the root of your folder. The DatabaseName
property for the Data control in these exercises assumes that the database file resides one
directory level above the folder in which the exercise project files reside.

Program 6.1: Connecting and updating records to an Access Database Using the VB
Data Control.

1. Open a new Visual Basic project.

2. Put a data control (an intrinsic control, located in the VB toolbox) on the form and set
the properties as follows:

Property Value
(Name) datAuthors
Caption Use the arrows to view the data
Connect Access (default)
DatabaseName ..\biblio.mdb
DefaultType UseJet (default)
RecordSource Authors (choose from list)

Notes: When you use the Data Control in a project, the properties that must be set
are DatabaseName and RecordSource, in that order. DatabaseName is the
name of the database you want to use, and the RecordSource is the name of the
table in that database that you want to use.

3. On your form, create a text box for each field in the Authors table, with labels. (If you
were to open the database in Access, you would see that the three fields of the
Authors table are Au_ID, Author, and Year Born.) Set the properties of the three
textboxes as follows:

Name DataSource DataField


txtAuthID datAuthors Au_ID
txtAuthor datAuthors Author
txtYearBorn datAuthors Year Born

In addition, set the Enabled property of txtAuthID to False.

When you want a control (such as a text box) to display data from a database, the
properties that must be set are DataSource and Datafield. The DataSource is the
name of the data control on the form (it should already be configured), and the
DataField is the name of the particular field in the database that should be displayed

72
in the control (this field will be in the table that was chosen for the RecordSource of
the data control).

At this point, your form should resemble the screen-shot shown in Figure 6.1.

Figure 6.1 Using Data Control

4. Save and run the project. Use the arrows on the data control to scroll through the
data.

5. On any record, change the data in the author name or year born field. Move ahead,
then move back to the record you changed. Note that your changes remain in
effect. The data control automatically updates a record when you move off of the
record.

Note: EOF (End Of File) is a Boolean property of the recordset object that becomes true
when an attempt is made to move forward past the last record in a recordset.

BOF (Beginning Of File) is a Boolean property of the recordset object that


becomes true when an attempt is made to move backward past the first record in a
recordset.

6. Click once on the data control and make sure that the following properties are set:

BOFAction = 0 - Move First


EOFAction = 0 - Move Last

7. Run the program and notice what happens when you use the arrows to move
previous when you are on the first record already, or move next when you are
already on the last record.

8. End the program, and set the data control properties as follows:

73
BOFAction = 1 - BOF
EOFAction = 1 - EOF

9. Notice what happens to the arrows on the data control when you try to move past
the last or first record.

10. Now set the EOFAction property to 2 - AddNew.

11. Run the program; click the >| arrow on the data control to move to the end of the
records; then click on the > arrow to move to the next record (which does not
exist).

12. A blank record should appear. Type some data in all the fields (the author ID will
be entered automatically), then move to a previous record. Move back to the last
record to verify that your data is still there.

13. End the program, then start it again. Verify that the data you entered is still in the
database.

The above program demonstrated that you can create a simple but functional application
that not only allows the user to browse through the rows of a database table and to update
rows in that table, but also allows the user to add a new record to that table without
writing any code.

In the previous program, you saw that by clicking specific buttons of the data control,
you could move to the first, previous, next, or last record. What is happening is that the
data control is automatically invoking specific methods of the recordset object: namely
the MoveFirst, MovePrevious, MoveNext, and MoveLast methods. You can also
invoke these methods through code, which is what program6.2 demonstrates.

Program 6.2: Using Navigation Buttons with a Data Control.

1. Copy the files from Program6.1 into a new folder and open the VBP file in the
new folder.

2. Set the Visible property of the data control (datAuthors) to False.

3. Make four command buttons with the following properties:

Name Caption
cmdMoveNext Next Record
cmdMoveLast Last Record
cmdMovePrevious Previous Record
cmdMoveFirst First Record

74
At this point, your form should resemble the Figure6.2:

Figure 6.2 Using Button controls to navigate

4. Put the following four lines of code in the appropriate Click events for the buttons:

Event Code
cmdMoveNext_Click datAuthors.Recordset.MoveNext
cmdMoveLast_Click datAuthors.Recordset.MoveLast
cmdMovePrevious_Click datAuthors.Recordset.MovePrevious
cmdMoveFirst_Click datAuthors.Recordset.MoveFirst

5. Save and run your program.

6. Move to the last record and then click the Move Next button twice. What happens?

7. When the user clicks on the MoveNext button, and there is no next record, your
code should stay on the same record (the last one). Put the following code in the
cmdMoveNext_Click() event:

datAuthors.Recordset.MoveNext
If datAuthors.Recordset.EOF = True Then
datAuthors.Recordset.MoveLast
End If

Note: Instead of Recordset.MoveLast, you could use MoveFirst to let the user loop
around to the first record.

7. Put similar code in the cmdMovePrevious_Click() event. In this case, you will be
checking for Recordset.BOF = True.

75
4. Save and run the project and test it thoroughly.

In program 6.2, you saw that with the data control, changes to a record are automatically
updated when the user moves off of that record which is done by the Update method of
the recordset object of the data control. You also saw that, by setting the EOFAction of
the data control to "2 - AddNew", the data control will invoke the AddNew method of
the recordset object, which causes all the bound controls to be cleared so that the user can
enter data. In addition to being invoked automatically through the data control, the
Update and AddNew methods can also be invoked through code. The recordset object
also has a Delete method, which can only be invoked through code, but it cannot be
accessed automatically through the data control.

Now lets see how to invoke the Update, AddNew, and Delete methods of the recordset
object through code.

Program 6.3: Update, Add and Delete records of the recordset object through code.

1. Add three more buttons to the form designed in program6.2 and set their properties
as follows:

Name Caption Enabled


cmdNewRecord New Record True
cmdSaveRecord Save Record False
cmdDeleteRecord Delete Record True

Your form should resemble the Figure 6.3:

Figure 6.3 Updating DB through Code

76
2. When the user clicks on New Record, your program should enable the Save Data
button and disable the others. Put the following code in the
cmdNewRecord_Click( ) event:

datAuthors.Recordset.AddNew
cmdSaveRecord.Enabled = True
cmdMoveFirst.Enabled = False
cmdMoveLast.Enabled = False
cmdMovePrevious.Enabled = False
cmdMoveNext.Enabled = False
cmdDeleteRecord.Enabled = False
cmdNewRecord.Enabled = False

3. Save and run the program to make sure the buttons are enabled and disabled
correctly.

4. When the user clicks on the Save button to save the data that was entered, the
Update method should be called and the buttons should be redisplayed. Place the
following code in the cmdSaveRecord_Click() event:

datAuthors.Recordset.Update
cmdSaveRecord.Enabled = False
cmdMoveFirst.Enabled = True
cmdMoveLast.Enabled = True
cmdMovePrevious.Enabled = True
cmdMoveNext.Enabled = True
cmdDeleteRecord.Enabled = True
cmdNewRecord.Enabled = True

5. Something to watch out for with the Delete method is that when a record is
deleted, the recordset is no longer pointing to a valid record, but the data from the
deleted record still remains in the controls. If the user attempted to update the
record at that point, a run-time error would occur. To prevent this from
happening, you should move the user to a valid record immediately following the
delete.

Another issue is that if you attempt to delete a record that has a related record in
another table, the Jet (Access) database engine will not allow the delete, and a
run-time error will occur. If you don't trap the error, the program will crash.

Finally, it is good programming practice to ask the user to confirm any destructive
action.

Place the following code, which addresses the above-mentioned issues, in the
cmdDelete_Click( ) event:

77
On Error GoTo Delete_Error

If MsgBox("Are you sure you want to delete this record?", _


vbQuestion + vbYesNo + vbDefaultButton2, "Confirm") = vbNo Then
Exit Sub
End If

'delete the current record


datAuthors.Recordset.Delete

'move to a valid record


cmdMoveNext_Click
Exit Sub

Delete_Error:

' This error will occur if you attempt to delete an author that is related to
' another table in the biblio.mdb database ...
MsgBox "This record cannot be deleted. Error code = " & Err.Number _
& vbCrLf & Err.Description, vbCritical, "Cannot Delete"

6. Save and test your program to make sure all functions work.

So far we were working with control that allows the user to work with records one by
one. But Visual Basic offers special data bound controls called grid controls to work with
multiple records.

6.2 Using Grid Controls

6.2.1 Using the MSFlexGrid Control

The Microsoft FlexGrid (MSFlexGrid) can be used to display multiple records in a grid.
This control displays and operates on tabular data. It allows complete flexibility to sort,
merge, and format tables containing strings and pictures. When bound to a Data control,
MSFlexGrid displays read-only data.

You can put text, a picture, or both, in any cell of an MSFlexGrid. The Row and Col
properties specify the current cell in an MSFlexGrid. You can specify the current cell in
code, or the user can change it at run time using the mouse or the arrow keys. The Text
property references the contents of the current cell.

If the text in a cell is too long to display in the cell, and the WordWrap property is set to
True, the text wraps to the next line within the same cell. To display the wrapped text,
you may need to increase the cell’s column width (ColWidth property) or row height
(RowHeight property).

78
Use the Col and Row properties to determine the number of columns and rows in an
MSFlexGrid.

Note: Before you can use an MSFlexGrid in your application, you must add the
MSFlxGrd.ocx file to your project. To automatically include the file in your project, put
it in the Autoload file. When distributing your application, you should install the
MSFlxGrd.ocx file in the user’s Microsoft Windows System directory.

Program 6.4: Using MSFlexGrid control.

1. Create a new project.

2. Place two data controls on the form and set their properties as follows:

Name DatabaseName RecordSource Visible


datCategories ..\NWIND.MDB Categories True
datProducts ..\NWIND.MDB (leave blank) False

3. Set the Caption property of datCategories to "Use Arrow Buttons to Navigate


Records".

4. Place three textboxes and one OLE control on the form. Set the DataSource
property for each of these four controls to datCategories.

Set the DataField property for these controls to CategoryID, CategoryName,


Description, and Picture respectively.

Set the Enabled property of the Category ID textbox to False. For the
Description text box, set its MultiLine property to True and set its ScrollBars
property to 2 - Vertical.

Add appropriate label controls to accompany the textboxes, and group these four
controls into a frame, as shown in Figure 6.4.

5. If necessary, add the MSFlexGrid to your toolbox from the Components item of
the Project menu. Place an MSFlexGrid control on your form, and set its
properties as follows:

Property Value
AllowUserResizing 1 - flexResizeColumns
DataSource datProducts
FixedCols 0

Enclose the grid in a frame, as shown in Figure 6.4.

79
Figure 6.4 Using MSFlexGrid Control

6. Place the following line of code in the Form_Load event:

datCategories.Refresh

This will force the controls bound to datCategories to be populated sooner than
they would otherwise, and will also trigger the Reposition event of the
datCategories control. (The Reposition event of a data control occurs whenever a
Move method is executed against that control.)

7. Place the following code in the datCategories_Reposition event:

datProducts.RecordSource = "SELECT * FROM Products " _


& "WHERE CategoryID = " & txtCatID
datProducts.Refresh

8. Save and run the program.

As we have discussed earlier MSFlexGrid does not allow us to add, update or delete
records. Now let’s discuss about another control named DBGrid which allows the user to
add, update, and delete records.

80
6.2.2 DBGrid Control

The DBGrid control does not install automatically when you install Visual Basic 6.0, but
it is available on the VB 6/VS 6 CD. To install the DBGrid control, perform the
following steps:

1. Locate these three files on your VB6 installation CD: DBGRID32.OCX,


DBGRID32.DEP, and DBGRID.REG. All three files should be located in this
folder: D:\COMMON\TOOLS\VB\CONTROLS (where "D:" is the drive letter
of your CD-ROM drive). If you cannot locate your installation CD, you may
download these three files from WWW.
2. Copy these three files to your Windows "System" directory (the default system
directory varies depending on the OS being used: On Windows 2000 and NT the
default is WINNT\SYSTEM32; on XP the default is WINDOWS\SYSTEM32,
and on 95, 98, and ME it is WINDOWS\SYSTEM).
3. Double-click on DBGRID.REG to register the DBGRID32.OCX. You should
now see the control (under the name "Microsoft Data Bound Grid Control 5.0
(SP3)") when you access the Components dialog by selecting
ProjectComponents within VB. (If not, click on the Browse button in the
Components dialog and locate the DBGRID32.OCX file by browsing to the folder
in which you copied it previously.)

Program 6.5: Using the DBGrid Control.

1. Copy your files from Program6.4 to a new folder and open the project.
2. Delete the MSFlexGrid control.
3. From the menu Project  Components, include the Microsoft Data Bound
Grid Control. Now the DBGrid will be available in your control box.
4. Place a DBGrid on your form in the position previously occupied by the flex
grid.
5. Set the DBGrid's properties as follows:

Property Value
AllowAddNew True
AllowDelete True
AllowUpdate True
DataSource datProducts

6. The code can remain as is. Save and run the program; experiment by using the
grid to add, update, and delete records. You'll find that built-in error-checking will
prevent most "illegal" actions attempted by the user (such as trying to change the
primary key, changing a foreign key to a non-existent value, or deleting a record
with a related record in another table).

81
PART II - VISUAL C++

CHAPTER 1

BASIC WINDOW CREATION

1.1 Creating a Win32 Program

All Win32 programs primarily look the same and behave the same but, just like C++
programs, there are small differences in terms of creating a program, depending on the
compiler you are using. The programs mentioned in this manual may be tested using
Microsoft Visual C++ 6.

For a basic Win32 program, the contents of a Win32 program is the same. You will feel a
difference only when you start adding some objects called resources.

There are three types of programming in VC++:


1. SDK programming
2. MFC based programming
3. Programming using Application Wizard

Let’s start with the first type of programming and see how a simple window can be
created and hence learn the steps involved.

Program 1.1: Creating a simple window Using Microsoft Visual C++

1. Start the Microsoft Development Environment by clicking Start Programs


Microsoft Visual Studio 6.0 Microsoft Visual C++.
2. On the main menu, click File -> New... or File -> New -> Project...
3. In the New or New Project dialog box as shown in Figure1.1, click Win32
Application.
4. In the location, type the path where the application should be stored, such as
“C:\Programs\MSVC”
5. In the Name edit box, type the name of the application as Win32A and click OK.
6. In the next dialog box of the wizard (Figure1.2), click the An Empty Project
radio button.
7. Click Finish. You will be presented with another dialog box; in this case click OK
.
8. To create the first needed file of the program, on the main menu (refer Figure1.3),
click File -> New.
9. Click either C++ Source File or C++ File (.cpp)
10. In the Name edit box, replace the contents with a name for a file. In the case,
replace it with Main and press Enter.

82
Figure 1.1 New Project Dialog Window

Figure 1.2 Step1 of 1 during Win32Application creation

83
Figure 1.3 Creating a new C++ Source file

11. Enter the following lines of code in the code window area:
#include "windows.h"

LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);

TCHAR szAppName[] = TEXT("SDI Frame");


TCHAR szWinClass[] = TEXT("WIN_CLASS");

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


PSTR lpCmdLine, int nCmdShow)
{
MSG msg; // a struct used in the passing of messages
WNDCLASS wc; // a window class struct, see below
HWND hwnd; // a handle-to-a-window, see below

wc.cbClsExtra = 0; // specify how many bytes extra space is required for


// every window derived from this window class
wc.cbWndExtra= 0; // specify how many bytes extra space is required for this
// window
wc.hbrBackground= (HBRUSH) GetStockObject(WHITE_BRUSH);
// background colour
wc.hCursor= LoadCursor(NULL, IDC_ARROW);
// cursor, this is usually the default
wc.hIcon= LoadIcon(NULL, IDI_APPLICATION);
// icon, this can be changed using resources
wc.hInstance= hInstance;

84
// the current instance of the program is passed to the
// instance of the class
wc.lpfnWndProc= WinProc;
// the window procedure used by this class, usually
// has a more distinguishing name
wc.lpszClassName= szWinClass;
// the name of this class
wc.lpszMenuName= NULL;
// the name of the menu to be attached to the window
wc.style= CS_HREDRAW | CS_VREDRAW;
// these 'class styles' mean that the window will be
//redrawn whenever it is resized vertically or horizontally

if( !RegisterClass(&wc)) // register the class, and test if it fails


{
MessageBox(NULL, TEXT("Error registering class"), TEXT("ERROR"),
MB_OK);
return 0;
}

hwnd = CreateWindow(szWinClass,
// the class as specified in the one we just registered
szAppName,
// the title of the window
WS_OVERLAPPEDWINDOW,
// the window style (there are usually a lot more of these
CW_USEDEFAULT,
// the left co-ord of the window
CW_USEDEFAULT,
// the top co-ord of the window
CW_USEDEFAULT,
// the width of the window
CW_USEDEFAULT,
// the height of the window
(HWND) NULL,
// a handle to the parent window
(HMENU) NULL,
// a handle to the window's menu
(HINSTANCE) hInstance,
// the instance of the window
(void *) NULL); // any extra information

// WM_CREATE message has been sent to the window

ShowWindow(hwnd, nCmdShow);
// shows the window, using the specified command
// (Maximised, Minimised, etc)
UpdateWindow(hwnd);
// the window is updated (a WM_PAINT message is sent
// to the window
while (GetMessage(&msg, (HWND) NULL, 0, 0))
// while there is a message to retrieve, and that message
// is not WM_QUIT
{
TranslateMessage(&msg); // some messages need translating
DispatchMessage(&msg); // send the message to the window

85
}

return msg.wParam; // return the message struct's wParam


}

LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam,


LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;

switch(msg)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;

case WM_DESTROY:
PostQuitMessage(0);
break;
}

/* takes care of all of the messages that we didn't catch


in our Window Procedure */

return DefWindowProc(hwnd, msg, wParam, lParam);


}

12. To execute the program first you must compile the program by pressing Ctrl + F7.
13. Then build the EXE by pressing F7.
14. Finally when you execute the EXE by pressing Ctrl + F5, you can see an output as
given in Figure1.4:

Figure 1.4 Output Window for Program 1.1

86
15. To close the window, click its system Close button and return to your
programming environment.

1.2 Display of a window

Once a window has been created and if this was done successfully, you can display it to
the user. This is done by calling the ShowWindow function. Its syntax is:

BOOL ShowWindow(HWND hWnd, int nCmdShow);

The hWnd argument is a handle to the window that you want to display. It could be the
window returned by the CreateWindow or the CreateWindowEx function.

The nCmdShow specifies how the window must be displayed. Its possible values are:

SW_SHOW Displays a window and makes it visible


SW_SHOWNORMAL Displays the window in its regular size. In most
circumstances, the operating system keeps track of the last
location and size a window such as Internet Explorer or My
Computer had the last time it was displaying. This value
allows the OS to restore it.
SW_SHOWMINIMIZED Opens the window in its minimized state, representing it as
a button on the taskbar
SW_SHOWMAXIMIZED Opens the window in its maximized state
SW_SHOWMINNOACTIVE Opens the window but displays only its icon. It does not
make it active
SW_SHOWNA As previous
SW_SHOWNOACTIVATE Retrieves the window's previous size and location and
displays it accordingly
SW_HIDE Used to hide a window
SW_MINIMIZE Shrinks the window and reduces it to a button on the
taskbar
SW_MAXIMIZE Maximizes the window to occupy the whole screen
area
SW_RESTORE If the window was minimized or maximized, it would be
restored to its previous location and size

Program 1.2: Creating a window and to change the display of window using
ShowWindow method.

1. In program1.1 change the ShowWindow method’s second parameter to


SW_SHOWNORMAL
2. Test the program with the above mentioned nCmdShow values.

87
Program 1.3: Creating a window and working the size of the window.

1. In program1.1 change the CreateWindow method using the following code:

hwnd = CreateWindow(szWinClass,
// the class as specified in the one we just registered
szAppName, // the title of the window
WS_OVERLAPPEDWINDOW,
// the window style
100, // the left co-ord of the window
100, // the top co-ord of the window
350, // the width of the window
250, // the height of the window
(HWND) NULL,
// a handle to the parent window
(HMENU) NULL,
// a handle to the window's menu
(HINSTANCE) hInstance,
// the instance of the window
(void *) NULL); // any extra information

2. Test the program with different window co-ordinates and sizes.

Program 1.4: Creating window with thick border.

1. In program1.1 change the Window Style (WS_OVERLAPPEDWINDOW )


parameter in the CreateWindow method using the following code:

hwnd = CreateWindow(szWinClass,
// the class as specified in the one we just registered
szAppName, // the title of the window
WS_VISIBLE | WS_SYSMENU | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX | WS_THICKFRAME, // the window style
100, // the left co-ord of the window
100, // the top co-ord of the window
350, // the width of the window
250, // the height of the window
(HWND) NULL,
// a handle to the parent window
(HMENU) NULL,
// a handle to the window's menu
(HINSTANCE) hInstance,
// the instance of the window
(void *) NULL); // any extra information

2. Test the program to find the window shown in Figure1.5 as an output. You can
find a system menu when you click the mouse on the top left hand corner of the
window.

88
Figure 1.5 Output window for Program 1.4

3. Also try out with the following style parameters in the CreateWindow method:

WS_BORDER
WS_BORDER | WS_CAPTION | WS_SYSMENU
WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX

Program 1.5: Creating a simple window and interact with it.

1. Follow steps 1 to 10 given in program1.1


2. Type the following code in the code window:

#include<windows.h>
long _stdcall func(HWND,UINT,UINT,long);WNDCLASS a;

int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)


{
HWND h;
MSG m;

a.hInstance=i; //instance handle


a.lpszClassName="Sample"; //long pointer to class name
a.lpfnWndProc=func; //long pointer to Window procedure
a.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
//set background color of Window Client area
RegisterClass(&a); // Register the Window Class before use

h=CreateWindow("Sample Application","Title",WS_OVERLAPPEDWINDOW,20,20,300,
200,0,0,i,0); // Create Window Application
ShowWindow(h,3);

89
while(GetMessage(&m,0,0,0)) // extracts message from Message Queue
DispatchMessage(&m); // dispatches the message received
return 0;
}

long _stdcall func(HWND w,UINT x,UINT y,long z)


{
switch(x)
{
case WM_DESTROY:
PostQuitMessage(0); // used to terminate while loop in WinMain()
break;

case WM_LBUTTONDOWN:
MessageBox(0,"Press me","Title",0); //pops up message box
break;
default:

return DefWindowProc(w,x,y,z);
}
return 0L;
}

3. Execute the program to find the output shown in Figure1.6 with a message box.

Figure 1.6 Output for Program 1.5

90
1.3 MFC based Programming

The Microsoft Foundation Class Library(MFC Library) is a C++ class library released
with Microsoft Visual C++ to support application development on Microsoft
Windows. Although MFC is most often used in GUI applications, it can be used to
develop any type of application. The MFC Library consists of numerous classes that are
thin wrappers for high level Application Programming Interfaces(APIs) such as
WinSock and ODBC. All the Win32 Kernel, GDI, and User Objects have associated
MFC classes.

If you do use MFC, your applications will not have to be modified much when moving
between different platforms. For instance, many MFC applications written for Windows
3.1(Win16) were simply recompiled for Win32 platforms such Windows 95 and
NT. When Win64 comes out, you do not have to rewrite your whole MFC again. If
MFC was used to develop a simple windows application with standard UI elements, it
would probable take hours to develop.

All the MFC Classes have a capital C prefix. For instance, CString, CFile, CSocket,
CMutex are classes found in the MFC library. The standard MFC classes are declared in
the header file afxwin.h. If you do not use the App Wizard, you will have to turn on
the MFC by modifying the project settings in Visual C++ to either static or dynamic
MFC linking.

Program 1.6: Create Window of your own class (MFC).

1. Follow steps 1 to 10 given in program 1.1.


2. This is very important if you go for MFC based programming. In the main menu
bar go to Project Settings…

Figure 1.7 Project Settings Dialog Window

91
3. The project settings dialog window as shown in Figure1.7 will be shown. Select
“Use MFC in Shared DLL” from the list box and click OK.
4. Type the following code in the Code window:
#include<afxwin.h>

class myframe:public CFrameWnd


{
public : myframe()
{
CString mywindowclass; //MFC declared string class
HBRUSH mybrush;

mybrush=(HBRUSH)::GetStockObject(WHITE_BRUSH);

mywindowclass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,


AfxGetApp()->LoadStandardCursor(IDC_CROSS),
mybrush,AfxGetApp() -> LoadStandardCursor(
IDI_EXCLAMATION));
//register class with windows

Create(mywindowclass,"Hello ! Welcome to MFC Classes");


}
};

class myapp:public CWinApp


{
public:
int InitInstance()
{
myframe *p;
p=new myframe;
p->ShowWindow(3);
m_pMainWnd=p;

return 1;
}
};

myapp a;

5. Build and test the application.

92
CHAPTER 2

HANDLING MOUSE AND KEYBOARD EVENTS

2.1 Using Mouse and handling Mouse events

Windows 98 can support a one-button, two-button, or three-button mouse, or it can use a


joystick or light pen to mimic a mouse. In theory, you can determine if a mouse is present
by using our old friend the GetSystemMetrics function:

fMouse = GetSystemMetrics (SM_MOUSEPRESENT) ;

The value of fMouse will be TRUE (nonzero) if a mouse is installed and 0 if a mouse is
not installed. However, in Windows 98 this function always returns TRUE whether a
mouse is attached or not. In Microsoft Windows NT, it works correctly. To determine the
number of buttons on the installed mouse, use

cButtons = GetSystemMetrics (SM_CMOUSEBUTTONS) ;

This function should also return 0 if a mouse is not installed. However, under Windows
98 the function returns 2 if a mouse is not installed. Left-handed users can switch the
mouse buttons using the Windows Control Panel.

When the Windows user moves the mouse, Windows moves a small bitmapped picture
on the display. This is called the "mouse cursor." The mouse cursor has a single-pixel
"hot spot" that points to a precise location on the display. Windows supports several
predefined mouse cursors that programs can use. The most common is the slanted arrow
named IDC_ARROW (using the identifier defined in WINUSER.H). The hot spot is the
tip of the arrow.

When the mouse is moved over the client area of a window, the window procedure
receives the message WM_MOUSEMOVE. When a mouse button is pressed or released
within the client area of a window, the window procedure receives the messages in this
table:

Button Pressed Released Pressed (Second Click)


Left WM_LBUTTONDOWN WM_LBUTTONUP WM_LBUTTONDBLCLK
Middle WM_MBUTTONDOWN WM_MBUTTONUP WM_MBUTTONDBLCLK
Right WM_RBUTTONDOWN WM_RBUTTONUP WM_RBUTTONDBLCLK

For all these messages, the value of lParam contains the position of the mouse. The low
word is the x-coordinate, and the high word is the y-coordinate relative to the upper left

93
corner of the client area of the window. You can extract these values using the LOWORD
and HIWORD macros:

x = LOWORD (lParam) ;
y = HIWORD (lParam) ;

The value of wParam indicates the state of the mouse buttons and the Shift and Ctrl keys.
You can test wParam using these bit masks defined in the WINUSER.H header file.

Now let’s start programming with the mouse.

Program 2.1: Draw a free hand drawing as Mouse is Drag

1. Create a new Win32Application project and enter the following lines of code:

#include<windows.h>
long _stdcall func(HWND,UINT,UINT,long);
WNDCLASS a;
int flag=0,x1,y1,x2,y2;

int _stdcall WinMain(HINSTANCE i,HINSTANCE j,char *k,int l)


{
HWND h;
MSG m;

a.hInstance=i; //instance handle


a.lpszClassName="SimpleWnd"; //long pointer to class name
a.lpfnWndProc=func; //long pointer to Window procedure
a.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
//set background color of Window Client area
RegisterClass(&a); // Register the Window Class before use

h=CreateWindow("SimpleWnd","Title",WS_OVERLAPPEDWINDOW,20,20,300,200,0,0,i,
0); // Create Window Application
ShowWindow(h,3);

while(GetMessage(&m,0,0,0)) // extracts message from Message Queue


DispatchMessage(&m); // dispatches the message received
return 0;
}

long _stdcall func(HWND w,UINT x,UINT y,long z)


{
HDC d;

switch(x)
{
case WM_LBUTTONDOWN:
if(flag==0)
{
x1=LOWORD(z);
y1=HIWORD(z);
flag=1;

94
}
break;

case WM_MOUSEMOVE:
if(flag==1)
{
x2=LOWORD(z);
y2=HIWORD(z);
d=GetDC(w);
MoveToEx(d,x1,y1,0); // current position is updated to (x1,y1)
LineTo(d,x2,y2); // draw line from current pos to (x2,y2)
ReleaseDC(w,d);
x1=x2;
y1=y2;
}
break;

case WM_LBUTTONUP:
flag=0;
break;

case WM_DESTROY:
PostQuitMessage(0); // used to terminate while loop in WinMain()
break;

default:
return DefWindowProc(w,x,y,z);
}
return 0L;
}

2. Build and Test the program to find a window similar to one shown in Figure 2.1.

Figure 2.1 Free hand mouse drawing

95
Program 2.2: Simple line drawing in mouse events using MFC

1. Follow steps 1 to 3 in program1.6


2. Type the following lines of code in the code window:
#include<afxwin.h>
class myframe:public CFrameWnd
{
private: CPoint startpoint,endpoint;

public: myframe()
{
Create(0,"Click Left MouseButton In The Client Area");
}

void OnLButtonDown(UINT flag,CPoint pt)


{
endpoint=startpoint=pt;
}

void OnMouseMove(UINT flag,CPoint pt)


{
CClientDC d(this);
if(flag==MK_LBUTTON)
{
d.SetROP2(R2_NOTXORPEN);
// erase line
d.MoveTo(startpoint);
d.LineTo(endpoint);
//draw line
d.MoveTo(startpoint);
d.LineTo(pt);
endpoint=pt;
}
}

void OnLButtonUp(UINT flag,CPoint pt)


{
CClientDC d(this);
d.SetROP2(R2_COPYPEN);
d.MoveTo(startpoint);
d.LineTo(endpoint);
}
DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(myframe,CFrameWnd)

ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()

END_MESSAGE_MAP()

96
class myapp:public CWinApp
{
public: int InitInstance()
{
myframe *p;
p=new myframe;
p->ShowWindow(1);
m_pMainWnd=p;

return 1;
}
};

myapp a;

3. Build and execute the application to find an output window in which you can
draw lines at your wish as shown in Figure2.2.

Figure 2.2 Simple line drawing using mouse events

2.1.1 Application Wizard based Programming

AppWizard is a code generator that creates a working skeleton of a Windows application


with features, class names, and source code filenames that you specify through dialog
boxes. AppWizard code is minimalist code; the functionality is inside the application
framework base classes. AppWizard gets you started quickly with a new application.

The AppWizard tool generates the code for a functioning MFC library application. This
working application simply brings up an empty window with a menu attached. Later
you'll add code that draws inside the window.

97
Program 2.3: Hit-test program involving mouse events developed using AppWizard.

1. Run AppWizard to generate SDI application source code. Choose New from
Visual C++'s File menu, and then click the Projects tab in the resulting New
dialog box as shown in Figure2.3. Make sure that MFC AppWizard (exe) is
highlighted, and then type the path (for e.g. C:\vcpp32\) where you want the
project to be created in the Location edit box. Type a project name (for e.g.
Mouse_Event_Exercise”) in the Project Name edit box, and then click the OK
button. Now you will step through a sequence of AppWizard screens, the first of
which is shown in Figure2.4.

Figure 2.3 New Dialog Window

Figure 2.4 Step1 of 6 in AppWizard

98
2. Be sure to select the Single Document option. Accept the defaults in the next five
screens.
3. Click the Finish button. Just before AppWizard generates your code, it displays
the New Project Information dialog box, shown in Figure2.5.

Figure 2.5 New Project Information Dialog Window

4. Add the m_rectEllipse and m_nColor data members to


CMouse_Event_ExerciseView. With the Workspace window set to ClassView,
right-click the CMouse_Event_ExerciseView class, select Add Member Variable,
and then insert the following two data members:

private:
CRect m_rectEllipse;
int m_nColor;

If you prefer, you could type the above code inside the class declaration in the file
Mouse_Event_ExerciseView.h.

5. Use ClassWizard to add a CMouse_Event_ExerciseView class message


handler. Choose ClassWizard from the View menu of Visual C++, or right-click
inside a source code window and choose ClassWizard from the context menu.
When the MFC ClassWizard dialog appears, be sure that the

99
CMouse_Event_ExerciseView class is selected, as shown in the Figure2.6. Now
click on CMouse_Event_ExerciseView at the top of the Object IDs list box, and
then scroll down past the virtual functions in the Messages list box and double-
click on WM_LBUTTONDOWN. The OnLButtonDown function name should
appear in the Member Functions list box, and the message name should be
displayed in bold in the Messages list box.

Figure 2.6 Class Wizard Dialog Box

6. Edit the OnLButtonDown code in Mouse_Event_ExerciseView.cpp. Click the


Edit Code button. ClassWizard opens an edit window for
Mouse_Event_ExerciseView.cpp in Visual C++ and positions the cursor on the
newly generated OnLButtonDown member function. The following boldface code
(that you type in) replaces the previous code:

void CMouse_Event_ExerciseView::OnLButtonDown(UINT nFlags, CPoint point)


{
if (m_rectEllipse.PtInRect(point))
{
if (m_nColor == GRAY_BRUSH)
{
m_nColor = WHITE_BRUSH;
}
else {
m_nColor = GRAY_BRUSH;
}
InvalidateRect(m_rectEllipse);
}
}

100
7. Edit the constructor and the OnDraw function in
Mouse_Event_ExerciseView .cpp. The following boldface code (that you type
in) replaces the previous code:

CMouse_Event_ExerciseView:: CMouse_Event_ExerciseView () : m_rectEllipse(0, 0,


200, 200)
{
m_nColor = GRAY_BRUSH;
}
.
.
.
void CMouse_Event_ExerciseView::OnDraw(CDC* pDC)
{
pDC->SelectStockObject(m_nColor);
pDC->Ellipse(m_rectEllipse);
}

8. Build and run the Mouse_Event_Exercise program. Choose Build


Mouse_Event_Exercise.exe from the Build menu, then choose Execute
Mouse_Event_Exercise.exe from the Build menu.
9. The resulting program responds to presses of the left mouse button by changing
the color of the circle in the view window. (Don't press the mouse's left button
quickly in succession; Windows interprets this as a double click rather than two
single clicks.)

Program2.4: A hit-test program involving mouse events and Windows mapping modes

1. Do the following changes in the Mouse_Event_Exercise program.


2. Use ClassWizard to override the virtual OnPrepareDC function. Select the
class name CMouse_Event_ExerciseView in the Object IDs list, and then double-
click on the OnPrepareDC function in the Messages list. Edit the function as
shown here:

void CMouse_Event_ExerciseView::OnPrepareDC(CDC* pDC, CPrintInfo*


pInfo)
{
pDC->SetMapMode(MM_HIMETRIC);
CView::OnPrepareDC(pDC, pInfo);
}

3. Edit the view class constructor. You must change the coordinate values for the
ellipse rectangle. That rectangle is now 4-by-4 centimeters instead of 200-by-200
pixels. Note that the y value must be negative; otherwise, the ellipse will be drawn
on the "virtual screen" right above your monitor! Change the values as shown
here:

CMouse_Event_ExerciseView:: CMouse_Event_ExerciseView () :
m_rectEllipse(0, 0, 4000, -4000)
{ m_nColor = GRAY_BRUSH; }

101
4. Edit the OnLButtonDown function. This function must now convert the ellipse
rectangle to device coordinates in order to do the hit-test. Change the function as
shown in the following code:

void CMouse_Event_ExerciseView::OnLButtonDown(UINT nFlags, CPoint point)


{
CClientDC dc(this);
OnPrepareDC(&dc);
CRect rectDevice = m_rectEllipse;
dc.LPtoDP(rectDevice);
if (rectDevice.PtInRect(point)) {
if (m_nColor == GRAY_BRUSH) {
m_nColor = WHITE_BRUSH;
}
else {
m_nColor = GRAY_BRUSH;
}
InvalidateRect(rectDevice);
}
}

5. Build and run the program. The output should look similar to the output of the
previous program, except that the ellipse size will be different. If you try using
Print Preview again, the ellipse should appear much larger than it did in the
previous program.

Program 2.5: Drawing using Mouse on a dialog Window

1. Create a new MFC AppWizard workspace project, and name the project as
“Mouse”.
2. Specify that this project will be a dialog-based application in the first AppWizard
step.
3. Use the default settings in the AppWizard. In the second step, specify a suitable
dialog title, such as “Mouse and Keyboard”.
4. After the application shell is created, remove all controls from the dialog window.
This provides the entire dialog window surface for drawing. This step is also
necessary for your application to capture any keyboard events.
5. Open the Class Wizard. Select WM_MOUSEMOVE from the list of messages, and
add a function by clicking the Add Function button. Click the OK button to accept
the suggested function name.
6. Click the Edit Code button to edit the OnMouseMove function you just created, and
add the following code:

void CMouseDlg::OnMouseMove(UINT nFlags, CPoint point)


{
// TODO: Add your message handler code here
// Check to see if the left mouse button is down
if ((nFlags & MK_LBUTTON) == MK_LBUTTON)
{
// Get the Device Context
CClientDC dc(this);

102
// Draw the pixel
dc.SetPixel(point.x, point.y, RGB(0, 0, 0));
}

CDialog::OnMouseMove(nFlags, point);
}

10. Build and run the program. You’ll see a dialog window available as shown in
Figure2.7 for drawing any thing you wish using the mouse.

Figure 2.7 Sample output window for Program2.5

2.2 Keyboard Events

Reading keyboard events is similar to reading mouse events. As with the mouse, there are
event messages for when a key is pressed and when it is released. These messages are
listed below:

Message Description
WM_KEYDOWN A key has been pressed down
WM_KEYUP A key has been released
WM_CHAR Character messages

Program 2.6: Toggling the Mouse Cursor using keyboard events. (Make the ‘A’ key
change the cursor to the default arrow cursor, which your application starts with. Then
make ‘B’ key change the cursor to the I-beam and ‘C’ change the cursor to the
hourglass.)

1. Make the following changes to the program2.5.


2. Using the Class Wizard, add a function for the WM_KEYDOWN message on the
dialog object.
3. Edit the OnKeyDown function by adding the following lines of code:

103
void CMouseDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default

char lsChar; // The current character being pressed


HCURSOR lhCursor; // The handle to the cursor to be displayed

// Convert the key pressed to a character


lsChar = char(nChar);

if (lsChar == `A') // Is the character "A" then load the arrow cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

if (lsChar == `B') // Is the character "B" then load the I beam cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);

if (lsChar == `C') // Is the character "C" then load the hourglass cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_WAIT);

if (lsChar == `X') // Is the character "X"


{
// Load the arrow cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
m_bCursor = TRUE; // Set the cursor flag
SetCursor(lhCursor); // Set the screen cursor
OnOK(); // Exit the application
}

CDialog::OnKeyDown(nChar, nRepCnt, nFlags);


}

4. Add a new variable m_bCursor to the CMouseDlg class. You can do this by right
clicking on the CMouseDlg in the Class View tab and select Add Member
Variable in the popup menu. Declare the type as BOOL as shown Figure2.8.

Figure 2.8 Adding Variable Dialog

5. Initialize the m_bCursor variable in the OnInitDialog with the following lines of
code:

BOOL CMouseDlg::OnInitDialog()
{

104
CDialog::OnInitDialog();

.
.
.

// Set the icon for this dialog. The framework does this
// automatically when the application's main window is not a
// dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

// Initialize the cursor to the arrow

m_bCursor = FALSE;

return TRUE; // return TRUE unless you set the focus to a control
}

6. Alter the OnKeyDown function to set the m_bCursor flag to TRUE when you
change the cursor by using the bold faced lines of statement shown below:

void CMouseDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)


{
// TODO: Add your message handler code here and/or call default

char lsChar; // The current character being pressed


HCURSOR lhCursor; // The handle to the cursor to be displayed

// Convert the key pressed to a character


lsChar = char(nChar);

if (lsChar == `A') // Is the character "A" then load the arrow cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

if (lsChar == `B') // Is the character "B" then load the I beam cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);

if (lsChar == `C') // Is the character "C" then load the hourglass cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_WAIT);

if (lsChar == `X') // Is the character "X"


{
// Load the arrow cursor
lhCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
m_bCursor = TRUE; // Set the cursor flag
SetCursor(lhCursor); // Set the screen cursor
OnOK(); // Exit the application
}
else
{
// Set the cursor flag

105
m_bCursor = TRUE;
// Set the screen cursor
SetCursor(lhCursor);
}

CDialog::OnKeyDown(nChar, nRepCnt, nFlags);


}

7. Using the Class Wizard, add a function for the WM_SETCURSOR message on the
dialog object.

8. Edit the OnSetCursor function that you just created, by adding the code show
below:
BOOL CMouseDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: Add your message handler code here and/or call default

// If the cursor has been set, then return TRUE


if (m_bCursor)
return TRUE;
else

return CDialog::OnSetCursor(pWnd, nHitTest, message);


}

9. Build and Execute the program and observe the changes that happens when you
press the keys on the keyboard.

Program 2.7: Creating a Notepad

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name Keystrokes in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Single Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CKeystrokesApp,
CMainFrame, CKeystrokesDoc, CKeystrokesView .
7. Declare the StringData variable on the document’s header file, KeystrokesDoc.h, in
the protected part.

class CKeystrokesDoc : public CDocument


{
protected: // create from serialization only
CKeystrokesDoc();
DECLARE_DYNCREATE(CKeystrokesDoc)
CString StringData;
...
};

106
8. Initialize that string to an empty string in the document’s constructor, which
we find in KeystrokesDoc.cpp.

CKeystrokesDoc::CKeystrokesDoc()
{
StringData=" ";
// TODO: add one-time construction code here
}

9. Add a new event handler OnChar to our view class which is called every time
the user types the character.
10. The character the user typed is now in the nChar parameter, which we store in the
our data string object, StringData. The object in our document, so we need a
pointer(pDoc) to our document object.
11. Add the character nChar to the string StringData.

void CKeystrokesView::OnChar(UINT nChar, UINT nRepCnt,


UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CKeystrokesDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData+=nChar;
Invalidate();

CView::OnChar(nChar, nRepCnt, nFlags);


}

12. We’ll handle the display of our data in the view’s OnDraw( ). We need to draw
the text string, which we do with TextOut( ).

void CKeystrokesView::OnDraw(CDC* pDC)


{
CKeystrokesDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

pDC->TextOut(0,0,pDoc->StringData);
// TODO: add draw code for native data here
}

13. Test the application and observe output.

107
CHAPTER 3

INTRODUCTION TO RESOURCES

3.1 Introduction

A resource is an object that cannot be defined in C++ terms but that is needed to
complete a program. In the strict sense, it is text that contains a series of terms or words
that the program can interpret through code. Examples of resources are menus, icons,
cursors, dialog boxes, sounds, etc.

There are various means of creating a resource and the approach you use depends on the
resource. For example, some resources are completely text-based, such is the case for the
String Table or the Accelerator Table. Some other resources must be designed, such is the
case for icons and cursors. Some other resources can be imported from another, more
elaborate application, such is the case for high graphic pictures. Yet some resources can
be a combination of different resources.

3.2 Resource Creation

Resources are not a C++ concept but a Microsoft Windows theory of completing an
application. Therefore, the programming environment you use may or may not provide
you with the means of creating certain resources. Some environments like Borland C++
Builder or Visual C++ (6 and .NET) are complete with (almost) anything you need to
create (almost) any type of resources. Some other environments may appear incomplete,
allowing you to create only some resources, the other resources must be created using an
external application not provided; such is the case for C++BuilderX.

Upon creating a resource, you must save it. Some resources are created as their own file,
such is the case for pictures, icons, cursors, sound, etc. Each of these resources has a
particular extension depending on the resource. After creating the resources, you must
add them to a file that has the extension .rc. Some resources are listed in this file using a
certain syntax. That's the case for icons, cursors, pictures, sounds, etc. Some other
resources must be created directly in this file because these resources are text-based;
that's the case for menus, strings, accelerators, version numbers, etc.

After creating the resource file, you must compile it. Again, some environments, such as
Microsoft Visual C++, do this automatically when you execute the application. Some
other environments may require you to explicitly compile the resource. That's the case for
Borland C++ Builder and C++BuilderX. (The fact that these environments require that
you compile the resource is not an anomaly. For example, if you create a Windows
application that is form-based in C++ Builder 6 or Delphi, you can easily add the
resources and they are automatically compiled and added to the application. If you decide
to create a Win32 application, C++ Builder believes that you want to completely control

108
your application; so, it lets you decide when and how to compile a resource. This means
that it simply gives you more control).

3.2.1 Cursor Resource

A cursor is a small picture that represents the position of the mouse on a screen. Cursors
are like images, and you edit them in the same way. However, cursors have attributes that
distinguish them from images. For example, each cursor resource can contain multiple
images for different display devices. In addition, a cursor has a “hot spot”: the location
Windows uses to track its position.

When you create a new cursor, the Graphics editor first creates an image for VGA. The
image is initially filled with the “screen” (transparent) color. If the image is a cursor, the
hot spot is initially the upper-left corner (coordinates 0,0). Now let’s see how to create
and use cursors in our windows programming environment. Those cursors already
available to you are shown in Figure3.1:

Figure 3.1 Cursors available in window environment

Now let’s see how to create and embed cursors in the window that we create.

Program 3.1: Creating a Cursor Resource and attaching it to a window

Main Program Creation

1. Create a new Win32 Application as done the previous time.


2. Save the project as Resources1.
3. Create a new C++ Source file named Exercise.cpp
4. Implement the source file as follows:

#include <windows.h>

LPCTSTR ClsName = "FundApp";

109
LPCTSTR WndName = "Resources Fundamentals";
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
MSG Msg;
HWND hWnd;
WNDCLASSEX WndClsEx;

// Create the application window


WndClsEx.cbSize = sizeof(WNDCLASSEX);
WndClsEx.style = CS_HREDRAW | CS_VREDRAW;
WndClsEx.lpfnWndProc = WndProcedure;
WndClsEx.cbClsExtra = 0;
WndClsEx.cbWndExtra = 0;
WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndClsEx.lpszMenuName = NULL;
WndClsEx.lpszClassName = ClsName;
WndClsEx.hInstance = hInstance;
WndClsEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

// Register the application


RegisterClassEx(&WndClsEx);

// Create the window object


hWnd = CreateWindowEx(0,
ClsName,
WndName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);

// Find out if the window was created


if( !hWnd ) // If the window was not created,
return FALSE; // stop the application

// Display the window to the user


ShowWindow(hWnd, nCmdShow);// SW_SHOWNORMAL);
UpdateWindow(hWnd);

while( GetMessage(&Msg, NULL, 0, 0) )


{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

110
return Msg.wParam;
}

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg,


WPARAM wParam, LPARAM lParam)
{
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
// Process the left-over messages
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
// If something was not done, let it go
return 0;
}

5. Execute the application to test it. The Application development is not over.
Continue with the resource creation steps.

Cursor Resource Creation

1. To create the cursor, on the main menu, click Insert -> Resource... In the Insert
Resource dialog box, click Cursor and click New.
2. Click View -> Properties...
In the Properties window, change the ID to IDC_TARGET and press Tab.
Make sure the file name is changed to target.cur and press Enter.
3. Design the cursor as shown in Figure3.2:

Figure3.2. Cursor Design

4. To define the hot spot, on the toolbar of the editor, click the Set Hot Spot button.
Click the middle of the square as shown in Figure3.3:

111
Figure 3.3 Defining the hotspot

5. To save and close the resource file, click its system Close button (the system
Close button of the child window) of the cursor and close the child window of the
script (the window with Script1 or Script2)
6. When asked to save the script, click Yes
7. Locate the folder where the current exercise is located and display in the Save In
combo box. Change the name of the file to Resources1.rc. The right extension
(.rc) will be added to the file.
8. Click Save
9. To add the resource file to the current project, on the main menu, click Project ->
Add To Project -> Files...
10. In the list box, click Resources1.rc and click OK
11. In the Workspace, click the ResourceView tab.
Expand the Resources1 resource node by clicking its + button. Expand the Cursor
node. Make sure the IDC_TARGET cursor is present.
12. After creating the resource file, because the Resource header file holds the
identifiers of the resource, remember to include it in the file where you want to
use the resources. Include the following statement:

#include "resource.h"

immediately below the #include <windows.h> statement in the Main.cpp file.


13. Also change the LoadCursor method in the Main.cpp as shown below:

WndClsEx.hCursor = LoadCursor(hInstance,
MAKEINTRESOURCE(IDC_TARGET));

14. To execute press Ctrl + F5 and Enter to see the window as shown in Figure3.4.

112
Figure 3.4 Output window with newly defined cursor

3.2.2 Menu Resource

A menu is one of the text-based resources. It is created directly in the rc file. As with
other resources, the process of creating a menu depends on the environment you are
using. If you are using Microsoft Visual C++, you can use the built-in menu editor. In
this case, the actual text that defines and describes the menu would be automatically
added to the rc file.

Program 3.2: Creating a Menu resource and attaching it with the window.

1) Use the previous “Resource Fundamental” program and continue with the below
mentioned steps.
2) On the main menu, click Insert  Resource and in the dialog box, click Menu
and click New. This will insert a new menu resource in your project.
3) While the first menu item is selected, type &File.
4) Click the next empty item under File. Type &New.
5) In the Properties window, click the ID edit box, type IDM_FILE_NEW and
press Enter.
6) Click the next empty item under New and type &Open.
7) In the Properties window, click the ID edit box, type IDM_FILE_OPEN and
press Enter.
8) Click the next empty item under Open and in the properties check the
“Separator” option to include a separator bar.
9) Click the next empty item under the new separator and type E&xit.
10) In the Properties window, click the ID edit box, type IDM_FILE_EXIT and
press Enter.
11) Click the next empty item on the right side of File. Type &Help.

113
12) Click the next empty item under Help and type &About.
13) In the Properties window, click the ID edit box, type IDM_HELP_ABOUT and
press Tab. In the Caption edit box, and press Enter.
14) In the ResourceView tab of the Workspace, under the Menu node, click
IDR_MENU1. In the Menu Properties window, change the ID to
IDR_MAINFRAME.
15) Open the Exercise.cpp source file and change the lpszMenuName member of the
WndClsEx variable as follows:

WndClsEx.lpszMenuName = MAKEINTRESOURCE(IDR_MAINFRAME);

16) To test the application, press Ctrl + F5 and press Enter and you’ll find a window
with the menu that you have created as shown in Figure3.5.

Figure 3.5 A Window with a Menu

3.2.3 String Table Resource

A string table is created in the rc file. In Visual C++, to create the list, you can add the
String Table from the Add Resource dialog box. This opens a special window in which
you can edit each string.

Besides new strings you create in the list with their own new identifiers, you can also use
the string table to assign strings to already created identifiers. For example, to can assign
a string to some or all of the menu items we created earlier.

After creating a string table, you can access any of its strings from anywhere in the
application. To access a string, call the LoadString function.

Program 3.3: Creating and Using a String Table

1) Use the previous “Menu” program and continue with the below mentioned steps.
2) To create a string table, on the main menu, click Project -> Add Resource...
3) In the Add Resource dialog box, double-click String Table

114
4) Replace the first IDS_ identifier with IDS_APP_NAME and press Tab twice
5) Type the string as Fundamentals of Windows Resources and press Enter
6) In the same way, create the following strings and their identifiers:

Value
IDM_ARROW 105 No tool selected
IDM_DRAW_LINE 106 Selects the Line tool\nLine
IDM_DRAW_RECTANGLE 107 Selects the Rectangle tool\nRectangle
IDM_DRAW_ELLIPSE 108 Selects the Ellipse tool\nEllipse

7) To assign to an existing identifier, click the arrow of the second identifier and
select IDM_FILE_NEW
8) Click its corresponding Caption section and type Creates a new file\nNew
9) To use a string from the string table, include the following lines of code in the
Main.cpp as shown below:
i. Include the following declaration statement
char AppCaption[40];
immediately below the #include "resource.h" statement.

ii. Include the following function


LoadString(hInstance, IDS_APP_NAME, AppCaption, 40);
below the WNDCLASSEX WndClsEx; declaration statement
inside the WinMain function.

iii. Change the CreateWindow method as shown:

hWnd = CreateWindowEx( 0,
ClsName,
AppCaption,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);

10) Execute the application and observe the output window.

3.2.4 Dialog Resource

Message Boxes

To create a message box, use the MessageBox function. Its syntax is:

115
int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

The first argument, hWnd, can be a handle to the window from where the message box
will be called. Otherwise, it can NULL.

The second argument, lpText, is a null-terminated string, such as an array of characters.


This is the actual message that will be presented to the user.

The third argument, lpCaption, is the title that will display on the title bar. It also can be a
null-terminated string, if you know what title you would like to display. Otherwise, it can
be NULL, in which case the title bar would display Error.

The simplest way you can create a message is by calling the MessageBox function with
all arguments set to NULL, in which case the message box would not make any sense:

MessageBox(NULL, NULL, NULL, NULL);

The fourth argument actually does three things. First it displays one or a few buttons. The
buttons depend on the value specified for the argument. If this argument is NULL, the
message box displays (only) OK. The values and their buttons can be as follows:

Constant Integer Buttons

MB_OK
MB_OKCANCEL
MB_ABORTRETRYIGNORE
MB_YESNOCANCEL
MB_YESNO
MB_RETRYCANCEL
MB_CANCELTRYCONTINUE
MB_HELP

Besides the buttons, the message box can also display a friendly icon that accompanies
the message. Each icon is displayed by specifying a constant integer. The values and their
buttons are as follows:

116
Value Icon Suited when
MB_ICONEXCLAMATION Warning the user of an action
MB_ICONWARNING performed on the application
MB_ICONINFORMATION Informing the user of a non-critical
MB_ICONASTERISK situation
Asking a question that expects a Yes
MB_ICONQUESTION or No, or a Yes, No, or Cancel
answer
A critical situation or error has
MB_ICONSTOP occurred. This icon is appropriate
MB_ICONERROR when informing the user of a
MB_ICONHAND termination or deniability of an
action

The icons are used in conjunction with the buttons constant. To combine these two flags,
use the bitwise OR operator “|”.

The second thing this fourth argument does is to let the user close the message box after
selecting one of the buttons. Once the user clicks one of the buttons, the message box is
closed.

The third role of this fourth argument is to control the result derived from the user
dismissing the message box. For example, clicking OK usually means that the user
acknowledges what the message. Clicking Cancel usually means the user is changing his
or her mind about the action performed previously. Clicking Yes instead of No usually
indicates that the user agrees to perform an action.

Program 3.4: Displaying a simple message box

1. Create a new Win32 application


2. Type the following code in the code window:

#include <windows.h>

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
MessageBox(NULL, "Welcome to Win32 Application Development\n",
NULL, NULL);
return 0;
}

3. Test the program and return to your programming environment


4. To create a more elaborate message, change the file as follows:

117
#include <windows.h>
LPCTSTR Caption = "Application Programming Interface";

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
MessageBox( NULL, "Welcome to Win32 Application Development\n"
"You are learning about MessageBoxes\n",
Caption,
MB_YESNOCANCEL | MB_ICONQUESTION);
return 0;
}

7. Execute the application and you’ll see a message box as indicated in Figure3.6:

Figure 3.6 Informative Message Box

3.2.5 Dialog Boxes

A dialog box is a rectangular object that displays a message, a control, or a few controls,
allowing the user to interact with an application.

A dialog box is created from a resources file, which is a file with the rc extension. The
resource file contains all pertinent information about the dialog box. This means that, in
this file, you must specify the size and location of the dialog box, its caption, whether it
contains buttons. After creating the resource file, make sure you add it to your project so
you can compile it.

There are two main reasons you would create or use a dialog box. You can create a
dialog-based application, that is, a dialog that uses only one or a few dialog box. You can
also use a dialog box as an addition to your application.

Program 3.5: Creating and using Dialog boxes in windows application.

1. Create a new Win32 Application. Specify the desired path in the Location edition
box. In the Project Name, type DialogApplication
2. Make sure you create it as an Empty Project.
3. To create a dialog box along with the resource files, on the main menu, click
Insert -> Resource...
4. In the Insert Resource dialog box, click Dialog and click New

118
5. Right-click in the main body of the new dialog box and click Properties. In the
Dialog Properties window, change the ID to IDD_DLGFIRST and press Tab.
6. In the Caption box, type Win32 Programming
7. In the X Pos box, type 260
8. In the Y Pos box, type 200
9. To close and save the resource file, click the system Close button of the Script1 -
IDD_DLGFIRST window
10. When asked whether you want to save the script, click Yes.
11. Locate the folder in which the application is being created (in this case
DialogApplication) and display it in the Save In combo box.
12. In the File Name box, replace the Script1 name with Dialog1.rc and click Save
13. To add the rc file to your project, on the main menu, click Project -> Add To
Project -> Files...
14. Select Dialog1.rc and click OK.
15. To create the main source file of the project, on the main menu, click File ->
New...
16. In the Files property page of the New dialog box, click C++ Source File. In the
File Name edit box, type Main and press Enter.
17. In the Main.cpp file, create the program as follows:

#include <windows.h>
#include "resource.h"

HWND hWnd;
LRESULT CALLBACK DlgProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DLGFIRST),
hWnd, reinterpret_cast<DLGPROC>(DlgProc));

return FALSE;
}

LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam,


LPARAM lParam)
{
switch(Msg)
{
case WM_INITDIALOG:
return TRUE;

case WM_COMMAND:
switch(wParam)
{
case IDOK:
EndDialog(hWndDlg, 0);
return TRUE;
}
break;

119
}
return FALSE;
}

18. Test the program and you’ll see an output shown in Figure3.7:

Figure 3.7 Dialog Box

120
CHAPTER 4

THE GRAPHICAL DEVICE INTERFACE

4.1 Introduction

To help with drawing on the Windows operating system, Microsoft created the Graphical
Device Interface, abbreviated as GDI. It is a set of classes, functions, variables, and
constants that group all or most of everything you need to draw on an application. The
GDI is provided as a library called Gdi.dll and is already installed on your computer.

4.2 Grabbing the Device Context

As mentioned already, in order to draw, you need at least two things: a platform and a
tool. The platform allows you to know what type of object you are drawing on and how
you can draw on it. On a Windows application, you get this platform by creating a device
context. A device context is actually a whole class that provides the necessary drawing
tools to perform the job. For example, it provides functions for selecting the tool to use
when drawing. It also provides functions to draw text, lines, shapes etc.

In order to draw using a device context, you must first declare an HDC variable. This can
be done as follows:

HDC hDC;

After declaring this variable, you must prepare the application to paint by initializing it
with a call to the BeginPaint function. The syntax of the BeginPaint function is:

HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);

The hwnd argument is a handle to the window on which you will be painting. The lpPaint
argument is a pointer to the PAINTSTRUCT structure. This means that, the BeginPaint
function returns two values. It returns a device context as HDC and it returns information
about the painting job that was performed. That painting job is stored in a
PAINTSTRUCT value. The PAINTSTRUCT structure is defined as follows:

typedef struct tagPAINTSTRUCT {


HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT;

121
After initializing the device context, you can call a drawing function or perform a series
of calls to draw. After painting, you must let the operating system know by calling the
EndPaint function. Its syntax is:

BOOL EndPaint(HWND hWnd, CONST PAINTSTRUCT *lpPaint);

Painting with the BeginPaint( ) and EndPaint( ) functions must be performed in the
WM_PAINT message.

4.3 Line-Based Shapes

4.3.1 Lines

A line is a junction of two points. This means that a line has a beginning and an end:

The beginning and the end are two distinct points . In real life, before drawing, you
should define where you would start. To help with this, you can use MoveToEx()
function. Its syntax is:

BOOL MoveToEx(HDC hdc, int X, int Y, LPPOINT lpPoint);

The origin of a drawing is specified as the (X, Y) point.

To end the line, you use the LineTo() function. Its syntax is:

BOOL LineTo(HDC hdc, int nXEnd, int nYEnd);

The end of a line can be defined by its horizontal (nXEnd) and its vertical measures
(nYEnd).

122
Program 4.1: Simple SDK program to draw a line starting at a point defined as (10, 22)
coordinates and ending at (155, 64).

11. Start the Microsoft Development Environment by clicking Start Programs


Microsoft Visual Studio 6.0 Microsoft Visual C++.
12. On the main menu, click File -> New... or File -> New -> Project...
13. In the New or New Project dialog box, click either Win32 Application as in
Figure 4.1:

Figure 4.1 New Project Dialog Window

14. In the location, type the path where the application should be stored, such as
“C:\Programs\MSVC”
15. In the Name edit box, type the name of the application as Win32A and click OK.
16. In the next dialog box of the wizard, click the An Empty Project radio button as
shown in Figure4.2.
17. Click Finish. You will be presented with another dialog box; in this case click
OK.
18. To create the first needed file of the program, on the main menu, click File ->
New(Figure4.3).
19. In the Name edit box, replace the contents with a name for a file. In the case,
replace it with Main and press Enter.
20. Enter the following lines of code in the code window area:

123
Figure 4.2 Step 1 of Win32 Application Creation

Figure 4.3 New File Dialog Window

124
#include "windows.h"

LRESULT CALLBACK WinProc(HWND, UINT, WPARAM, LPARAM);

TCHAR szAppName[] = TEXT("GDI Fundamentals");


TCHAR szWinClass[] = TEXT("WIN_CLASS");

int WINAPI WinMain(HINSTANCE hInstance,


HINSTANCE hPrevInstance,
PSTR lpCmdLine,
int nCmdShow)
{
MSG msg; // a struct used in the passing of messages
WNDCLASS wc; // a window class struct, see below
HWND hwnd; // a handle-to-a-window, see below

wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground= (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.hCursor= LoadCursor(NULL, IDC_ARROW);
wc.hIcon= LoadIcon(NULL, IDI_APPLICATION);
wc.hInstance= hInstance;
wc.lpfnWndProc= WinProc;
wc.lpszClassName= szWinClass;
wc.lpszMenuName= NULL;
wc.style= CS_HREDRAW | CS_VREDRAW;

if( !RegisterClass(&wc)) // register the class, and test if it fails


{
MessageBox(NULL, TEXT("Error registering class"), TEXT("ERROR"),
MB_OK);
return 0;
}

hwnd = CreateWindow( szWinClass,


szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
(HWND) NULL,
(HMENU) NULL,
(HINSTANCE) hInstance,
(void *) NULL);

ShowWindow(hwnd, nCmdShow);

(Maximised, Minimised, etc)


UpdateWindow(hwnd);
while (GetMessage(&msg, (HWND) NULL, 0, 0))
{
TranslateMessage(&msg); // some messages need translating
DispatchMessage(&msg); // send the message to the window
}

125
return msg.wParam; // return the message struct's wParam
}

LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam,


LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;

switch(msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
oveToEx(hDC, 60, 20, NULL);
ineTo(hDC, 264, 122);
ndPaint(hWnd, &Ps);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;
}

return DefWindowProc(hwnd, msg, wParam, lParam);


}

12. To execute the program first you must compile the program by pressing Ctrl + F7.
13. Then build the EXE by pressing F7.
14. Finally when you execute the EXE by pressing Ctrl + F5, you can see an output as
given Figure4.4.

Figure 4.4 Line Drawing

15. To close the window, click its system Close button and return to your
programming environment.

126
Program 4.2: Create a window and draw a triangle wing line drawing functions.

1. Modify the program4.1 by replacing the case WM_PAINT using the codes given
below:

case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
MoveToEx(hDC, 60, 20, NULL);
LineTo(hDC, 60, 122);
LineTo(hDC, 264, 122);
LineTo(hDC, 60, 20);
EndPaint(hWnd, &Ps);
break;

2. Test the program and you’ll find a window as shown in Figure4.5 with a triangle:

Figure 4.5 Drawing a triangle

4.3.2 Polylines

A polyline is a series of connected lines. The lines are stored in an array of POINT
values. To draw a polyline, you can use the Polyline() function. Its syntax is:

BOOL Polyline(HDC hdc, CONST POINT *lppt, int cPoints);

The lppt argument is an array of points that can be of POINT types. The cPoints
argument specifies the number of members of the array. When executing, the compiler
moves the starting point to lppt[0]. The first line is drawn from lppt[0] to lppt[1].

To draw a polyline, you must have at least two points. If you define more than two
points, each line after the first would be drawn from the previous point to the next point
until all points have been included.

127
Program 4.3: Drawing multiple lines using PolyLine method.

1. Replace the Window Procedure in program4.1 by the following lines of codes:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM


lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
POINT Pt[7];
Pt[0].x = 20; Pt[0].y = 50;
Pt[1].x = 180; Pt[1].y = 50;
Pt[2].x = 180; Pt[2].y = 20;
Pt[3].x = 230; Pt[3].y = 70;
Pt[4].x = 180; Pt[4].y = 120;
Pt[5].x = 180; Pt[5].y = 90;
Pt[6].x = 20; Pt[6].y = 90;

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
Polyline(hDC, Pt, 7);
EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find a window as shown in Figure4.6:

Figure 4.6 Drawing lines using PolyLine Method

128
4.3.3 Multiple Polylines

The above polylines were used each as a single entity. That is, a polyline is a combination
of lines. If you want to draw various polylines in one step, you can use the PolyPolyline()
function. By definition, the PolyPolyline() function is used to draw a series of polylines.
Its syntax is:

BOOL PolyPolyline(HDC hdc, CONST POINT *lppt, CONST DWORD


*lpdwPolyPoints, DWORD cCount);

Like the above Polyline() function, the lppt argument is an array of POINT values. The
PolyPolyline() function needs to know how many polylines you would be drawing.

Each polyline will use the points of the lpdwPolyPoints value but when creating the array
of points, the values must be incremental. This means that PolyPolyline() will not access
their values at random. It will retrieve the first point, followed by the second, followed by
the third, etc. Therefore, your first responsibility is to decide where one polyline starts
and where it ends. The good news (of course depending on how you see it) is that a
polyline does not start where the previous line ended. Each polyline has its own
beginning and its own ending point.

Unlike Polyline(), here, the cCount argument is actually the number of shapes you want
to draw and not the number of points (remember that each polyline "knows" or controls
its beginning and end).

The lpdwPolyPoints argument is an array or positive integers. Each member of this array
specifies the number of vertices (lines) that its corresponding polyline will have. For
example, imagine you want to draw M, followed by L, followed by Z. The letter M has 4
lines but you need 5 points to draw it. The letter L has 2 lines and you need 3 points to
draw it. The letter Z has 3 lines so 4 points are necessary to draw it. You can store this
combination of lines in an array defined as { 5, 3, 4 }.

Program 4.4: Drawing multiple object shapes using PolyLine method

1. Replace the Window Procedure in program4.1 by the following lines of codes:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM


lParam)
{
HDC hDC;
PAINTSTRUCT Ps;

POINT Pt[15];
DWORD lpPts[] = { 4, 4, 7 };

// Left Triangle
Pt[0].x = 50;
Pt[0].y = 20;
Pt[1].x = 20;

129
Pt[1].y = 60;
Pt[2].x = 80;
Pt[2].y = 60;
Pt[3].x = 50;
Pt[3].y = 20;

// Second Triangle
Pt[4].x = 70;
Pt[4].y = 20;
Pt[5].x = 100;
Pt[5].y = 60;
Pt[6].x = 130;
Pt[6].y = 20;
Pt[7].x = 70;
Pt[7].y = 20;

// Hexagon
Pt[8].x = 145;
Pt[8].y = 20;
Pt[9].x = 130;
Pt[9].y = 40;
Pt[10].x = 145;
Pt[10].y = 60;
Pt[11].x = 165;
Pt[11].y = 60;
Pt[12].x = 180;
Pt[12].y = 40;
Pt[13].x = 165;
Pt[13].y = 20;
Pt[14].x = 145;
Pt[14].y = 20;

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
PolyPolyline(hDC, Pt, lpPts, 3);
EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

3. Test the program and you’ll find a window as shown in Figure4.7.

130
Figure 4.7 Drawing shapes using PolyPloyline method

4.3.4 Closed Shapes

Polygons

A polygon is a closed polyline. In other words, it is a polyline defined so that the end
point of the last line is connected to the start point of the first line. To draw a polygon,
you can use the Polygon() function. Its syntax is:

BOOL Polygon(HDC hdc, CONST POINT *lpPoints, int nCount);

This function uses the same types of arguments as the Polyline() function.

Program 4.5: Drawing a polygon.

1. Replace the Window Procedure in program4.1 by the following lines of codes:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM


lParam)
{
HDC hDC;
PAINTSTRUCT Ps;

POINT Pt[7];
Pt[0].x = 20;
Pt[0].y = 50;
Pt[1].x = 180;
Pt[1].y = 50;
Pt[2].x = 180;
Pt[2].y = 20;
Pt[3].x = 230;
Pt[3].y = 70;
Pt[4].x = 180;
Pt[4].y = 120;
Pt[5].x = 180;
Pt[5].y = 90;
Pt[6].x = 20;
Pt[6].y = 90;

switch(Msg)
{
case WM_PAINT:

131
hDC = BeginPaint(hWnd, &Ps);
Polygon(hDC, Pt, 7);
EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find a window as shown in Figure 4.8.

Figure 4.8 Drawing a Polygon using Polygon method

Rectangles and Squares

A rectangle is a geometric Figure made of four sides that compose four right angles. Like
the line, to draw a rectangle, you must define where it starts and where it ends. This can
be illustrated as follows:

132
The drawing of a rectangle typically starts from a point defined as (X1, Y1) and ends at
another point (X2, Y2). To draw a rectangle, you can use the Rectangle() function. Its
syntax is:

BOOL Rectangle(HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int
nBottomRect);

Program 4.6: Drawing Rectangle

1. Replace the Window Procedure in program4.1 by the following lines of codes:

LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM


lParam)
{
HDC hDC;
PAINTSTRUCT Ps;

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
Rectangle(hDC, 20, 20, 226, 144);
EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find a window as shown in Figure4.9.

Figure 4.9 Drawing a Rectangle

133
Bézier Curves

A bézier line is an arc that is strictly based on a set number of points instead of on an
ellipse. A bézier curve uses at least four points to draw on. A bézier line with four points
can be illustrated as follows:

To draw this line (with four points), the compiler would draw a curve from the first to the
fourth points. Then it would bend the curve by bringing each middle (half-center) side
close to the second and the third points respectively, of course without touching those
second and third points. For example, the above bézier curve could have been drawn
using the following four points:

PolyBezier():

To draw a bézier curve, the GDI library provides the PolyBezier() function. Its syntax is:

BOOL PolyBezier(HDC hdc, CONST POINT *lppt, DWORD cPoints);

The lppt argument is an array of POINT values. The cPoints argument specifies the
number of points that will be used to draw the line.

134
Program 4.7: Drawing a bézier using PolyBezier method.

1. Replace the Window Procedure in program4.1 by the following lines of codes:


LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
lParam)
{
HDC hDC;
PAINTSTRUCT Ps;

POINT Pt[4] = { { 20, 12 }, { 88, 246 }, { 364, 192 }, { 250, 48 } };

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
PolyBezier(hDC, Pt, 4);
EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find a window as shown in Figure4.10.

Figure 4.10 Drawing Bezier Line

4.4 Drawing Text

By default, the device context is able to draw text using a font pre-selected, known as the
System Font. To draw text, you can use the TextOut() method. Its syntax is:

135
BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString);

To use this funuction, you must specify where the text would start. This location is
determined from the (0, 0) origin to the nXStart and to the nYStart values. The text to
display is the lpString string. The cbString value is the length of the text.

Program 4.8: To draw a Text on the client area of the window.

1. Start the Microsoft Development Environment by clicking Start Programs


Microsoft Visual Studio 6.0 Microsoft Visual C++.
2. On the main menu, click File -> New... or File -> New -> Project...
3. In the New or New Project dialog box, click either Win32 Application.
4. In the location, type the path where the application should be stored, such as
“C:\Programs\MSVC”
5. In the Name edit box, type the name of the application as TextDraw and click
OK.
6. In the next dialog box of the wizard, click the An Empty Project radio button.
7. Click Finish. You will be presented with another dialog box; in this case click
OK.
8. To create the first needed file of the program, on the main menu, click File ->
New.
9. In the Name edit box, replace the contents with a name for a file. In the case,
replace it with Main and press Enter.
10. Enter the following lines of code in the code window area:
#include <windows.h>

LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam,


LPARAM lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndCls;
static char szAppName[] = "GDI Suite";
MSG Msg;

WndCls.cbSize = sizeof(WndCls);
WndCls.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
WndCls.lpfnWndProc = WindProcedure;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hInstance = hInstance;
WndCls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = szAppName;
WndCls.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);

136
CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szAppName,
"GDI – Drawing Text",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);

while( GetMessage(&Msg, NULL, 0, 0) )


{
TranslateMessage(&Msg);
DispatchMessage( &Msg);
}

return static_cast<int>(Msg.wParam);
}

LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,


WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
COLORREF clrRed = RGB(255, 25, 5);
COLORREF clrBlue = RGB(12, 25, 255);

switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
SetTextColor(hDC, clrRed);
TextOut(hDC, 50, 42, "Anna University", 15);
SetTextColor(hDC, clrBlue);
TextOut(hDC, 50, 80, "One Among the top ten Universities
in India", 43);
EndPaint(hWnd, &Ps);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

12. To execute the program first you must compile the program by pressing Ctrl + F7.
13. Then build the EXE by pressing F7.
14. Finally when you execute the EXE by pressing Ctrl + F5, you can see an output as
given in Figure 4.11.

137
Figure 4.11 Drawing Text

15. To close the window, click its system Close button and return to your
programming environment.

4.5 Bitmaps

A bitmap is a series of points (bits) arranged like a map so that, when put together, they
produce a picture that can be written to, copied from, re-arranged, changed, manipulated,
or stored as a a computer file. Bitmaps are used to display pictures on graphical
applications, word processors, database files, or audience presentations. To display its
product on a device such as a monitor or a printer, a bitmap holds some properties and
follows a set of rules.

There are various types of bitmaps, based on the number of colors that the bitmap can
display. First of all, a bitmap can be monochrome, in which case each pixel corresponds
to 1 bit. A bitmap can also be colored. The number of colors that a bitmap can display is
equal to 2 raised to the number of pits/pixel. For example, a simple bitmap uses only 4
bits/pixel or 4 bpp can handle only 24 = 16 colors. A more enhanced bitmap that requires
8 bpp can handle 28 = 256 colors. Bitmaps are divided in two categories that control their
availability to display on a device.

A device-independent bitmap (DIB) is a bitmap that is designed to be loaded on any


application or display on any device and produce the same visual effect. To make this
possible, such a bitmap contains a table of colors that describes how the colors of the
bitmap should be used on pixels when displaying it. The characteristics of a DIB are
defined by the BITMAPINFO structure.

A device-dependent bitmap (DDB) is a bitmap created from the BITMAP structure using
the dimensions of the bitmap.

138
4.5.1 Bitmap Creation

Unlike the other GDI tools, creating a bitmap usually involves more steps. For example,
you may want to create a bitmap to display on a window. You may create another bitmap
to paint a geometric area, in which case the bitmap would be used as a brush.

Before creating a bitmap as a GDI object, you should first have a bitmap. You can do this
by defining an array of unsigned hexadecimal numbers. Such a bitmap can be used for a
brush. Once your bitmap is ready, call the LoadBitmap function. Its syntax is:

HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);

The hInstance argument is the instance of the application that contains the bitmap you
want to use.

The lpBitmapName argument is the string that determines where the bitmap file is
located. If you had imported the bitmap, you can use the MAKEINTRESOURCE macro
to convert this string.

Before selecting the newly created bitmap object, allocate a block of computer memory
that would hold the bitmap. You can then copy it to the actual device. This job can be
taken care of by the CreateCompatibleDC function. Its syntax is:

HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight);

This function takes a pointer to a device context. If it is successful, it returns TRUE or a


non-zero value. If it is not, it returns FALSE or 0.

Now let us see how a bitmap image can be used in your windows program.

Program 4.9: Embedding bitmap resource in a window.

1. Start Microsoft VC++ to create a new Win32 Project and name it Bitmap1.
2. Create it as a Windows Application and Empty Project.
3. Save any bitmap image in your computer as penguin.bmp. For this program let
us make use of the following bitmap image in Figure 4.12.

Figure 4.12 Penguin Bitmap image

139
4. On the main menu, click Insert -> Resource... and select Bitmap resource
5. Then click the Import... button
6. Locate the above picture from your computer and import it
7. In the Properties window, change its ID to IDB_PENGUIN
8. Save the resource. Save the resource script as Penguin.rc then add it to your
project (Project -> Add To Project -> Files... and select the file Penguin.rc)
9. Add a new C++ (Source) File named Penguin and implement it as follows:

#include <windows.h>
#include "Resource.h"

HINSTANCE hInst;
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam,
LPARAM lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndCls;
static char szAppName[] = "BitmapIntro";
MSG Msg;

hInst = hInstance;
WndCls.cbSize = sizeof(WndCls);
WndCls.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
WndCls.lpfnWndProc = WindProcedure;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hInstance = hInst;
WndCls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = szAppName;
WndCls.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);

CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szAppName,
"Bitmaps Fundamentals",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);

while( GetMessage(&Msg, NULL, 0, 0) )


{
TranslateMessage(&Msg);
DispatchMessage( &Msg);

140
}

return static_cast<int>(Msg.wParam);
}

LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,


WPARAM wParam, LPARAM lParam)
{
HDC hDC, MemDCPenguin;
PAINTSTRUCT Ps;
HBITMAP bmpPenguin;

switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);

// Load the bitmap from the resource


bmpPenguin = LoadBitmap(hInst,
MAKEINTRESOURCE(IDB_PENGUIN));

// Create a memory device compatible with the above DC variable


MemDCPenguin = CreateCompatibleDC(hDC);

// Select the new bitmap


SelectObject(MemDCPenguin, bmpPenguin);

// Copy the bits from the memory DC into the current dc


BitBlt(hDC, 10, 10, 450, 400, MemDCPenguin, 0, 0, SRCCOPY);

// Restore the old bitmap


DeleteDC(MemDCPenguin);
DeleteObject(bmpPenguin);
EndPaint(hWnd, &Ps);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

10. Test the application and you’ll find an output window as shown in Figure 4.13.

141
Figure 4.13 Using bitmap resources

11. Return to your programming environment

4.6 Fonts

A font is a list of symbols that can be drawn on a device context to produce a symbol. A
font is designed by an artist but usually follows a specific pattern.

4.6.1 Font Selection

Before using a font to draw a symbol on a device, the font must have been installed.
Microsoft Windows installs many fonts during setup. To handle its various assignments,
the operating system uses a particular font known as the System Font. This is the font
used to display the menu items and other labels for resources in applications. If you want
to use a different font to draw text in your application, you must select it.

Selecting a font, as well as selecting any other GDI object, is equivalent to specifying the
characteristics of a GDI object you want to use. To do this, you must first create the
object, unless it exists already. To select an object, pass it as a pointer to the SelectObject
function. The syntax of this function is:

HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj);

This function takes as argument the font you want to use, hgdiobj. It returns a pointer to
the font that was previously selected. If there was a problem when selecting the font, the
function returns NULL. As you can see, you must first have a font you want to select.

142
4.6.2 Regular Font Creation

A font in Microsoft Windows is stored as an HFONT value. To Create a font, you can
use the CreateFont function. Its syntax is:

HFONT CreateFont(
int nHeight,
int nWidth,
int nEscapement,
int nOrientation,
int fnWeight,
DWORD fdwItalic,
DWORD fdwUnderline,
DWORD fdwStrikeOut,
DWORD fdwCharSet,
DWORD fdwOutputPrecision,
DWORD fdwClipPrecision,
DWORD fdwQuality,
DWORD fdwPitchAndFamily,
LPCTSTR lpszFace
);

The nHeight argument is the height applied to the text.

The nWidth value is the desired width that will be applied on the text.

The nEscapement is the angle used to orient the text. The angle is calculated as a multiple
of 0.1 and oriented counterclockwise.

The nOrientation is the angular orientation of the text with regards to the horizontal axis.

The nWeight is used to attempt to control the font weight of the text because it is affected
by the characteristics of the font as set by the designer. It holds values that displays text
from thin heavy bold. The possible values are:

Constant Value
FW_DONTCARE 0
FW_THIN 100
FW_EXTRALIGHT 200
FW_ULTRALIGHT 200
FW_LIGHT 300
FW_NORMAL 400
FW_REGULAR 400
FW_MEDIUM 500
FW_SEMIBOLD 600
FW_DEMIBOLD 600

143
FW_BOLD 700
FW_EXTRABOLD 800
FW_ULTRABOLD 800
FW_BLACK 900
FW_HEAVY 900

The bItalic specifies whether the font will be italicized (TRUE) or not (FALSE).

The bUnderline is used to underline (TRUE) or not underline (FALSE) the text.

The cStrikeOut is specifies whether the text should be stroke out (TRUE) or not (FALSE)
with a line.

The nCharSet, specifies the character set used. The possible values are:

Constant Description
FF_DECORATIVE Used for a decorative or fancy font
FF_DONTCARE Let the compiler specify
Modern fonts that have a constant
FF_MODERN
width
FF_ROMAN Serif fonts with variable width
FF_SCRIPT Script-like fonts
Sans serif fonts with variable
FF_SWISS
width

The nOutPrecision controls the amount precision used to evaluate the numeric values
used on this function for the height, the width, and angles. It can have one of the
following values: OUT_CHARACTER_PRECIS, OUT_STRING_PRECIS,
OUT_DEFAULT_PRECIS, OUT_STROKE_PRECIS, OUT_DEVICE_PRECIS,
OUT_TT_PRECIS, OUT_RASTER_PRECIS.

If some characters may be drawn outside of the area in which they are intended, the
nClipPrecision is used to specify how they may be clipped. The possible value used are
CLIP_CHARACTER_PRECIS, CLIP_MASK, CLIP_DEFAULT_PRECIS,
CLIP_STROKE_PRECIS, CLIP_ENCAPSULATE, CLIP_TT_ALWAYS,
CLIP_LH_ANGLES.

The nQuality specifies how the function will attempt to match the font's characteristics.
The possible values are DEFAULT_QUALITY, PROOF_QUALITY, and
DRAFT_QUALITY.

The nPitchAndFamily specifies the category of the font used. It combines the pitch and
the family the intended font belongs to. The pitch can be specified with
DEFAULT_PITCH, VARIABLE_PITCH, or FIXED_PITCH. The pitch is combined
using the bitwise OR operator with one of the following values:

144
Constant Value
ANSI_CHARSET 0
DEFAULT_CHARSET 1
SYMBOL_CHARSET 2
SHIFTJIS_CHARSET 128
OEM_CHARSET 255

The lpszFacename is the name of the font used.

Once you have created a font, you can select it into the device context and use it it for
example to draw text. After using a font, you should delete it to reclaim the memory
space its variable was using. This is done by calling the DeleteObject function.

Program 4.10: Creating a font and writing a text in the window.

1. Start the Microsoft Development Environment by clicking Start Programs


Microsoft Visual Studio 6.0 Microsoft Visual C++.
2. On the main menu, click File -> New... or File -> New -> Project...
3. In the New or New Project dialog box, click either Win32 Application.
4. In the location, type the path where the application should be stored, such as
“C:\Programs\MSVC”
5. In the Name edit box, type the name of the application as FontDraw and click
OK.
6. In the next dialog box of the wizard, click the An Empty Project radio button.
7. Click Finish. You will be presented with another dialog box; in this case click
OK.
8. To create the first needed file of the program, on the main menu, click File ->
New.
9. In the Name edit box, replace the contents with a name for a file. In the case,
replace it with Main and press Enter.
10. Enter the following lines of code in the code window area:

#include <windows.h>

LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam,


LPARAM lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,


LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WndCls;
static char szAppName[] = "FontExercise";
MSG Msg;

WndCls.cbSize = sizeof(WndCls);
WndCls.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;

145
WndCls.lpfnWndProc = WindProcedure;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hInstance = hInstance;
WndCls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = szAppName;
WndCls.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);

CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
szAppName, "Fonts Fundamentals",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 450, 220,
NULL, NULL, hInstance, NULL);

while( GetMessage(&Msg, NULL, 0, 0) )


{
TranslateMessage(&Msg);
DispatchMessage( &Msg);
}

return static_cast<int>(Msg.wParam);
}

LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,


WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
HFONT font;

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);

font = CreateFont(46, 28, 215, 0,


FW_NORMAL, FALSE, FALSE, FALSE,
ANSI_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_ROMAN,
"Times New Roman");

SelectObject(hDC, font);
TextOut(hDC, 20, 128, "Its my Font", 12);
DeleteObject(font);

EndPaint(hWnd, &Ps);
break;

case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;

146
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

11. Test the application and you’ll find an output window as shown Figure4.14.

Figure 4.14 Using Fonts

12. Return to your programming environment

Remember that once an object such as a font has been selected, it remains in the device
context until further notice. For example, if you have created and selected a font, any text
you draw would follow the characteristics of that font. If you want another font, you must
change the previously selected font.

The computer uses the default black color to draw the text. If you want to draw text with
a different color, you can first call the SetTextColor function and specify the color of
your choice.

4.6.3 Logical Font Creation

The CreateFont function is used to specify all characteristics of a font in one step.
Alternatively, if you want to specify each font property, you can declare a LOGFONT
variable and initialize it. It is defined as follows:

typedef struct tagLOGFONT {


LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight;
BYTE lfItalic;
BYTE lfUnderline;
BYTE lfStrikeOut;

147
BYTE lfCharSet;
BYTE lfOutPrecision;
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE];
} LOGFONT, *PLOGFONT;

This time, you do not have to provide a value for each member of the structure and even
if you do, you can supply values in the order of your choice. For any member whose
value is not specified, the compiler would use a default value but you may not like some
the result. Therefore, you should specify as many values as possible.

After initializing the LOGFONT variable, call the CreateFontIndirect function. Its
syntax is:

BOOL CreateFontIndirect(const LOGFONT* lpLogFont);

When calling this member function, pass the LOGFONT variable as a pointer,
lpLogFont.

To select the newly created font, call the SelectObject function. Once done, you can use
the new font as you see fit.

Program 4.11: Creating and using a logical font.

1. Replace the Window Procedure in program4.10 by the following lines of codes:


LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
HFONT font;
LOGFONT LogFont;

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);

LogFont.lfStrikeOut = 0;
LogFont.lfUnderline = 0;
LogFont.lfHeight = 42;
LogFont.lfEscapement = 0;
LogFont.lfItalic = TRUE;

font = CreateFontIndirect(&LogFont);
SelectObject(hDC, font);
TextOut(hDC, 20, 18, "Center for Dist. Education", 26);

DeleteObject(font);

148
EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find a window as shown in Figure 4.15.

Figure 4.15 Creating and using logical fonts

3. Return to your programming environment

4.7 Pens

A pen is a tool used to draw lines and curves on a device context. In the graphics
programming, a pen is also used to draw the borders of a geometric closed shape such as
a rectangle or a polygon.

To make it an efficient tool, a pen must produce some characteristics on the lines it is
asked to draw. These characteristics can range from the width of the line drawn to their
colors, from the pattern applied to the level of visibility of the lines. To manage these
properties, Microsoft Windows considers two types of pens: cosmetic and geometric.

 A pen is referred to as cosmetic when it can be used to draw only simple lines of a
fixed width, less than or equal to 1 pixel.
 A pen is geometric when it can assume different widths and various ends.

4.7.1 Creating and Selecting a Pen

149
To create a pen, you can call the CreatePen function. Its syntax is:

HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor);

The fnPenStyle argument is characteristic is referred to as the style of the pen. The
possible values of this argument are:

Value Illustration Description


PS_SOLID A continuous solid line
A continuous line with dashed
PS_DASH
interruptions
A line with a dot interruption
PS_DOT
at every other pixel
A combination of alternating
PS_DASHDOT
dashed and dotted points
A combination of dash and
PS_DASHDOTDOT
double dotted interruptions
PS_NULL No visible line
A line drawn just inside of the
PS_INSIDEFRAME
border of a closed shape

To specify the type of pen you are creating, as cosmetic or geometric, use the bitwise OR
operator to combine one of the above styles with one of the following:

 PS_COSMETIC: used to create a cosmetic pen


 PS_GEOMTERIC: used to create a geometric pen

If you are creating a cosmetic pen, you can also add (bitwise OR) the PS_ALTERNATE
style to to set the pen at every other pixel.

The nWidth argument is the width used to draw the lines or borders of a closed shape. A
cosmetic pen can have a width of only 1 pixel. If you specify a higher width, it would be
ignored. A geometric pen can have a width of 1 or more pixels but the line can only be
solid or null. This means that, if you specify the style as PS_DASH, PS_DOT,
PS_DASHDOT, or PS_DASHDOTDOT but set a width higher than 1, the line would
be drawn as PS_SOLID.

The default color of pen on the device context is black. If you want to control the color,
specify the desired value for the crColor argument.

After creating a pen, you can select it into the desired device context variable and then
use it as you see fit, such as drawing a rectangle.

After using a pen, between exiting the function or event that created it, you should get rid
of it and restore the pen that was selected previously. This is done by calling the
DeleteObject function.

150
Program 4.12: Creating a pen and drawing in the window.

1. Do the fowling changes in program4.10:


a. Change the static char szAppName[] = "PenExercise";
b. Change the 3rd parameter of the CreateWindow method to “Pen
Fundamentals”.
c. Replace the Window Procedure in previous program by the following
lines of codes:
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
HPEN hPen;

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);

hPen = CreatePen(PS_DASHDOTDOT, 1, RGB(255, 25, 5));


SelectObject(hDC, hPen);
Rectangle(hDC, 20, 22, 250, 125);
DeleteObject(hPen);

EndPaint(hWnd, &Ps);
break;
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find the output window as in Figure4.16

Figure 4.16 Using Pen Objects

151
3. Return to your programming environment by clicking the close button the output
window.

4.8 Brushes

A brush is a drawing tool used to fill out closed shapes or the interior of lines. Using a
brush is like picking up a bucket of paint and pouring it somewhere. In the case of
computer graphics, the area where you position the brush is called the brush origin. The
color or pattern that the brush holds would be used to fill the whole area until the brush
finds a limit set by some rule.

A brush can be characterized by its color (if used), its pattern used to fill the area, or a
picture (bitmap) used as the brush.

Because there can be so many variations of brushes, there are different functions for the
various possible types of brushes you would need. The easiest brush you can create is
made of a color.

4.8.1 Solid Brushes

A brush is referred to as solid if it is made of a color simply used to fill a closed shape.
To create a solid brush, call the CreateSolidBrush function. Its syntax is:

HBRUSH CreateSolidBrush(COLORREF crColor);

The color to provide as the crColor argument follows the rules we reviewed for colors.

To use the newly created brush, you can select it into the device context by calling the
SelectObject function. Any closed shape you draw (ellipse, rectangle, polygon) would be
filled with the color specified. After using the brush, you can delete it and restore the
previous brush.

Program 4.13: Creating a brush object and drawing in the window.

1. Do the following changes in program4.10:


a. Change the static char szAppName[] = "BrushExercise";
b. Change the 3rd parameter of the CreateWindow method to “GDI Brush
Fundamentals”.
c. Replace the Window Procedure in previous program by the following
lines of codes:
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
HBRUSH BrushGreen = CreateSolidBrush(RGB(0, 125, 5));

152
HBRUSH BrushRed = CreateSolidBrush(RGB(255, 2, 5));
HBRUSH BrushYellow = CreateSolidBrush(RGB(250, 255, 5));
HBRUSH BrushBlue = CreateSolidBrush(RGB(0, 2, 255));

POINT Pt[3];

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);

// Top Triangle
Pt[0].x = 125; Pt[0].y = 10;
Pt[1].x = 95; Pt[1].y = 70;
Pt[2].x = 155; Pt[2].y = 70;

SelectObject(hDC, BrushGreen);
Polygon(hDC, Pt, 3);

// Left Triangle
Pt[0].x = 80; Pt[0].y = 80;
Pt[1].x = 20; Pt[1].y = 110;
Pt[2].x = 80; Pt[2].y = 140;

SelectObject(hDC, BrushRed);
Polygon(hDC, Pt, 3);

// Bottom Triangle
Pt[0].x = 95; Pt[0].y = 155;
Pt[1].x = 125; Pt[1].y = 215;
Pt[2].x = 155; Pt[2].y = 155;

SelectObject(hDC, BrushYellow);
Polygon(hDC, Pt, 3);

// Right Triangle
Pt[0].x = 170; Pt[0].y = 80;
Pt[1].x = 170; Pt[1].y = 140;
Pt[2].x = 230; Pt[2].y = 110;

SelectObject(hDC, BrushBlue);
Polygon(hDC, Pt, 3);

DeleteObject(BrushGreen);
DeleteObject(BrushRed);
DeleteObject(BrushYellow);
DeleteObject(BrushBlue);

EndPaint(hWnd, &Ps);
break;

case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;

153
default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find the following output as in Figure4.17 on the
window:

Figure 4.17 Using Brush Objects

3. Return to your programming environment by clicking the close button the output
window.

4.8.2 Hatched Brushes

A hatch brush is one that uses a drawn hatch pattern to regularly fill an area. Microsoft
Windows provides 6 preset patterns for such a brush. To create a hatched brush, you can
call the CreateHatchBrush() function. Its syntax is:

HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);

The fnStyle argument specifies the hatch style that must be used to fill the area. The
possible values to use are HS_BDIAGONAL, HS_CROSS, HS_DIAGCROSS,
HS_FDIAGONAL, HS_HORIZONTAL, or HS_VERTICAL.

The clrref argument specifies the color applied on the drawn pattern.

Program 4.14: Creating a hatched brush object and drawing in the window.

1. Replace the Window Procedure in program4.13 by the following lines of codes:

154
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg,
WPARAM wParam, LPARAM lParam)
{
HDC hDC;
PAINTSTRUCT Ps;
HBRUSH brBDiagonal = CreateHatchBrush(HS_BDIAGONAL,RGB(0,0,255));
HBRUSH brCross = CreateHatchBrush(HS_CROSS, RGB(200, 0, 0));
HBRUSH brDiagCross = CreateHatchBrush(HS_DIAGCROSS,RGB(0,128,0));
HBRUSH brFDiagonal =CreateHatchBrush(HS_FDIAGONAL,RGB(0,128,192));
HBRUSH brHorizontal =CreateHatchBrush(HS_HORIZONTAL, RGB(255,128,0));
HBRUSH brVertical = CreateHatchBrush(HS_VERTICAL,RGB(255,0,255));

switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);

SelectObject(hDC, brBDiagonal);
RoundRect(hDC, 20, 30, 160, 80, 10, 10);

SelectObject(hDC, brFDiagonal);
RoundRect(hDC, 180, 30, 320, 80, 10, 10);

SelectObject(hDC, brDiagCross);
RoundRect(hDC, 340, 30, 480, 80, 10, 10);

SelectObject(hDC, brVertical);
RoundRect(hDC, 20, 120, 160, 170, 10, 10);

SelectObject(hDC, brHorizontal);
RoundRect(hDC, 180, 120, 320, 170, 10, 10);

SelectObject(hDC, brCross);
RoundRect(hDC, 340, 120, 480, 170, 10, 10);

SetTextColor(hDC, RGB(0, 0, 255));


TextOut(hDC, 40, 10, "HS_BDIAGONAL", 12);
SetTextColor(hDC, RGB(0, 128, 192));
TextOut(hDC, 205, 10, "HS_FDIAGONAL", 12);
SetTextColor(hDC, RGB(0, 128, 0));
TextOut(hDC, 355, 10, "HS_DIAGCROSS", 12);
SetTextColor(hDC, RGB(255, 0, 255));
TextOut(hDC, 44, 100, "HS_VERTICAL", 11);
SetTextColor(hDC, RGB(255, 128, 0));
TextOut(hDC, 195, 100, "HS_HORIZONTAL", 13);
SetTextColor(hDC, RGB(200, 0, 0));
TextOut(hDC, 370, 100, "HS_CROSS", 8);

DeleteObject(brBDiagonal);
DeleteObject(brCross);
DeleteObject(brDiagCross);
DeleteObject(brFDiagonal);
DeleteObject(brHorizontal);
DeleteObject(brVertical);

EndPaint(hWnd, &Ps);

155
break;

case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;

default:
return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

2. Test the program and you’ll find the following output on the window as in Figure
4.18.

Figure 4.18 Hatched Brushes

3. Return to your programming environment by clicking the close button the output
window.

156
CHAPTER 5

WORKING WITH CONTROLS

5.1 Introduction

Some of the things that you will find in just about every Windows application are
buttons, check boxes, text fields, and drop-down list boxes. These are known as controls,
and many of these controls are built into the operating system itself. With Visual C++,
using these common controls is as easy as placing them on a dialog window with a drag-
and-drop window design method.

Use the control palette to add each control. (If the control palette is not visible, right-click
any toolbar and choose “Controls” from the list.) Drag controls from the control palette to
the new dialog, and then position and size the controls. The control palette in VC++
environment is shown in Figure 5.1.

Figure 5.1 Control palette and standard controls

Now let’s use some of these standard controls to create a dialog application that invokes
another application.

Program 5.1: Dialog application that invokes another application.

1. Create a new AppWizard workspace project, calling the project ExCtrl.


2. In Step 1 of the AppWizard, specify that you want to create a Dialog-based
application. Click Next at the bottom of the wizard.
3. In Step 2 of the AppWizard, the wizard asks you about a number of features that
you can include in your application. You can uncheck the option for including
support for ActiveX controls if you will not be using any ActiveX controls in your
application. Because you won't be using any ActiveX controls in today's
application, go ahead and uncheck this box.
4. In the field near the bottom of the wizard, type in the title that you want to appear
in the title bar of the main application window, such as “Exercise on VC++”.
Click next at the bottom of the wizard.

157
5. In Step 3 of the AppWizard, leave the defaults for including source file comments
and using the MFC library as a DLL. Click Next at the bottom of the wizard to
proceed to the final AppWizard step.
6. The final step of the AppWizard shows you the C++ classes that the AppWizard
will create for your application. Click Finish to let AppWizard generate your
application shell.
7. Before AppWizard creates your application shell, it presents you with a list of
what it is going to put into the application shell, based on the options you selected
when going through the AppWizard. Click OK and AppWizard generates your
application.
8. After you create the application shell, design the main dialog as shown in Figure
5.1:

Figure 5.1 Main Dialog in design mode

9. Configure the control properties as specified below:


Object Property Setting
Static Text ID IDC_STATIC
Caption This is an example of a Visual C++
Application using a number of controls.
Static Text ID IDC_STATICMSG
Caption Enter a &Message:
Static Text ID IDC_STATICPGM
Caption Run a &Program:
Edit Box ID IDC_MSG
Button ID IDC_SHWMSG
Caption &Show Message

158
Button ID IDC_DFLTMSG
Caption &Default Message
Button ID IDC_CLRMSG
Caption &Clear Message
Button ID IDC_RUNPGM
Caption &Run Program
Button ID IDC_EXIT
Caption E&xit
Combo Box ID IDC_PROGTORUN
Group Box ID IDC_STATIC
Caption Enable Actions
Group Box ID IDC_STATIC
Caption Show Actions
Check Box ID IDC_CKENBLMSG
Caption &Enable Message Action
Check Box ID IDC_CKENBLPGM
Caption E&nable Program Action
Check Box ID IDC_CKSHWMSG
Caption S&how Message Action
Check Box ID IDC_CKSHWPGM
Caption Sh&ow Program Action

10. After you place all these controls on the dialog window and configure all their
properties, reopen the properties dialog for the combo box that you placed on the
window. On the Data tab of the properties dialog, enter the following values:
Notepad
Paint
Solitaire
using a Control+Enter key combination to add the second and third items, as
shown in Figure 5.2.

Figure 5.2 Combo Box Property Window

159
Before you can begin coding, you have to assign variables to each of the controls
that will have a value attached--everything except the static text and the command
buttons. You will interact with these variables when you write the code for your
application. The values that the user enters into the screen controls are placed into
these variables for use in the application code. Likewise, any values that your
application code places into these variables are updated in the controls on the
window for the user to see. To do this follow the steps given below:

10. Open the Class Wizard by pressing Ctrl + W.

11. Select the Member Variables tab, as shown in Figure5.3:

Figure 5.3 Class Wizard

12. Select the ID of one of the controls that you need to attach a variable to, such as
IDC_MSG.

13. Click the Add Variable button.

14. In the Add Member Variable dialog, enter the variable name, specifying the
category and variable type, as shown in Figure 5.4 and Click OK.

160
Figure 5.4 Add Member Variable Window

15. Repeat steps 12 through 14 for all the other controls for which you need to
add variables. You should add the variables for your application as listed below:

Control Variable Name Category Type


IDC_MSG m_strMessage Value CString
IDC_PROGTORUN m_strProgToRun Value CString
IDC_CKENBLMSG m_bEnableMsg Value BOOL
IDC_CKENBLPGM m_bEnablePgm Value BOOL
IDC_CKSHWMSG m_bShowMsg Value BOOL
IDC_CKSHWPGM m_bShowPgm Value BOOL

16. After you add all the necessary variables, click the OK button to close the Class
Wizard.

Before you begin adding code to all the controls on your application window, you need to
add a little bit of code to initialize the variables, setting starting values for most of them.
Do this by following these steps:

17. Using the Class Wizard, on the Message Maps tab, select the OnInitDialog
function in the list of member functions. You can do this by finding the function
in the Member Functions list, or by selecting the CExCtrlDlg object in the list of
object IDs and then selecting the WM_INITDIALOG message in the messages
list.

18. Click Edit Code to be taken to the source code for the OnInitDialog function.

161
19. Find the TODO marker, which indicates where to begin adding your code, and
add the following code:
BOOL CExCtrlDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// TODO: Add extra initialization here

// Put a default message in the message edit

m_strMessage = "Place a message here";

// Set all of the check boxes to checked


m_bShowMsg = TRUE;
m_bShowPgm = TRUE;
m_bEnableMsg = TRUE;
m_bEnablePgm = TRUE;

// Update the dialog with the values


UpdateData(FALSE);

return TRUE; // return TRUE unless you set the focus to a


}

The first thing that you want to take care of is making sure that the user can close your
application. Because you deleted the OK and Cancel buttons and added a new button for
closing the application window, you need to place code into the function called by the
Exit button to close the window. To do this, follow these steps:

20. Using the Class Wizard, add a function for the IDC_EXIT object on the
BN_CLICKED message.
21. Click the Edit Code button to take you to the new function that you just added.
22. Enter the code given below:
void CExCtrlDlg::OnExit()
{
// TODO: Add your control notification handler code here

// Exit the program


OnOK();

}
23. Add a function OnShwmsg to the Show Message button and call the MessageBox
function, as shown below:

void CExCtrlDlg::OnShwmsg()
{
// TODO: Add your control notification handler code here

// Update the message variable with what the user entered


UpdateData(TRUE);

162
// Display the message for the user
MessageBox(m_strMessage);

24. If you prefer the edit box to be cleared before you type a message, you can attach
a function OnClrmsg to the Clear Message button to clear the contents. To do
this, add a function to the Clear Message button through the Class Wizard in the
usual way and enter the following code in that function:
void CExCtrlDlg::OnClrmsg()
{
// TODO: Add your control notification handler code here

// Clear the message


m_strMessage = "";

// Update the screen


UpdateData(FALSE);

25. Add functionality to the Enable Message Action and Show Message Action check
boxes. The first of these check boxes enables or disables the controls dealing with
displaying the user message. When the check box is in a checked state, the
controls are all enabled. When the check box is in an unchecked state, all those
same controls are disabled. In a likewise fashion, the second check box shows and
hides this same set of controls. The code for these two functions is as shown
below:

void CExCtrlDlg::OnCkenblmsg()
{
// TODO: Add your control notification handler code here

// Get the current values from the screen


UpdateData(TRUE);

// Is the Enable Message Action check box checked?


if (m_bEnableMsg == TRUE)
{
// Yes, so enable all controls that have anything
// to do with showing the user message
GetDlgItem(IDC_MSG)->EnableWindow(TRUE);
GetDlgItem(IDC_SHWMSG)->EnableWindow(TRUE);
GetDlgItem(IDC_DFLTMSG)->EnableWindow(TRUE);
GetDlgItem(IDC_CLRMSG)->EnableWindow(TRUE);
GetDlgItem(IDC_STATICMSG)->EnableWindow(TRUE);
}
else
{
// No, so disable all controls that have anything
// to do with showing the user message
GetDlgItem(IDC_MSG)->EnableWindow(FALSE);
GetDlgItem(IDC_SHWMSG)->EnableWindow(FALSE);

163
GetDlgItem(IDC_DFLTMSG)->EnableWindow(FALSE);
GetDlgItem(IDC_CLRMSG)->EnableWindow(FALSE);
GetDlgItem(IDC_STATICMSG)->EnableWindow(FALSE);
}

void CExCtrlDlg::OnCkshwmsg()
{
// TODO: Add your control notification handler code here

// Get the current values from the screen


UpdateData(TRUE);

// Is the Show Message Action check box checked?


if (m_bShowMsg == TRUE)
{
// Yes, so show all controls that have anything
// to do with showing the user message
GetDlgItem(IDC_MSG)->ShowWindow(TRUE);
GetDlgItem(IDC_SHWMSG)->ShowWindow(TRUE);
GetDlgItem(IDC_DFLTMSG)->ShowWindow(TRUE);
GetDlgItem(IDC_CLRMSG)->ShowWindow(TRUE);
GetDlgItem(IDC_STATICMSG)->ShowWindow(TRUE);
}
else
{
// No, so hide all controls that have anything
// to do with showing the user message
GetDlgItem(IDC_MSG)->ShowWindow(FALSE);
GetDlgItem(IDC_SHWMSG)->ShowWindow(FALSE);
GetDlgItem(IDC_DFLTMSG)->ShowWindow(FALSE);
GetDlgItem(IDC_CLRMSG)->ShowWindow(FALSE);
GetDlgItem(IDC_STATICMSG)->ShowWindow(FALSE);
}

26. Finally create the function for the Run Program button using the Class Wizard,
and add the code given below to the function:

void CExCtrlDlg::OnRunpgm()
{
// TODO: Add your control notification handler code here

// Get the current values from the screen


UpdateData(TRUE);

// Declare a local variable for holding the program name


CString strPgmName;

// Copy the program name to the local variable


strPgmName = m_strProgToRun;

// Make the program name all uppercase

164
strPgmName.MakeUpper();

// Did the user select to run the Paint program?


if (strPgmName == "PAINT")
// Yes, run the Paint program
WinExec("pbrush.exe", SW_SHOW);

// Did the user select to run the Notepad program?


if (strPgmName == "NOTEPAD")
// Yes, run the Notepad program
WinExec("notepad.exe", SW_SHOW);

// Did the user select to run the Solitaire program?


if (strPgmName == "SOLITAIRE")
// Yes, run the Solitaire program
WinExec("sol.exe", SW_SHOW);

27. Test the program and see how it works.

165
CHAPTER 6

CARETS

6.1 Introduction

When you type text into a program, generally a little underline, vertical bar, or box shows
you where the next character you type will appear on the screen. You may know this as a
"cursor," but you'll have to get out of that habit when programming for Windows. In
Windows, it's called the "caret." The word "cursor" is reserved for the little bitmap image
that represents the mouse position.

6.1.1 The Caret Functions

There are five essential caret functions:


 CreateCaret Creates a caret associated with a window.
 SetCaretPos Sets the position of the caret within the window.
 ShowCaret Shows the caret.
 HideCaret Hides the caret.
 DestroyCaret Destroys the caret.

There are also functions to get the current caret position (GetCaretPos) and to get and set
the caret blink time (GetCaretBlinkTime and SetCaretBlinkTime).

In Windows, the caret is customarily a horizontal line or box that is the size of a
character, or a vertical line that is the height of a character. The vertical line caret is
recommended when you use a proportional font such as the Windows default system
font. Because the characters in a proportional font are not of a fixed size, the horizontal
line or box can't be set to the size of a character.

If you need a caret in your program, you should not simply create it during the
WM_CREATE message of your window procedure and destroy it during the
WM_DESTROY message. The reason this is not advised is that a message queue can
support only one caret. Thus, if your program has more than one window, the windows
must effectively share the same caret.

The main rule for using the caret is simple: a window procedure calls CreateCaret during
the WM_SETFOCUS message and DestroyWindow during the WM_KILLFOCUS
message.

There are a few other rules: The caret is created hidden. After calling CreateCaret, the
window procedure must call ShowCaret for the caret to be visible. In addition, the
window procedure must hide the caret by calling HideCaret whenever it draws something
on its window during a message other than WM_PAINT. After it finishes drawing on the
window, the program calls ShowCaret to display the caret again. The effect of HideCaret

166
is additive: if you call HideCaret several times without calling ShowCaret, you must call
ShowCaret the same number of times before the caret becomes visible again.

Program 6.1: Creating a Blinking Cursor.

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name Carets in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Single Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CCaretsApp,
CMainFrame, CCaretsDoc, CCaretsView .
7. Declare the StringData variable on the document’s header file, CaretsDoc.h, in the
protected part.
class CCaretsDoc : public CDocument
{
protected: // create from serialization only
CCaretsDoc();
DECLARE_DYNCREATE(CCaretsDoc)
CString StringData;
.
.
};
8. Initialize that string to an empty string in the document’s constructor, which we
find in CaretsDoc.cpp.

CCaretsDoc::CCaretsDoc()
{
StringData=" ";
// TODO: add one-time construction code here
}

9. Add a new event handler OnChar to our view class which is called every time the
user types the character.
10. The character the user typed is now in the nChar parameter, which we store in the
our data string object, StringData. The object in our document, so we need a
pointer(pDoc) to our document object.
11. Add the character nChar to the string StringData.

void CCaretsView::OnChar(UINT nChar, UINT nRepCnt,


UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CCaretsDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData+=nChar;
Invalidate();
CView::OnChar(nChar, nRepCnt, nFlags);
}

167
12. Set a boolean variable named CaretCreated in view object to keep track that caret
has been created or not, a CPoint type variable CaretPosition and finally two
integer variables x and y respectively to holds the position of Caret.
class CCaretsView : public CView
{
protected: // create from serialization only
CCaretsView();
DECLARE_DYNCREATE(CCaretsView)
CPoint CaretPosition;
int x,y;
boolean CaretCreated;
// Attributes
.
.
};

13. Set CaretCreated to false in the View’s Constructor.

CCaretsView::CCaretsView()
{
CaretCreated=false;
// TODO: add construction code here
}

14. We’re ready to create our new caret. We’ll make the caret the same height and
width as our text. We call CreateSolidCaret() to actually create the caret.
15. Initially, set caret’s position to (0,0) in OnDraw method.
16. We set the caret’s position with SetCaretPos( ), show caret on the screen with
ShowCaret( ), and set the CaretCreated Boolean flag to true.
17. In next step the caret is to move as the user types text.
18. Place the caret at the end of displayed text string.
19. To display the caret at the end of the text string, we first hide it using HideCaret(
).
20. Set the CaretPosition & Show the Caret using the following lines of code:

void CCaretsView::OnDraw(CDC* pDC)


{
CCaretsDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(!CaretCreated)
{
TEXTMETRIC textmetric;
pDC->GetTextMetrics(&textmetric);

CreateSolidCaret(textmetric.tmAveCharWidth/8, textmetric.tmHeight);
CaretPosition.x=CaretPosition.y=0;
SetCaretPos(CaretPosition);
ShowCaret();
CaretCreated=true;
}

168
pDC->TextOut(x,y,pDoc->StringData);

CSize size=pDC->GetTextExtent(pDoc->StringData);
HideCaret();
CaretPosition.x=x+size.cx;
CaretPosition.y=y;
SetCaretPos(CaretPosition);
ShowCaret();

// TODO: add draw code for native data here


}

21. To handle left mouse button down we select LButtonDown, point parameter, an
Object of the CPoint class, holds mouse’s present location.
22. Store the variables in x & y.

void CCaretsView::OnLButtonDown(UINT nFlags, CPoint point)


{
// TODO: Add your message handler code here and/or call default
x=point.x;
y=point.y;

CCaretsDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData.Empty();
Invalidate();
CView::OnLButtonDown(nFlags, point);
}

23. Test the application and observe the output window as you type some text.

169
CHAPTER 7

USING MENUS, KEYBOARD ACCELERATORS, STATUS AND


TOOL BAR

7.1 Windows Menus

A Microsoft Windows menu is a familiar application element that consists of a top-level


horizontal list of items with associated pop-up menus that appear when the user selects a
top-level item. Most of the time, you define for a frame window a default menu resource
that loads when the window is created. You can also define a menu resource independent
of a frame window. In that case, your program must call the functions necessary to load
and activate the menu.

A menu resource completely defines the initial appearance of a menu. Menu items can be
grayed or have check marks, and bars can separate groups of menu items. Multiple levels
of pop-up menus are possible. If a first-level menu item is associated with a subsidiary
pop-up menu, the menu item carries a right-pointing arrow symbol.

Visual C++ includes an easy-to-use menu-resource editing tool. This tool lets you edit
menus in a wysiwyg environment. Each menu item has a properties dialog that defines all
the characteristics of that item. The resulting resource definition is stored in the
application's resource script (RC) file. Each menu item is associated with an ID, such as
ID_FILE_OPEN, that is defined in the resource.h file.

The MFC library extends the functionality of the standard menus for Windows. Each
menu item can have a prompt string that appears in the frame's status bar when the item is
highlighted. These prompts are really Windows string resource elements linked to the
menu item by a common ID. From the point of view of the menu editor and your
program, the prompts appear to be part of the menu item definition.

7.2 Keyboard Accelerators

You've probably noticed that most menu items contain an underlined letter. In Visual
C++ (and most other applications), pressing Alt-F followed by S activates the File Save
menu item. This shortcut system is the standard Windows method of using the keyboard
to choose commands from menus. If you look at an application's menu resource script (or
the menu editor's properties dialog), you will see an ampersand (&) preceding the
character that is underlined in each of the application's menu items.

Windows offers an alternative way of linking keystrokes to menu items. The keyboard
accelerator resource consists of a table of key combinations with associated command
IDs. The Edit Copy menu item (with command ID ID_EDIT_COPY), for example, might
be linked to the Ctrl-C key combination through a keyboard accelerator entry. A
keyboard accelerator entry does not have to be associated with a menu item. If no Edit

170
Copy menu item were present, the Ctrl-C key combination would nevertheless activate
the ID_EDIT_COPY command.

Program 7.1: Creating a pop-up menu named Transfer, move data between the view
object and the document object, and a Clear Document menu item to erase the
document's contents.

1. Run AppWizard to generate a project named Menu. Accept all the default
settings but two: select Single Document and deselect Printing and Print Preview.
2. Use the resource editor to edit the application's main menu. Click on the
ResourceView tab in the Workspace window. Edit the IDR_MAINFRAME menu
resource to add a separator and a Clear Document item to the Edit menu, as
shown in Figure7.2-(a).

(a) (b)

Figure 7.2 Creating New Menus

Now add a Transfer menu, and then define the underlying items as shown in
Figure7.2-(b).

Use the following command IDs for your new menu items:

Menu Caption Command ID


Edit Clear &Document ID_EDIT_CLEAR_ALL
Transfer &Get Data From Document\tF2 ID_TRANSFER_GETDATA
Transfer &Store Data In Document\tF3 ID_TRANSFER_STOREDATA

3. Use the resource editor to add keyboard accelerators. Open the


IDR_MAINFRAME accelerator table, and then use the insert key to add the
following items.
Accelerator ID Key
ID_TRANSFER_GETDATA VK_F2
ID_TRANSFER_STOREDATA VK_F3

171
4. Be sure to turn off the Ctrl, Alt, and Shift modifiers. The Accelerator edit screen
and Accel Properties dialog are shown in the Figure 7.2.

Figure 7.2 Setting Accelerator

5. Use ClassWizard to add the view class command and update command UI
message handlers. Select the CMenuView class, and then add the following
member functions.

Object ID Message Member Function


ID_TRANSFER_GETDATA COMMAND OnTransferGetData
ID_TRANSFER_STOREDATA COMMAND OnTransferStoreData
ID_TRANSFER_STOREDATA UPDATE_COMMAND_UI OnUpdateTransferStoreData

6. Use ClassWizard to add the document class command and update command
UI message handlers. Select the CMenuDoc class, and then add the following
member functions.

Object ID Message Member Function


ID_EDIT_CLEAR_ALL COMMAND OnEditClearDocument
ID_EDIT_CLEAR_ALL UPDATE_COMMAND_UI OnUpdateEditClearDocument

172
7. Add a CString data member to the CMenuDoc class. Edit the file MenuDoc.h
or use ClassView.

public:
CString m_strText;

8. Edit the document class member functions in MenuDoc.cpp. The


OnNewDocument function was generated by ClassWizard. Add the following
boldface code:

BOOL CMenuDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
m_strText = "Hello (from CMenuDoc::OnNewDocument)";
return TRUE;
}

The Edit Clear Document message handler sets m_strText to empty, and the
update command UI handler grays the menu item if the string is already empty.
Remember that the framework calls OnUpdateEditClearDocument when the Edit
menu pops up. Add the following boldface code:

void CMenuDoc::OnEditClearDocument()
{
m_strText.Empty();
}

void CMenuDoc::OnUpdateEditClearDocument(CCmdUI* pCmdUI)


{
pCmdUI->Enable(!m_strText.IsEmpty());
}

9. Add a CRichEditCtrl data member to the CMenuView class. Edit the file
MenuView.h or use ClassView.

public:
CRichEditCtrl m_rich;

10. Use ClassWizard to map the WM_CREATE and WM_SIZE messages in the
CMenuView class. The OnCreate function creates the rich edit control. The
control's size is 0 here because the view window doesn't have a size yet. The code
for the two handlers is shown below.

int CMenuView::OnCreate(LPCREATESTRUCT lpCreateStruct)


{
CRect rect(0, 0, 0, 0);
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
m_rich.Create(ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN |
WS_CHILD | WS_VISIBLE | WS_VSCROLL, rect, this, 1);
return 0; }

173
Windows sends the WM_SIZE message to the view as soon as the view's initial
size is determined and again each time the user changes the frame size. This
handler simply adjusts the rich edit control's size to fill the view client area. Add
the following boldface code:

void CMenuView::OnSize(UINT nType, int cx, int cy)


{
CRect rect;
CView::OnSize(nType, cx, cy);
GetClientRect(rect);
m_rich.SetWindowPos(&wndTop, 0, 0, rect.right - rect.left,
rect.bottom - rect.top, SWP_SHOWWINDOW);
}

11. Edit the menu command handler functions in MenuView.cpp. ClassWizard


generated these skeleton functions when you mapped the menu commands in step
4. The OnTransferGetData function gets the text from the document data member
and puts it in the rich edit control. The function then clears the control's modified
flag. There is no update command UI handler. Add the following boldface code:

void CMenuView::OnTransferGetData()
{
CMenuDoc* pDoc = GetDocument();
m_rich.SetWindowText(pDoc->m_strText);
m_rich.SetModify(FALSE);
}

The OnTransferStoreData function copies the text from the view's rich edit
control to the document string and resets the control's modified flag. The
corresponding update command UI handler grays the menu item if the control has
not been changed since it was last copied to or from the document. Add the
following boldface code:

void CMenuView::OnTransferStoreData()
{
CMenuDoc* pDoc = GetDocument();
m_rich.GetWindowText(pDoc->m_strText);
m_rich.SetModify(FALSE);
}

void CMenuView::OnUpdateTransferStoreData(CCmdUI* pCmdUI)


{
pCmdUI->Enable(m_rich.GetModify());
}

12. Build and test the Menu application. When the application starts, the Clear
Document item on the Edit menu should be enabled. Choose Get Data From
Document from the Transfer menu. Some text should appear. Edit the text, and
then choose Store Data In Document. That menu item should now appear gray.

174
Try choosing the Clear Document command, and then choose Get Data From
Document again.

7.3 The Toolbar

A toolbar consists of a number of horizontally (or vertically) arranged graphical buttons


that might be clustered in groups. The programming interface determines the grouping.
The graphical images for the buttons are stored in a single bitmap that is attached to the
application's resource file. When a button is clicked, it sends a command message, as do
menus and keyboard accelerators. An update command UI message handler is used to
update the button's state, which in turn is used by the application framework to modify
the button's graphical image.

7.3.1 The Toolbar Bitmap

Each button on a toolbar appears to have its own bitmap, but actually a single bitmap
serves the entire toolbar. The toolbar bitmap has a tile, 15 pixels high and 16 pixels wide,
for each button. The application framework supplies the button borders, and it modifies
those borders, together with the button's bitmap tile color, to reflect the current button
state.

7.3.2 The Toolbar and Command Messages

When the user clicks a toolbar button with the mouse, a command message is generated.
This message is routed like the menu command messages. Most of the time, a toolbar
button matches a menu option. A toolbar button doesn't have to mirror a menu item. If
you don't provide the equivalent menu item, however, you are advised to define a
keyboard accelerator for the button so that the user can activate the command with the
keyboard or with a keyboard macro product for Microsoft Windows. You can use
ClassWizard to define command and update command UI message handlers for toolbar
buttons, whether or not they have corresponding menu items.

A toolbar has an associated bitmap resource and, in the RC file, a companion TOOLBAR
resource that defines the menu commands associated with the buttons. Both the bitmap
and the TOOLBAR resource have the same ID, typically IDR_MAINFRAME. The text of
the AppWizard-generated TOOLBAR resource is shown below:

IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15


BEGIN
BUTTON ID_FILE_NEW
BUTTON ID_FILE_OPEN
BUTTON ID_FILE_SAVE
SEPARATOR
BUTTON ID_EDIT_CUT
BUTTON ID_EDIT_COPY
BUTTON ID_EDIT_PASTE

175
SEPARATOR
BUTTON ID_FILE_PRINT
BUTTON ID_APP_ABOUT
END

The SEPARATOR constants serve to group the buttons by inserting corresponding spaces
on the toolbar. If the number of toolbar bitmap panes exceeds the number of resource
elements (excluding separators), the extra buttons are not displayed.

When you edit the toolbar with the resource editor, you're editing both the bitmap
resource and the TOOLBAR resource. You select a button image, and then you double-
click on the left panel to edit the properties, including the button's ID.

7.4 The Status Bar

The status bar window neither accepts user input nor generates command messages. Its
job is simply to display text in panes under program control. The status bar supports two
types of text panes—message line panes and status indicator panes. To use the status bar
for application-specific data, you must first disable the standard status bar that displays
the menu prompt and key-board status.

7.4.1 The Status Bar Definition

The static indicators array that AppWizard generates in the MainFrm.cpp file defines the
panes for the application's status bar. The constant ID_SEPARATOR identifies a message
line pane; the other constants are string resource IDs that identify indicator panes. Figure
7.3 shows the indicators array and its relationship to the standard framework status bar.

Figure 7.3 Status Bar

Program 7.2: Program to display the mouse co-ordinates in the status bar.

1. Run AppWizard to generate a project named Status. Accept all default


settings but two: select Single Document and deselect Printing and Print Preview.
2. Use the string editor to edit the application's string table resource. Double-
click on the String Table icon in the String Table folder on the ResourceView

176
page to bring up the string editor. Then double-click on the empty entry at the end
of the list. A dialog allows you to assign the ID and the string value as shown in
Figure 7.3.

Figure 7.4 String Table

Add two strings as follows.


String ID String Caption
ID_INDICATOR_LEFT LEFT
ID_INDICATOR_RIGHT RIGHT
3. Use Visual C++ to edit the application's symbols. Choose Resource Symbols
from the View menu. Add the new status bar identifier, ID_MY_STATUS_BAR,
and accept the default value.
4. Use ClassWizard to add View menu command handlers in the class
CMainFrame. Add the following command message handlers.

Object ID Message Member Function


ID_VIEW_STATUS_BAR COMMAND OnViewStatusBar
ID_VIEW_STATUS_BAR UPDATE_COMMAND_UI OnUpdateViewStatusBar

177
5. Add the following function prototypes to MainFrm.h. You must add these
CMainFrame message handler prototypes manually because ClassWizard doesn't
recognize the associated command message IDs.

afx_msg void OnUpdateLeft(CCmdUI* pCmdUI);


afx_msg void OnUpdateRight(CCmdUI* pCmdUI);

Add the message handler statements inside the AFX_MSG brackets so that
ClassWizard will let you access and edit the code later. While MainFrm.h is open,
make m_wndStatusBar public rather than protected.

6. Edit the MainFrm.cpp file. Replace the original indicators array with the
following boldface code:
static UINT indicators[] =
{
ID_SEPARATOR, // first message line pane
ID_SEPARATOR, // second message line pane
ID_INDICATOR_LEFT,
ID_INDICATOR_RIGHT,
};

Next edit the OnCreate member function. Replace the following statement:

if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}

with the statement shown here:

if (!m_wndStatusBar.Create(this,
WS_CHILD | WS_VISIBLE | CBRS_BOTTOM, ID_MY_STATUS_BAR) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}

The modified call to Create uses our own status bar ID, ID_MY_STATUS_BAR,
instead of AFX_IDW_STATUS_BAR (the application framework's status bar
object).

Now add the following message map entries for the class CMainFrame.
ClassWizard can't add these for you because it doesn't recognize the string table
IDs as object IDs.

178
ON_UPDATE_COMMAND_UI(ID_INDICATOR_LEFT, OnUpdateLeft)
ON_UPDATE_COMMAND_UI(ID_INDICATOR_RIGHT, OnUpdateRight)

Next add the following CMainFrame member functions that update the two status
indicators:

void CMainFrame::OnUpdateLeft(CCmdUI* pCmdUI)


{
pCmdUI->Enable(::GetKeyState(VK_LBUTTON) < 0);
}

void CMainFrame::OnUpdateRight(CCmdUI* pCmdUI)


{
pCmdUI->Enable(::GetKeyState(VK_RBUTTON) < 0);
}

Note that the left and right mouse buttons have virtual key codes like keys on the
keyboard have. You don't have to depend on mouse-click messages to determine
the button status.

Finally, edit the following View menu functions that ClassWizard originally
generated in MainFrm.cpp:

void CMainFrame::OnViewStatusBar()
{
m_wndStatusBar.ShowWindow((m_wndStatusBar.GetStyle() &
WS_VISIBLE) == 0);
RecalcLayout();
}
void CMainFrame::OnUpdateViewStatusBar(CCmdUI* pCmdUI)
{
pCmdUISetCheck((m_wndStatusBar.GetStyle() & WS_VISIBLE) != 0);
}

These functions ensure that the View menu Status Bar command is properly
linked to the new status bar.

7. Edit the OnDraw function in StatusView.cpp. The OnDraw function displays a


message in the view window. Add the following boldface code:

void CStatusView::OnDraw(CDC* pDC)


{
pDC->TextOut(0, 0,
"Watch the status bar while you move and click the mouse.");
}

8. Add a WM_MOUSEMOVE handler in the CStatusView class. Use


ClassWizard to map the message to OnMouseMove, and then edit the function as
shown below. This function gets a pointer to the status bar object and then calls
the SetPaneText function to update the first and second message line panes.

179
void CStatusView::OnMouseMove(UINT nFlags, CPoint point)
{
CString str;
CMainFrame* pFrame = (CMainFrame*) AfxGetApp()m_pMainWnd;
CStatusBar* pStatus = &pFrame->m_wndStatusBar;
if (pStatus)
{
str.Format("x = %d", point.x);
pStatus->SetPaneText(0, str);
str.Format("y = %d", point.y);
pStatus->SetPaneText(1, str);
}
}

Finally, add the statement #include "MainFrm.h" near the top of the file
StatusView.cpp.

9. Build and test the STATUS application. Move the mouse, and observe that the
left two status bar panes accurately reflect the mouse cursor's position as shown in
Figure7.5.

Figure 7.5 Status bar application

Program 7.3: Integrating Menu, Status and Tool bars in a window.

1. Open Visual C++ and click the New item in the File menu, which opens the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name DME in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Single Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CDMEApp,
CMainFrame, CDMEDoc, CDMEView.

180
7. Click Resources view tab in the VC++ view window to open the Menu Editor.
Expand the resource folder by double clicking on DME resources folder. Find the
folder marked Menu & open it. Double click the entry in that folder,
IDR_MAINFRAME, to open the Menu Editor.
8. Double click the Edit menu and add a new menu item named “Display” into the
Edit menu. Do these by double click the empty menu item, to open the Menu Item
Properties box. Type the caption &Display. In Prompt Box write “Display the
message”. This text appears in the status bar when user lets mouse rest on this
menu item.
10. To add Accelerator key to Display menu item, Double click the Accelerator folder
from the resource view window. Double-click the IDR_MAINFRAME entry, to
open Accelerator editor.
11. Double click on the last blank entry, to open the Accel Properties box. Set the ID
as ID_EDIT_DISPLAY in the ID combo box and set Ctrl+Alt+F9 (VK_F9) in the
key box.
12. Declare the StringData variable on the document’s header file, DMEDoc.h.

class CDMEDoc : public CDocument


{
public:
CString StringData;


};

13. Initialize that string to an empty string in the document’s constructor in the
DMEDoc.cpp file.

CDMEDoc::CDMEDoc()
{
StringData=" ";
}

14. Select the DMEView.cpp file and Open the ClassWizard. ID_EDIT_DISPLAY is
listed in the Object IDs box. Click ID_EDIT_DISPLAY, and then double click
the COMMAND entry in the Message Box. This makes class wizard suggest a
name for the event handler of OnEditDisplay. Click OK to accept the name.
Double click on OnEditDisplay( ) in the Class Wizard Member functions box.

void CDMEView::OnEditDisplay()
{
// TODO: Add your command handler code here
}

16. To create a new Dialog Box, select Resources item in Insert menu. Select dialog
entry & click the New button.
17. Add a button & a text box(or edit box) control, onto the dialog box.

181
18. Right click on the button control to open property window. Set the Caption
property to “Click me” and set the control ID as IDC_BUTTON1. In the same
way, text box has IDC_EDIT1.
19. Now open Class Wizard and if the dialog class has not been set so far, you’ll be
prompted to Create a new dialog class. When you click the OK button a New
Class Dialog box will be prompted. Type the name Dlg for new class. Clicking
OK opens Class Wizard. Select IDC_BUTTON1 from Object ID & Double click
the BN_CLICKED entry in Message Box.
20. Start Class Wizard, & click the Member Variable tab. Now select text box
control, IDC_EDIT1, click add variable button. Give name m_text in the Member
variable
Name box, Value in Category Box and CString in the Variable text box. Click
OK.
21. The variable m_text is connected to the IDC_EDIT1 using special method that
class wizard had added to our Dlg dialog box class.

void Dlg::DoDataExchange(CDataExchange* pDX)


{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(Dlg)
DDX_Text(pDX, IDC_EDIT1, m_text);
//}}AFX_DATA_MAP
}

22. To place text in the text box add the following lines of code in the Button1’s event
handler:
void Dlg::OnButton1()
{
m_text="Welcome to VC++";
UpdateData(false);
}

23. Add the following bold faced code to OK button’s event handler.

void Dlg::OnOK()
{
UpdateData(true);
CDialog::OnOK();
}

24. To display the dialog box we have to connect it to “Display” item in the Edit
menu. Create new object dlg of our dialog box’s class Dlg. Invoke the
dialogbox’s DoModal( ) method. This method returns an integer value, which we
stored in the integer variable named result.
25. At this point, dialog box appears on the screen. If the user clicks OK, string
from the text box will be stored in our document. And we place the text in the
dialog’s box m_text variable in the StringData object.

void CDMEView::OnEditDisplay()

182
{
Dlg dlg;
int result=dlg.DoModal();
if(result==IDOK)
{
CDMEDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData=dlg.m_text;
Invalidate();
}
}

26. In view’s OnDraw( ) method, add the following bold faced statements to draw
the text from the dialog box:

void CDMEView::OnDraw(CDC* pDC)


{
CDMEDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(0,0,pDoc->StringData);
}

27. Test the application and you’ll see the window shown in Figure7.6 as an output.
Select the Display menu from the Edit menu, which in turn will display the dialog
window. When you rest the mouse on the Display menu the corresponding
prompt message will be displayed in the status bar as shown in Figure7.7.

Menu Prompt message

Figure 7.6 Integrating Menu and Status Bar

183
Note: We can open the Display menu item from Edit menu by following ways:
(i) Edit Display.
(ii) Using shortcut key Alt+E then D.
(iii) Using Accelerator key Alt+Ctrl+F9.
(iv) Using first button of the toolbar.

Figure 7.7 Invoking Dialog window through Menu

When you click the “Click Me” button the text “Welcome to VC++” will be
displayed in the client area of the window as shown in Figure 7.8.

Figure 7.8 Data Exchange from a Dialog Window

184
CHAPTER 8

SERIALIZATION AND FILE ACCESS

8.1 Serialization

Serialization is the process of saving the state of an object by converting it to a stream of


bytes. The object can then be persisted to file, database, or even memory. The reverse
process of serialization is known as deserialization.

In the Microsoft Foundation Class (MFC) library, designated classes have a member
function named Serialize. When the application framework calls Serialize for a particular
object—for example, an object of class CStudent—the data for the student is either saved
on disk or read from disk.

8.1.1 The CArchive and CFile Classes

Serialization in Visual C++ applications is accomplished through the CArchive class. The
CArchive class is designed to act as an input/output (I/O) stream for a CFile object, as
shown in Figure8.1.

Figure 8.1 The CArchive class stores application data in a CFile object

It uses C++ streams to enable efficient data flow to and from the file that is the storage of
the application data. The CArchive class cannot exist without a CFile class object to
which it is attached.

185
The CArchive class can store data in a number of types of files, all of which are
descendants of the CFile class. By default, the AppWizard includes all the functionality
to create and open regular CFile objects for use with CArchive. If you want or need to
work with one of these other file types, you might need to add additional code to your
application to enable the use of these different file types.

8.1.2 The Serialize Function

The CArchive class is used in the Serialize function on the document and data objects in
Visual C++ applications. When an application is reading or writing a file, the document
object's Serialize function is called, passing the CArchive object that is used to write to or
read from the file. In the Serialize function, the typical logic to follow is to determine
whether the archive is being written to or read from by calling the CArchive IsStoring or
IsLoading functions. The return value from either of these two functions determines if
your application needs to be writing to or reading from the CArchive class's I/O stream.

Program 8.1: Serializing your own objects and classes.

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name Serialize in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Single Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CSerializeApp,
CMainFrame, CSerializeDoc, CSerializeView .
7. Click ProjectAdd to ProjectNew. A list of file types appear in the dialog box.
Choose C/C++ Header File (be sure that “Add to Project” checkbox is checked.
Type file name CData.h in the Edit Box.
8. Open the CData.h file and place the code:
class CData
{
private:
CString data;
public:
CData( )
{
data=CString(" ");
}
void AddText(CString text)
{
data+=text;
}
void DrawText(CDC* pDC)
{
pDC->TextOut(0,0,data);
}

186
void ClearText()
{
data=" ";
}
};

 CData( ) Constructor to initialize the string to empty .


 AddText( ) to add more text to the end of string.
 DrawText( ) to draw string in the device context.
 ClearText( ) to clear the string.

9. Include this new file in the documents’ header & create a new object of CData
class named DataObject.
10. Now we add code to OnChar( ), which adds the newly typed character to internal
data in DataObject using the AddText( ) method.
void CSerializeView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
CSerializeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->DataObject.AddText(CString(nChar));
Invalidate();

CView::OnChar(nChar, nRepCnt, nFlags);


}

11. We draw the text in the DataObject object using the DrawText( ) method in the
OnDraw( ) method.

void CSerializeView::OnDraw(CDC* pDC)


{
CSerializeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->DataObject.DrawText(pDC);
}

12. To make class serializable, add code to CData class


(i) make it derived from MFC CObject class.
(ii) also include DECLARE_SERIAL macro to add the declarations of the
methods use for serialization.
(iii) Override CObject’s Serialize( ) method.
class CData : public CObject //to achieve 12(i)
{
private:
CString data;
DECLARE_SERIAL(CData); //to achieve 12 (ii)
public:
CData( )
{
data=CString(" ");
}

187
void AddText(CString text)
{
data+=text;
}
void DrawText(CDC* pDC)
{
pDC->TextOut(0,0,data);
}
void ClearText( )
{
data=" ";
}
void Serialize(CArchive& archive); //to achieve 12 (iii)
};

13. To write new version of Serialize, add new file CData.cpp to the project.
(i) Call base class’s Serialize( ) method.
(ii) Serialize our CString data member using << & >>
(iii) Include IMPLEMENT_SERIAL macro, which adds additional methods for
serialization.

void CData::Serialize(CArchive& archive) //to achieve 13(i)


{
CObject::Serialize(archive);
if(archive.IsStoring())
{
archive<<data; //to achieve 13 (ii)
}
else
{
archive>>data;
}
}
IMPLEMENT_SERIAL(CData,CObject,0); //to achieve 13 (iii)

14. To serialize our DataObject object, we have to call its Serialize( ) method in
document’s Serialize( ) method :

void CSerializeDoc::Serialize(CArchive& ar)


{
DataObject.Serialize(ar);
}

15. Execute and Test the application and you’ll find output windows as shown in
Figure8.2 and 8.3.

188
Figure 8.2 Serializing own class and objects

Figure 8.3 Serializing custom class

189
8.2 File Handling

Program 8.2: Program to create, open, read, write, modify and close a file.

1. Open Visual C++ and click the New item in the File menu.
2. In the New Projects Dialog window select the MFC AppWizard(exe).
3. Give the new project a name file in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Single Document in the AppWizard, click Finish.
6. Declare array of strings named OutString[] and InString[] to hold string values in
the fileDlg.h file.

protected:
HICON m_hIcon;
char OutString[4][20];
char InString[20];

7. You’ll have to save the string “Welcome to file handling.” in four character arrays.
We’ll use standard C strcpy( ) function to fill each character array in OnInitDialog(
).
8. Add two text boxes and a button in the default dialog resource attached to your
project. Create member variables m_text1 and m_text2 to the first and second text
boxes respectively. Initialize the first text box to display by default the string
“Welcome to file handling.” To do this add the following bold face lines of code
into the OnInitDialog( ) event handler.

BOOL CFileDlg::OnInitDialog()
{
CDialog::OnInitDialog();
strcpy(OutString[0],"Welcome ");
strcpy(OutString[1],"to ");
strcpy(OutString[2],"file ");
strcpy(OutString[3],"handling. ");

m_text1=CString(OutString[0]) + CString(OutString[1]) +
CString(OutString[2])+ CString(OutString[3]);
UpdateData(false);
.
.
.
}

9. Add the following bold faced coded into the OnButton1( ) event handler.

void CFileDlg::OnButton1()
{
CFile OutFile("data.txt",CFile::modeCreate | CFile::modeWrite);
for(int i=0;i<4;i++)
{
OutFile.Write(OutString[i],20);

190
}
OutFile.Close();

CFile InFile("data.txt",CFile::modeRead);
for(i=0;i<4;i++)
{
InFile.Seek(20*i,CFile::begin);
int NumChar=InFile.Read(InString,20);
m_text2+=CString(InString);
}
UpdateData(false);
InFile.Close();
}

The above lines of code do the following:

 Create an object of type CFile class named OutFile.


 Use the CFile Write( ) method to write the four strings into the file using a for
loop.
 By using CFile Read( ) method, the program reads the character strings in
data.txt back in.
 Create a new CFile object InFile to read the file.
 Use CFile Seek( ) method to position the file pointer at the beginning of each
successive string (placed inside a for loop).
 The InFile.Read( ) method returns the number of characters actually read, and
the return value is stored in the integer NumChar.
 The record just read in is in the character array InString[]. Add that record to
the text in the second text box & then close the file data.txt.

10. Execute the program and observe the output shown in Figure8.4.

Figure 8.4 File Access

191
CHAPTER 9

MULTIPLE DOCUMENT INTERFACE

9.1 Introduction

The Document/View architecture is the foundation used to create applications based on


the Microsoft Foundation Classes library. It allows you to make distinct the different
parts that compose a computer program including what the user sees as part of your
application and the document a user would work on. This is done through a combination
of separate classes that work as an ensemble.

The parts that compose the Document/View architecture are a frame, one or more
documents, and the view. Put together, these entities make up a usable application.

9.1.1. The view

A view is the platform the user is working on to do his or her job. For example, while
performing word processing, the user works on a series of words that compose the text. If
a user is performing calculations on a spreadsheet application, the interface the user is
viewing is made of small boxes called cells. Another user may be in front of a graphic
document while drawing lines and other geometric figures. The thing the user is starring
at and performing changes is called a view. The view also allows the user to print a
document.

To let the user do anything on an application, you must provide a view, which is an
object based on the CView class. You can either directly use one of the classes derived
from CView or you can derive your own custom class from CView or one of its child
classes.

9.1.2 The Document

For a computer application, a document holds the user's data. For example, after working
on a text processor, the user may want to save the file. Such an action creates a document
and this document must reside somewhere. In the same way, to use an existing file, the
user must locate it, open it, and make it available to the application. These two jobs and
many others are handled behind the scenes as a document.

To create the document part of this architecture, you must derive an object from the
CDocument class.

9.1.3 The Frame

As its name suggests, a frame is a combination of the building blocks, the structure (in
the English sense), and the borders of an item. A frame gives "physical" presence to a
window. A frame defines the location of an object with regards to the Windows desktop.

192
A frame provides borders to a window, borders that the user can grab to move, size, and
resize the object. The frame is also a type of desk that holds the tools needed on an
application.

An application cannot exist without a frame. As we saw in previous lessons, to provide a


frame to an application, you can derive a class from CFrameWnd.

9.2 Overview of the Single Document Interface (SDI)

The expression Single Document Interface or SDI refers to a document that can present
only one view to the user. This means that the application cannot display more than one
document at a time. If the user wants to view another type of document of the current
application, he or she must another instance of the application. Notepad and WordPad are
examples of SDI applications.

Notepad can be used to open only one document such as an HTML file, to view another
file, the user would either replace the current document or launch another copy of
Notepad.

To create an SDI, Microsoft Visual C++ provides the MFC wizard which provides all the
basic functionality that an application needs, including the resources and classes. We
were working on SDI applications till chapter 8 of this lab manual.

9.3 Overview of the Multiple Document Interface (MDI)

An application is referred to as Multiple Document Interface, or MDI, if the user can


open more than one document in the application without closing it. To provide this
functionality, the application provides a parent frame that acts as the main frame of the
computer program.

Inside of this frame, the application allows creating views that each uses its own frame,
making it distinct from the other. Microsoft Word 97 as shown in Figure 9.1 displays as a
classic MDI application.

The separation of the parent and the child frames allows the user to close one child
document or all documents. This would still leave the main frame of the application but
the user cannot use it as a document. Still, the main frame allows the user to either create
a new document or open an existing one.

To manage the differentiation between the parent and its children, the application uses
two different menus: one for the main frame and one for a (or each) child. Both menus
use the same menu bar, meaning that the application cannot display two frame menus at
one time. It displays either the parent menu or a (the) child menu. When at least one
document is displaying, the menu applies to the document. If no document is displaying,
the main frame is equipped with a simplified menu with limited but appropriate

193
operations. The user can only create a new document, only open an existing document, or
simply close the application.

Figure 9.1 MSWord Application

Program 9.1: Creating a Multiple Document Interface

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name Multiview in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Multiple Document in the AppWizard, click Finish.
6. Here, the AppWizard indicates four classes will be created : CKeystrokesApp,
CMainFrame, CKeystrokesDoc, CKeystrokesView .
7. Declare the StringData variable on the document’s header file, MultiviewDoc.h,
in the protected part.

class CMultiviewDoc : public CDocument


{
CString StringData;
.
.
.
};

194
8. Initialize that string to an empty string in the document’s constructor, which
we find in MultiviewDoc.cpp.

CMultiviewDoc::CMultiviewDoc()
{
StringData=" ";
}

9. We have to store data on the disk:

void CMultiviewDoc::Serialize(CArchive& ar)


{
if (ar.IsStoring())
{
ar << StringData;
}
else
{
ar >> StringData;
}
}

10. Add a new event handler OnChar( ) to our view class which is called every time
the user types the character.
11. The character the user typed is now in the nChar parameter, which we store in the
data string object, StringData. We need a pointer (pDoc) to our document object.
12. Add the character nChar to the string StringData. Steps 10, 11 and 12 will result
in the following lines of code in the OnChar( ) event handler:
void CMultiviewView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) //step 10
{
CMultiviewDoc* pDoc=GetDocument(); //step11
ASSERT_VALID(pDoc);
pDoc->StringData+=nChar; //step 12

}

13. We’ll handle the display of our data in the view’s OnDraw( ). We need to draw
the text string, which we do with TextOut( ).

void CMultiviewView::OnDraw(CDC* pDC)


{
CMultiviewDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

pDC->TextOut(0,0,pDoc->StringData);
}

14. Modify the OnChar( ) event handler according to the following steps:
a. Using UpdateAllViews( ) method, we’re able to refresh all the views into this
document now that user has typed a new character.

195
b. Set the document’s modified flag using SetModifiedFlag( ),means that if user
tries to close the current document without saving it, the program will ask if
they want to save it before the data in it is lost.

void CMultiviewView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)


{
CMultiviewDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->StringData+=nChar;
Invalidate();
pDoc->UpdateAllViews(this,0L,NULL); //step 14a
pDoc->SetModifiedFlag(); //step 14b
CView::OnChar(nChar, nRepCnt, nFlags);
}

15. Test the above program to see the outputs as shown in Figure 9.1.

Figure 9.2 Multiple Document Interface

196
CHAPTER 10

DYNAMIC LINK LIBRARY

10.1 Introduction

Dynamic link libraries (DLL) were introduced by Microsoft back in the early days of
Windows. DLLs are similar to library modules in that they both contain sets of
functionality that have been packaged for use by applications. The difference is when the
applications link to the library. With a library module (LIB), the application is linked to
the functionality in the library during the compile and builds process. The functionality
contained in the library file becomes part of the application executable file. With a DLL,
the application links to the functionality in the library file when the application is run.
The library file remains a separate file that is referenced and called by the application.

There are several reasons for creating DLLs instead of library module files. First, you can
reduce the size of the application executable files by placing functionality that is used by
multiple applications into DLLs that are shared by all of the applications. You can update
and modify functionality in the DLLs without having to update the application executable
(assuming that the exported interface for the DLL doesn't change). Finally, you can use
DLLs with just about any other Windows programming language, which makes your
functionality available to a wider number of programmers, not just fellow Visual C++
programmers.

Basically, a DLL is a file on disk (usually with a DLL extension) consisting of global
data, compiled functions, and resources, that becomes part of your process. It is compiled
to load at a preferred base address, and if there's no conflict with other DLLs, the file gets
mapped to the same virtual address in your process. The DLL has various exported
functions, and the client program (the program that loaded the DLL in the first place)
imports those functions. Windows matches up the imports and exports when it loads the
DLL.

10.2 How the Client Program Finds a DLL

If you link explicitly with LoadLibrary, you can specify the DLL's full pathname. If you
don't specify the pathname, or if you link implicitly, Windows follows this search
sequence to locate your DLL:
1. The directory containing the EXE file
2. The process's current directory
3. The Windows system directory
4. The Windows directory
5. The directories listed in the Path environment variable

Now let’s see how to create a simple DLL file and use it with our window program.

197
Program 10.1: Program to create a DLL.

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(dll) entry in the New dialog box.
3. Give the new program the name dll in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Open dll.cpp file and write the function that is to be exported here,

int _stdcall add(int a,int b)


{
return(a+b);
}

6. In the dll.def file,

EXPORTS
add @ 1
; Explicit exports can go here
7. Compile the application. dll.dll file is created and will be found in your debug
folder.
8. Copy the dll.dll file from debug folder of dll. And paste into debug folder of view
application wizard(exe).
9. In the view.cpp file under #include statements write the prototype of the functions-

typedef int(CALLBACK *lpfn) (int,int);


10. In OnDraw( ) function:

void CViewView::OnDraw(CDC* pDC)


{
CViewDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
HINSTANCE hDll;
int sum;
lpfn f1;
hDll=LoadLibrary("dlll");
if(hDll!=NULL)
{
f1=(lpfn)GetProcAddress(hDll,"add");
if(!f1)
FreeLibrary(hDll);
else
{
sum=f1(3,4);
char ch[2];
sprintf(ch,"%d",ch);
pDC->TextOut(10,10,sum);
}
}

11. Test the application and observe the result.

198
CHAPTER 11

INTERNET APPLICATIONS

11.1 Introduction

During the days of Windows 3.x, before networking was built into the Windows
operating system, you could buy the network protocols required for network
communications from numerous different companies. Each of these companies had a
slightly different way that an application performed network communications. As a
result, any applications that performed network communications had a list of the different
networking software that the application would work with. Many application developers
were not happy with this situation. As a result, all the networking companies, including
Microsoft, got together and developed the Winsock (Windows Sockets) and WinInet API.
This provided all application developers with a consistent API to perform all network
communications, regardless of the networking software used.

The WinInet is an application-level API and supports only HTTP, FTP, and Gopher
protocols. While WinSock is set of low-level APIs and supports most of the protocols
described above.

11.2 WinInet Vs. WinSock

WinInet provides a higher level-programming interface, which is easy to use while


WinSock, is a low level interface, which is hard to implement. To implement WinSock,
you should have some knowledge of Windows Sockets and TCP/IP. While WinInet hides
this all from developers and does every thing under the hood.

WinInet provides support for only three protocols - HTTP, FTP, and Gopher while
WinSock let you work with most of the protocols. WinInet supports build-in-caching
which improves downloading performance. WinInet provides easy connections and has
support for proxy servers. WinInet provides more security over WinSock.

Basically choosing between WinInet and WinSock is pretty easy. If your application
needs to access HTTP, FTP, or Gopher protocols then WinInet is better choice, whille
WinSock is for rest.

11.2.1 WinInet and its application

WinInet is high level, easy-to-use API to work with HTTP, FTP, and Gopher protocols. If
you use WinInet, you don't have to worry about learning protocol specifications such as
TCP/IP or Windows Sockets.

WinInet may be used for the following cases:


1. HTTP, FTP, and gopher.

199
2. Download web pages, images, sounds, and video files.
3. Execute server files such as CGI scripts, ISAPI dlls, or ASP scripts.
4. Access remote database and file systems.
5. Perform web searches.
6. Download and Upload files between computers.

11.3 InternetOpen

This function is root of all WinInet functions, and must be called before any WinInet
function. The InternetOpen function initializes WinInet environment and prepares to call
other WinInet functions. Basically this function starts a new Internet session. The WinInet
is based on hierarchy so next level function will require the handle returned by
InternetOpen.

After initializing WinInet, there are two ways to work with Internet. Either URL
related requirement, or protocol related requirement. InternetConnect function is
followed by protocol related functions and InternetOpenUrl is related to URLs. Here is
when to choose what?

InternetOpenUrl is used to download a web page, downoad an image via HTTP,


download a file via FTP, or download a file via Gopher.

InternetConnect is used for HTTP POST/GET headers to send and retrieve data, work
with FTP such as create, rename, delete directories or upload/download file, use gopher
locators.

11.4 InternetConnect

InternetConnect is responsible for starting new HTTP, FTP, or Gopher session after
establishing a connection using InternetOpen. A single application can have multiple
InternetConnect objects, depends on the requirement of the application.

11.5 InternetCloseHandle

This function closes opened Internet connection and terminates any pending operations
on the handle and discards any outstanding data.

11.6 InternetOpenUrl

InternetOpenUrl is a general function that an application can use to retrieve data over any
of the protocols that the Win32 Internet functions support. This function is particularly
useful when the application does not need to access the particulars of a protocol, but only
requires the data corresponding to a URL.

The InternetOpenUrl function parses the URL string, establishes a connection to the
server, and prepares to download the data identified by the URL. The application can

200
then use InternetReadFile (for files) or InternetFindNextFile (for directories) to retrieve
the URL data. It is not necessary to call InternetConnect before InternetOpenUrl.

Program 11.3: Using InternetOpenUrl to download a URL.

1. Create a dialog based application as shown in Figure 11.1 with two buttons and
two edit boxes. Set content edit box's as multiline.

Figure 11.1 Working with InternetOpenUrl

2. Add two variables using Class wizard, m_strURL and m_strContents, for each edit
boxes.
3. Include <wininet.h> in your stdafx.h and link to wininet.lib in your project settings.
WinInet.lib is in your Lib directory of Visual Studio.
4. And add a handler for Download button using Class Wizard and add this piece of
code:

void COpenUrlDlg::OnOk( )
{
UpdateData(TRUE);
if ( m_strURL.IsEmpty( ) )
return;
HINTERNET hINet, hFile;
hINet = InternetOpen("InetURL/1.0", INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, 0 );
if ( !hINet )
{
AfxMessageBox("InternetOpen Failed");
return;
}
hFile = InternetOpenUrl( hINet, m_strURL, NULL, 0, 0, 0 ) ;
if ( hFile )
{
CHAR buffer[1024];

201
DWORD dwRead;
while ( InternetReadFile( hFile, buffer, 1023, &dwRead ) )
{
if ( dwRead == 0 )
break;
buffer[dwRead] = 0;
m_strURL += buffer;
}
InternetCloseHandle( hFile );
}
InternetCloseHandle( hINet );
UpdateData(FALSE);
}

4. Now run your program, type URL with http and hit Download. You will see source
code of the URL you have entered.
5. Don't forget to include wininet.h #include <wininet.h> in your stdafx.h.

Program 11.2: Creating Internet Applications using HTTP.

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name http in the Project name box.
4. Click OK to starts the Visual C++ AppWizard.
5. Click the option marked Dialog Based in the AppWizard, click Finish.
6. Add a text box and a button. The button ha “Download the Web Page” as its
caption.
7. Connect an event handler, OnButton1( ), to the button.
8. We’ll create a new Internet Session. This Internet Session is actually an object of
the
MFC CInternetSession class, and this class is the basis of Visual C++ Internet
support.
9. Also add the line #include<afxinet.h> to make sure we can use the Internet
components.

// httpDlg.cpp : implementation file


.
.
.
#include "afxinet.h"
.
.
.

10. We’ve set aside a pointer, pInternetSession, for our new Internet session
and we create the session now.
11. If computer is not connected to the Internet, the program will display a connect
box

202
and make the connection. If connection failed, we should terminate the program.
12. We’ll use the CInternetSession class’s OpenURL( ) method to open a web page
for HTTP transfer. This returns a pointer to a file object of class CStdioFile and
save that pointer as pFile.
13. Now we have a pointer to a file object representing the Web page we want to
work
with, and we can treat it just like a file.
14. If we want to download the file’s first 1000 bytes, we do it by setting up a buffer
for
our data and using the Read( ) method.
15. To display the data received, we connect a member variable, m_text, to the text
box in our program and places the downloaded text in that text box.
16. We close the file we’ve opened and Internet Session.
17. The above mentioned steps 10 to 16 will result in the following lines of code in
the OnButton1( ) event handler:

void CHtttpDlg::OnButton1()
{
CInternetSession* pInternetSession; //Step 10

pInternetSession=new CInternetSession(); //Step 10

if(!pInternetSession) //Step 11
{
AfxMessageBox("Could not establish Internet Session",MB_OK);
return;
}

CStdioFile* pFile=NULL; //Step 12

char* buffer; //Step 14


buffer=new char[1000]; //Step 14
pFile=pInternetSession
OpenURL(CString("http://www.microsoft.com"));
//Step 12
pFile->Read(buffer,1000); //Step 14

m_text=CString(buffer,1000); //Step 15
UpdateData(false);

pFile->Close(); //Step 16
pInternetSession->Close(); //Step 16
}

18. When you execute the application with a it will display a window as shown in
Figure 11.2 as an output.

203
Figure 11.2 Downloading a Web Page

11.7 WinInet FTP MFC Classes

11.7.1 FTP Classes

CFtpConnection and CFtpFindFile are two FTP classes, which encapsulate all MFC
APIs.

CFtpConnection

This class manages connection to your FTP server and allows direct manipulation of files
and directories on the server. You always create a CFtpConnection object using
CInternetSession::GetFtpConnection. All member of this class are easy to understand.

Members Description
SetCurrentDirectory Sets the current FTP directory.
GetCurrentDirectory Gets the current FTP directory.
GetCurrentDirectoryAsURL Get current dir as a URL.
RemoveDirectory Removes the specified dir.
CreateDirectory Creates a new dir.

204
Rename Rename a file or a dir.
Remove Removes a file.
PutFile Uploads a file to the server.
GetFile Download a file from the server.
OpenFile Opens a file and returns a pointer to CInternetFile.
Close Closes the connection.

CFtpFindFile

CFtpFindFile is used to find a file on the server.

Members Description
FindFile Finds a file on the server. It returns nonzero if successful, otherwise 0.
FindNextFile Use to continue to search for a file, which you started with FindFile.
GetFileURL Gets the URL for a specified file.

Let’ s see how to use the above mentioned class and methods for developing an internet
application.

Program 11.3: Creating Internet Applications using FTP.

1. Open Visual C++ and click the New item in the File menu, opening the New dialog
box.
2. Now select the MFC AppWizard(exe) entry in the New dialog box.
3. Give the new program the name ftp in the Project name box.
4. Click OK to start the Visual C++ AppWizard.
5. Click the option marked Dialog Based in the AppWizard, click Finish.
6. Add a text box and a button with the caption “Download the File”.
7. Connect an event handler, OnButton1( ), to the button and member variable,
m_text, to the text box.
8. We’ll create a new Internet Session. This Internet Session is actually an object of
the MFC CInternetSession class, and this class is the basis of Visual C++ Internet
support.
9. Also add the line #include<afxinet.h> to make sure we can use the Internet
components.

// httpDlg.cpp : implementation file


.
.
.
#include "afxinet.h"
.
.
.

205
10. We’ve set aside a pointer, pInternetSession, for our new Internet session and we
create the session now.
11. If computer is not connected to the Internet, the program will display a connect
box and make the connection. If connection failed, we should terminate the
program.
12. We create pointer to the class CFtpConnection named pFTPConnection. This
class represents the FTP support in VC++.
13. To create this new object, we call the CInternetSession class’s GetFtpConnection(
) method to make an anonymous FTP connection to the Microsoft site, passing
that method the name of the FTP site we want to connect to, ftp.microsoft.com.
14. If we were unsuccessful in connecting to the FTP site, we display an error
message and finish up.
15. Otherwise, we indicate that we have started the downloading process by placing
the message “Downloading” in the text box.
16. We close the FTP connection and the Internet session at the end of OnButton1( ).
17. The above mentioned steps 10 to 16 will result in the following lines of code in
the OnButton1( ) event handler:

void CFtpDlg::OnButton1()
{
CInternetSession* pInternetSession; // Step 10
CFtpConnection* pFTPConnection; // Step 12

pInternetSession=new CInternetSession(); // Step 11

if(!pInternetSession) // Step 11
{
AfxMessageBox("Could not establish Internet session",MB_OK);
return;
}

pFTPConnection=pInternetSession
GetFtpConnection(CString("ftp.microsoft.com"));
// Step 13

if(!pFTPConnection) // Step 14
{
AfxMessageBox("Could not establish FTP connection. ",MB_OK);
return;
}

else // Step 15
{
m_text="Downloading.....";
UpdateData(false);
}

pFTPConnection
GetFile(CString("disclaimer.txt"),CString("disclaimer.txt"));

206
pFTPConnection->Close(); // Step 16
pInternetSession->Close(); // Step 16

18. When you execute the application it will display a window as shown in Figure
11.3 and when you click the button it starts downloading the URL.

Figure 11.3 Downloading a web site using FTP

207
CHAPTER 12

ACTIVEX CONTROLS

12.1 Introduction

An ActiveX control is a set of functionality packaged in a COM (Component Object


Model) object. This COM object is self-contained, although it does not have the ability to
run by itself. An ActiveX control can only run within a ActiveX container, such as a
Visual C++ or Visual Basic application.

ActiveX controls provide a series of interfaces used by the container application to


trigger the various sets of functionality contained in the control. Many of these interfaces
are used for triggering events in the control or in the containing application. Others are
for specifying the property page of the control or for communicating whether the control
has been activated. All in all, so many interfaces are built into most ActiveX controls that
coding the functionality for each of these interfaces yourself would take quite some time.
Luckily, the Visual C++ App and Class Wizards add much of this functionality for you,
allowing you to focus on the specific functionality that the control is supposed to have.

Among the aspects of the control you create that you still must plan yourself are what
properties, methods, and events you will expose for your control. You can add these
elements to your control through the Class Wizard, but if any of the properties or events
require special code on your part, then you must add it yourself. As should be expected
with any methods that you add to your controls, you have to supply all of the code. The
Class Wizard will add the surrounding structure and code to allow the containing
application to see and call the method, just as it will add all the code necessary to call any
event handlers for your applications.

12.1.1 Properties

Properties are attributes of controls that are visible to, and often modifiable by, the
container application. The four basic types of properties are ambient, extended, stock, and
custom. Ambient properties are provided by the container application to the control--such
things as background color or the default font to be used--so that the control looks like
part of the container application. Extended properties are not actually properties of the
control but instead are provided and implemented by the container application, such as
tab order. The control may extend these properties somewhat; for example, if the control
contains two or more standard controls, it may control the tab order within the overall
control, returning the tab order control to the application once the control has completed
its internal tab order. Stock properties are implemented by the ActiveX control
development kit, such as control font or control background color. The final type of
properties, custom properties, are what you are most concerned with because these
properties are specific to your control and are directly related to the functionality of your
control.

208
You can specify any properties you need in your control using the Automation tab on the
Class Wizard. When you add a new property to your control through the Class Wizard,
you'll specify several aspects of the property.

The first aspect is the external property name, which is the name shown to the containing
application for the property. Another aspect that you can specify is the internal variable
name, which is used in your code, but only if the property is implemented as a member
variable. You also specify the variable type for the property.

If you specify that the property is to be implemented as a member variable (the property
is a member variable of the control class), then you can specify the name of the
notification function, which is called when the property is changed by the containing
application. If the property is not a member variable of the control class, you need to
specify that it is altered and viewed through Get and Set methods, where the containing
application calls a Get method to get the current value of the property and calls a Set
method to change the value of the property. If the property is maintained through Get and
Set methods, then you can specify the names of these two methods.

For all these aspects of a property, the Add Property dialog suggests appropriate names
for everything once you enter the external name for the property. If you want to accept
the default names, the only things you need to specify are the external name, the type,
and whether the property is a member variable or uses Get and Set methods. If you
choose a stock property from the list of available stock properties, the rest of the elements
are automatically specified for you. Once you specify all of this information, the Class
Wizard adds all of the necessary code and variables to your control project.

12.1.2 Methods

Methods are functions in the control that can be called by the container application.
These functions are made available to other applications through the IDispatch interface,
which we discussed on Day 9. Because of the way the IDispatch works in calling the
methods in a control, the variables passed to the method have to be packaged in a
structure that is passed to the control. This structure is machine independent so that it
doesn't matter whether your control is running with Windows 95/98 on an Intel Pentium
II or on a Windows NT with a MIPS or Alpha processor; the structure will look the same.
It is the responsibility of each side of the function call to convert the parameters as
necessary to fit them into the structure correctly or to extract them from the structure.
This process of packaging the method parameters is called marshaling.

When you add a new method to your control through the Class Wizard on the
Automation tab, the Class Wizard adds all of the necessary code to perform the
marshaling of the parameters, as well as all other supporting functionality, including
building the IDispatch interface and table.

When you add a new method to your control through the Class Wizard, you are asked to
provide the external name for the method called by the container application. Your

209
method will get a default internal name, which you can override by entering your own
internal name. Other aspects of your control methods that you have to specify are the
method's return type and the parameters for the method. Once you finish entering all this
information, the Class Wizard adds all the necessary code to the control.

12.1.3 Events

Events are notification messages that are sent from the control to the container
application. They are intended to notify the application that a certain event has happened,
and the application can take action on that event if desirable. You can trigger two types of
events from your control, stock or custom events. Stock events are implemented by the
ActiveX control development kit and are available as function calls within the control.
These stock events enable you to trigger events in the container application for mouse or
keyboard events, errors, or state changes.

Along with the stock events, you can add your own custom events to be triggered in the
container application. These events should be related to the specific functionality of your
control. You can specify arguments to be passed with the event to the container
application so that the application can have the data it needs for reacting to the event
message.

When you need to trigger any of these events, all you do is call the internal event function
that fires the event, passing all the necessary parameters to the function. The Class
Wizard will have added all of the necessary code to trigger the event message from the
internal function call.

Events are one of the three elements that you do not add to your controls through the
Automation tab in the Class Wizard. Events are added through the ActiveX Events tab in
the Class Wizard.

Program 12.1: Creating an ActiveX control.

1. Open Visual C++ and click the New item in the File menu, opening the New
dialog box.
2. Now select the MFC ActiveX ControlWizard entry in the New dialog box.
3. Give the new program the name boxer in the Project name box.
4. Accept all the defaults by pressing the Finish button.
5. We have to divide the control into four rectangles, naming those rectangles box1 to
box4 and declaring them in BoxerCtl.h:

class CBoxerCtrl : public COleControl


{
.
.
.
// Implementation
protected:
~CBoxerCtrl();

210
CRect box1;
CRect box2;
CRect box3;
CRect box4;
.
.
.
};

6. Now, we have four rectangles to divide the control up in OnDraw( ), placing the
four boxes at upper left, upper right, lower left, and lower right.
7. Then we draw the four rectangles.

void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)


{
pdc->FillRect(rcBounds,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

box1=CRect(rcBounds.left, rcBounds.top, rcBounds.right/2,


rcBounds.bottom/2);

box2=CRect(rcBounds.left, rcBounds.bottom/2, rcBounds.right/2,


rcBounds.bottom);

box3=CRect(rcBounds.right/2, rcBounds.top, rcBounds.right,


rcBounds.bottom/2);

box4=CRect(rcBounds.right/2, rcBounds.bottom/2, rcBounds.right,


rcBounds.bottom);

pdc->Rectangle(&box1); //Step 7
pdc->Rectangle(&box2); //Step 7
pdc->Rectangle(&box3); //Step 7
pdc->Rectangle(&box4); //Step 7
}

8. To handle mouse click we add an eventhandler LButtonDown( ) using


ClassWizard.
9. We can record which of our flag rectangles the user clicked, and which rectangle to
fill with color - by setting up four new Boolean flags, fill1 to fill4, in the CBoxerCtl
header.

class CBoxerCtrl : public COleControl


{
.
.
.
// Implementation
protected:
~CBoxerCtrl( );
CRect box1;
CRect box2;
CRect box3;
CRect box4;

211
boolean fill1;
boolean fill2;
boolean fill3;
boolean fill4;
.
.
.
};

10. Set those flags to false in the control’s constructor:

CBoxerCtrl::CBoxerCtrl( )
{
InitializeIIDs(&IID_DBoxer, &IID_DBoxerEvents);
fill1 = fill2 = fill3 = fill4 = false;
}

11. In OnLButtonDown( ), we can set the boolean fill flags using the CRect method
PtInRect( ), which returns true if the point you pass to it is in a certain rectangle,
such as our box1 to box4 objects:

void CBoxerCtrl::OnLButtonDown(UINT nFlags, CPoint point)


{
fill1 = box1.PtInRect(point);
fill2 = box2.PtInRect(point);
fill3 = box3.PtInRect(point);
fill4 = box4.PtInRect(point);
Invalidate( );

COleControl::OnLButtonDown(nFlags, point);
}

12. Invalidate( ) calls the OnDraw( ), there we check the four Boolean fill flags
and fill the corresponding rectangle using the CDC method FillSolidRect( ):

void CBoxerCtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)


{
pdc->FillRect(rcBounds,
CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));

box1=CRect(rcBounds.left, rcBounds.top, rcBounds.right/2,


rcBounds.bottom/2);

box2=CRect(rcBounds.left, rcBounds.bottom/2, rcBounds.right/2,


rcBounds.bottom);

box3=CRect(rcBounds.right/2, rcBounds.top, rcBounds.right,


rcBounds.bottom/2);

box4=CRect(rcBounds.right/2, rcBounds.bottom/2, rcBounds.right,


rcBounds.bottom);

pdc->Rectangle(&box1);

212
pdc->Rectangle(&box2);
pdc->Rectangle(&box3);
pdc->Rectangle(&box4);

if(fill1) pdc-> FillSolidRect(&box1,RGB(0,0,0));

if(fill2) pdc-> FillSolidRect(&box2, RGB(0,0,0));

if(fill3) pdc-> FillSolidRect(&box3, RGB(0,0,0));

if(fill4) pdc-> FillSolidRect(&box4, RGB(0,0,0));


}

13. To test “Boxer”, start Build  Build Boxer.ocx to build the boxer.ocx and
registered that control with Windows.
14. Select the ActiveX Control Test Container item in the tools menu, which brings
up the very useful test container tool.
15. Select Insert New Control item in the test container’s Edit menu and Double
click the Boxer control in the Insert Control box that appears. This inserts our
ActiveX control in the test container.

Figure 12.1 ActiveX control Test Container

213
16. Click one of the boxes in the control, shading it. Clicking another rectangle
shades that rectangle instead.
17. To embed the ActiveX in a program. Create a new dialog based program now
named Boxerapp. To insert a control of Boxer type in this program: select
Project  Add to Project  Components and Controls, opening the
Components and Controls Gallery.
18. Double click on the Registered ActiveX Controls. Select the Boxer Control
entry and click insert button. This inserts the Boxer control into the dialog’s
editor’s toolbox, where it has an icon OCX.
19. Test the application and you’ll find the windows shown in Figure 12.1 and 12.2 as
output.

Figure 12.2 Application involving ActiveX Control

214
CHAPTER 13

DATABASE CONNECTIVITY

13.1 Introduction

A large number of applications use a database. Everything from a personal organizer to a


large, corporate personnel system uses a database to store and maintain all the records
that the applications use and manipulate. Visual C++ provides you with four different
technologies for using and accessing databases in your applications, Data Access Objects
(DAO), ODBC, OLE DB, and ActiveX Data Objects (ADO).

13.2 The MFC Classes for ODBC Support

In the Visual C++ development environment, most of the ODBC functionality has been
encapsulated into two classes, CRecordset and CDatabase. The CDatabase class contains
the database connection information and can be shared across an entire application. The
CRecordset class encapsulates a set of records from the database. The CRecordset class
allows you to specify a SQL query to be run, and the CRecordset class will run the query
and maintain the set of records that are returned by the database. You can modify and
update the records in the record set, and your changes will be passed back to the database.
You can add or delete records from the record set, and those same actions can be passed
back to the database.

13.2.1 Connecting to the Database

Before the CRecordset class can perform any other functions, it has to be connected to a
database. This is accomplished through the use of the CDatabase class. You don't need to
create or set the CDatabase instance; the first instance of the CRecordset class does this
for you. When you create an application using the AppWizard and choose to include
ODBC database support, the AppWizard includes the database connection information in
the first CRecordset-derived class that it creates. When this CRecordset class is created
without being passed a CDatabase object, it uses the default connection information,
which was added by the AppWizard, to create its own database connection.

13.2.2 Opening and Closing the Record Set

Once the CRecordset object is created and connected to the database, you need to open
the record set to retrieve the set of records from the database. Do this by calling the Open
member function of the CRecordset object. You can call this function without any
arguments if you want to take the default values for everything, including the SQL
statement to be executed.

215
Once the user finishes working with the record set, you can call the Close function to
close the record set and free any resources used by the record set. The Close function
doesn't take any arguments.

13.2.3 Navigating the Record Set

Once you have a set of records retrieved from the database, you need to be able to
navigate the set of records (unless the set has only one record). The CRecordset class
provides several functions for navigating the record set, allowing you to move the user to
any record. Below is the list of functions that you can use to navigate the record set.

Function Description
MoveFirst Moves to the first record in the set.
MoveLast Moves to the last record in the set.
MoveNext Moves to the next record in the set.
MovePrev Moves to the previous record in the set.
Move Can be used to move a specific number of records from the current
record or from the first record in the set.
SetAbsolutePosition Moves to the specified record in the set.
IsBOF Returns TRUE if the current record is the first record in the set.
IsEOF Returns TRUE if the current record is the last record in the set.
GetRecordCount Returns the number of records in the set.

13.2.4 Adding, Deleting, and Updating Records

Apart from navigating a set of records you also need to be able to add new records to the
record set, edit and update existing records, and delete records. These actions are all
possible through the various functions that the CRecordset class provides. The functions
that will enable you to add new records to the record set, edit and update existing records,
and delete records are listed below:

Function Description
AddNew Adds a new record to the record set.
Delete Deletes the current record from the record set.
Edit Allows the current record to be edited.
Update Saves the current changes to the database.
Requery Reruns the current SQL query to refresh the record set.

None of these functions takes any arguments. However, some of them require following a
few specific steps to get them to work correctly.

216
To add a new record to the database, you can call the AddNew function. The next thing
that you need to do is set default values in any of the fields that require values, such as
the key fields. Next, you must call the Update function to add the new record to the
database. If you try to navigate to another record before calling the Update function, the
new record will be lost. Once you save the new record, you need to call the Requery
function to refresh the record set so that you can navigate to the new record and let the
user edit it.

Now let’s make use of the above mentioned classes and methods to create a simple
database application.

Program 13.1: Simple DB application to view the contents of a table in a dialog


window.
1. First create a database dbs.mdb in MSAccess.
2. Then create a table named Student with the following columns in dbs.mdb:
Name, Roll_No, Age and Department.
3. Save the table and exit MSAccess.
4. Click the ODBC icon in the Windows Control Panel.
5. The Visual C++ Setup program should have already installed the required ODBC
drivers on your hard disk. If you are running Windows 95, click the Drivers
button to see whether the Microsoft Access driver is available. If you're running
Windows 98, click the Drivers tab to see whether the Microsoft Access driver is
available. (If the Microsoft Access driver is not available, rerun Visual C++
Setup.) Click the Add button (in Windows 98, the Add button is on the User DSN
tab), choose Microsoft Access Driver in the Add Data Source dialog box (in
Windows 98, select the Microsoft Access Driver in the Create New Data Source
dialog box and click the Finish button), and fill in the ODBC Microsoft Access 97
Setup dialog box as shown in Figure 13.1.

Figure 13.1 Registering Student Database

217
Set the database to point to dbs.mdb using the Select button. Finally, click the
OK button.
6. Now open Visual C++ and click the New item in the File menu, opening the New
dialog box.
7. Now select the MFC AppWizard(exe) entry in the New dialog box.
8. Give the new program the name DB in the Project name box.
9. Click Next button, There is a Question: “What Database support would you like
to include?”, click the radio button labeled “Database View with File Support”.
10. Next, click the button labeled Data Source to open the Database Options box as
shown in Figure13.2.

Figure 13.2 MFC AppWizard – Step 2 of 6

Figure 13.3 Selecting ODBC Database

218
11. We select the ODBC button, and specify the dbs.mdb files as our Data source as
in Figure 13.3.
12. When the Select Database Tables appears, click the Student table and the OK
button as in Figure 13.4.

Figure 13.4 Select Database Tables Dialog Box

Figure 13.5 Dialog Window Design

11. Now we click the OK button and finish button in App Wizard, letting AppWizard
create the New Program.
12. Open the main view, IDD_DB_FORM, in the dialog editor, and add the
following controls: a button with caption “Display the current record’s fields”,
four edit text boxes & four static text boxes as shown in Figure 13.5.
13. Using Class Wizard, we connect an event handler, OnButton1( ) to the button &
four member variable m_text1, m_text2, m_text3 and m_text4 to four text boxes.

219
14. Add the following bold faced codes into the OnButton1( ) event handler:

void CDbvcView::OnButton1( )
{
m_text1=m_pSet->m_Name;
UpdateData(false);

m_text2=m_pSet->m_Roll_No;
UpdateData(false);

m_text3=m_pSet->m_Branch;
UpdateData(false);

m_text4=m_pSet->m_Semester;
UpdateData(false);

15. Run the application to find the window shown in Figure 13.6 as an output. You
can click on the navigation buttons in the toolbar to navigate through the various
records.

Record Navigation Buttons

Figure 13.6 View table information

The above exercise allows the user just to view information from a table. Now let’s work
on another program that will allow the user to view, add, modify and delete information
from a table.

220
Program 13.2: Program to add, delete and modify records into a table.

1. Follow the steps 1 to 11 as given in program13.1.


2. Selecten the resource view tab, and double click on the Dialog folder to open the
IDD_DB_FORM, in the dialog editor, and add the following controls: four edit
text boxes & four static text boxes as shown in Figure 13.7.

Figure 13.7 Dialog Window Design

3. Use ClassWizard to link the edit controls to the recordset data members. To
add a data member, click on the Member Variables tab and choose the ID
corresponding to the edit box for each variable. Click the Add Variable button,
and click the arrow in the Member Variable Name combo box to display a list of
variables. Select only the appropriate variable, as shown in Figure 13.8. When
you're finished adding variable names for each edit box, you'll see a screen like
the one shown in Figure 13.9.
4. Add menu commands. Add the following items to the Record pop-up menu in
the IDR_MAINFRAME menu as shown in Figure 13.10. Also, use ClassWizard to
map the commands to the specified CDBView class members.

Menu Command ID Command Handler Update Command


Command UI Handler

Add Record ID_RECORD_ADD OnRecordAdd

Clear Fields ID_RECORD_CLEAR OnRecordClearfields

Delete Record ID_RECORD_DELETE OnRecordDelete OnUpdateRecordDelete

Update Record ID_RECORD_UPDATE OnRecordUpdate OnUpdateRecordUpdate

221
Figure 13.8 Linking control variables to Recordset data members

Figure 13.9 Class Wizard displaying Controls and corresponding Recordset data
members

222
Figure 13.10 Adding Menu

5. Add and override the OnMove function in the CDBView class. Invoke Class
Wizard, in the Message Map tab select CDBView from the ObjectID list box and
double click on the OnMove message handler from the Messages list box as
shown in Figure13.11. This will create the OnMove( ) function.

Figure 13.11 Adding OnMove function using Class Wizard

223
The CRecordView::OnMove function does the work of updating the database
when the user moves out of a record. Because we don't want this behavior, we
must override the function by adding the following bold faced codes inside the
CDBView::OnMove( ) function:

BOOL CDBView::OnMove(UINT nIDMoveCommand)


{
switch (nIDMoveCommand)
{
case ID_RECORD_PREV:
m_pSet->MovePrev();
if (!m_pSet->IsBOF())
break;

case ID_RECORD_FIRST:
m_pSet->MoveFirst();
break;

case ID_RECORD_NEXT:
m_pSet->MoveNext();
if (!m_pSet->IsEOF())
break;
if (!m_pSet->CanScroll()) {
// Clear screen since we're currently in EOF
m_pSet->SetFieldNull(NULL);
break;
}

case ID_RECORD_LAST:
m_pSet->MoveLast();
break;

default:
// unexpected case value
ASSERT(FALSE);
}

// Show results of Move operation


UpdateData(FALSE);
return TRUE;
}

6. Edit the menu command handlers. The following functions call various
CRecordset member functions to edit the database. To add a record, you must call
CRecordset::AddNew, followed by Update. To modify a record, you must call
CRecordset::Edit, followed by Update. When you add a new record to the
database, you should call CRecordset::MoveLast because the new record is
always added to the end of the dynaset. Add the following boldface code:

void CDBView::OnRecordAdd( )
{
m_pSet->AddNew( );
UpdateData(TRUE);

224
if (m_pSet->CanUpdate( ))
{
m_pSet->Update( );
}
if (!m_pSet->IsEOF( ))
{
m_pSet->MoveLast( );
}
m_pSet->Requery( ); // for sorted sets
UpdateData(FALSE);
}

void CDBView::OnRecordClear( )
{
m_pSet->SetFieldNull(NULL);
UpdateData(FALSE);
}

void CDBView::OnRecordDelete()
{
CRecordsetStatus status;
try {
m_pSet->Delete( );
}
catch(CDBException* e) {
AfxMessageBox(e->m_strError);
e->Delete( );
m_pSet->MoveFirst( ); // lost our place!
UpdateData(FALSE);
return;
}
m_pSet->GetStatus(status);
if (status.m_lCurrentRecord == 0) {
// We deleted last of 2 records
m_pSet->MoveFirst( );
}
else {
m_pSet->MoveNext( );
}
UpdateData(FALSE);
}

void CDBView::OnUpdateRecordDelete(CCmdUI* pCmdUI)


{
pCmdUI->Enable(!m_pSet->IsEOF( ));
}

void CDBView::OnRecordUpdate()
{
m_pSet->Edit( );
UpdateData(TRUE);
if (m_pSet->CanUpdate( )) {
m_pSet->Update();
}
// should requery if key field changed
}

225
void CDBView::OnUpdateRecordUpdate(CCmdUI* pCmdUI)
{
pCmdUI->Enable(!m_pSet->IsEOF( ));
}

7. Build and test the DB application again. Now you can add, change, and delete
records using the menu items. You may find an output window similar to the one
shown in Figure 13.12.

Figure 13.12 DB Application Window

Observe what happens if you try to add a record with a duplicate key. You get an
error message that comes from an exception handler inside the framework. You
can add try/catch logic in OnRecordAdd to customize the error processing.

226
CHAPTER 14

DYNAMIC CONTROLS

14.1 Introduction

The Windows Common Controls are the new Windows controls, introduced for
Microsoft Windows 95 and available in Microsoft Windows NT. These include the
progress indicator, trackbar, spin button control, list control, and tree control as shown in
Figure14.1.

Figure 14.3 Windows Common Controls

The code for these controls is in the Windows COMCTL32.DLL file. This code includes
the window procedure for each control, together with code that registers a window class
for each control. The registration code is called when the DLL is loaded. When your
program initializes a dialog, it uses the symbolic class name in the dialog resource to
connect to the window procedure in the DLL. Thus your program owns the control's
window, but the code is in the DLL. Except for ActiveX controls, most controls work this
way.

The Progress Indicator Control (CProgressCtrl) - is the easiest common control to


program and is generally used only for output.

The Trackbar Control (CSliderCtrl) - sometimes called a slider, allows the user to set
an "analog" value. If you specify a large range for this control—0 to 100 or more, for
example—the trackbar's motion appears continuous. If you specify a small range, such as
0 to 5, the tracker moves in discrete increments. You can program tick marks to match
the increments. In this discrete mode, you can use a trackbar to set such items as the

227
display screen resolution, lens f-stop values, and so forth. The trackbar does not have a
default range.

The Spin Button Control (CSpinButtonCtrl) - is often used in conjunction with an edit
control. The edit control, located just ahead of the spin control in the dialog's tabbing
order, is known as the spin control's buddy. The idea is that the user holds down the left
mouse button on the spin control to raise or lower the value in the edit control. The spin
speed accelerates as the user continues to hold down the mouse button.

The List Control (CListCtrl) - used to display a list that contains images as well as text.
The elements are arranged in a grid, and the control includes horizontal scrolling. When
the user selects an item, the control sends a notification message, which you map in your
dialog class. That message handler can determine which item the user selected. Items are
identified by a zero-based integer index.

The Tree Control (CTreeCtrl) - You're already familiar with tree controls if you've used
Microsoft Windows Explorer or Visual C++'s Workspace view. The user can expand and
collapse elements by clicking the + and - buttons or by double-clicking the elements. The
icon next to each item is programmed to change when the user selects the item with a
single click.

Program 14.1: Creating an equalizer with Progress bar controls.

1. Start Microsoft Visual C++ and create a new MFC AppWizard (exe) application
named Equalizer.
2. Create the project as a Dialog Based and set the Dialog Title as Sound Equalizer
without the About Box
3. Delete the TODO line and move the buttons to the bottom section of the dialog.
4. Right-click anywhere on the dialog box and click Insert ActiveX Control.
5. In the ActiveX Control list of the Insert ActiveX Control dialog box, click
Microsoft ProgressBar Control, version 6.0 as shown in Figure14.2.

Figure 14.2 Insert ActiveX Control dialog box

228
6. Click OK.
7. Right-click the newly added control and click Properties. In the Properties
window, click the Control tab and change the Orientation property to 1 –
ccOrientationVertical.
8. On the dialog box, right-click the ProgressBar and click Copy. Right-click
anywhere on the dialog box and click Paste many times until you get 10
ProgressBar controls.
9. Design the dialog box as shown in Figure 14.3 (only the top labels and the
ProgressBar controls need IDs):

Figure 14.3 Dialog Design for Sound Equalizer

Additional
Control ID Caption
Properties
Static Text IDC_VAL_250 000 Align Text: Center
Static Text IDC_VAL_500 000 Align Text: Center
Static Text IDC_VAL_1 000 Align Text: Center
Static Text IDC_VAL_10 000 Align Text: Center
ProgressBar IDC_PRGR_250 000 Align Text: Center
ProgressBar IDC_PRGR_500

229
ProgressBar IDC_PRGR_1
ProgressBar IDC_PRGR_10

10. Press Ctrl + W to access the ClassWizard. Add a CString Value Variable for
each label that has an ID and Add a CProgressBar Control Variable for each
ProgressBar control as follows:

Control
Identifier Value Variable
Variable
IDC_VAL_250 m_ValTwo
IDC_VAL_500 m_ValFive
IDC_VAL_1 m_ValOne
IDC_VAL_10 m_ValTen
IDC_PRGR_250 m_two
IDC_PRGR_500 m_five
IDC_PRGR_1 m_one
IDC_PRGR_10 m_ten

11. Click OK
12. Using the Resource Symbols dialog box, add four new identifiers as
IDT_TWOFIVE, IDT_FIVE, IDT_ONE, and IDT_TEN as shown in Figure14.4.

Figure 14.4 Resource Symbols Dialog Box

230
13. Click Close.
14. In the OnInitDialog( ) event of the dialog class, create the following timers and
generate a random seed:

BOOL CEqualizerDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here


SetTimer(IDT_TWO, 650, NULL);
SetTimer(IDT_FIVE, 200, NULL);
SetTimer(IDT_ONE, 450, NULL);
SetTimer(IDT_TEN, 1000, NULL);

srand(static_cast<unsigned>(time(NULL)));

return TRUE; // return TRUE unless you set the focus to a control
}

15. Save All.


16. Generate a WM_TIMER message for the dialog box and implement it as
follows:

void CEqualizerDlg::OnTimer(UINT nIDEvent)


{
// TODO: Add your message handler code here and/or call default
float two = static_cast<float>(rand( ) % 100);
float five = static_cast<float>(rand( ) % 100);
float one = static_cast<float>(rand( ) % 100);
float ten = static_cast<float>(rand( ) % 100);

if( nIDEvent == IDT_TWO )


{
m_two.put_Value(two);
// Make a sound if the value of the bass is too high
if( two >= 85 )
MessageBeep(MB_ICONEXCLAMATION);
}
if( nIDEvent == IDT_FIVE )
m_five.SetValue(five);
if( nIDEvent == IDT_ONE )
m_one.SetValue(one);

231
if( nIDEvent == IDT_TEN )
m_ten.SetValue(ten);

m_ValTwo.Format("%.f.%d", m_two.GetValue( ), rand( )%99);


m_ValFive.Format("%.f\260", m_five.GetValue( ));
m_ValOne.Format("%.f\045", m_one.GetValue( ));
m_ValTen.Format("<%.f", m_ten.GetValue( ));

UpdateData(FALSE);

CDialog::OnTimer(nIDEvent);
}

17. Test the application.

Program 14.2: Displaying different pictures of a car using Slider Control.

1. Start a new Dialog-based application named CarInventory with no About Box


and set the Dialog Title to Car Inventory.
2. Delete the TODO line and the OK button
3. Collect ten pictures of automobiles or any ten pictures (or even ten different
images of you or your friend) available in your system and save it in your drive.
For this program the following pictures were used:

232
4. On the main menu, click Insert -> Resource or Project -> Add Resource…
5. On the Add Resource dialog box, click Import… and import the above pictures. If
you are using MSVC 6, you may receive a message box when you import each
picture, simply click OK.
6. Change the ID of the new bitmap to IDB_CIVIC, IDB_ELANTRA,
IDB_ESCAPE, IDB_ESCORT, IDB_FOCUS, IDB_MARQUIS,
IDB_MYSTIQUE, IDB_NAVIGATOR, IDB_SENTRA, and IDB_SEPHIA
respectively.
7. Add a Picture control to the top side of the dialog box and change its ID to
IDC_PREVIEW.
8. Type to Bitmap and set its Bitmap to IDB_CIVIC.
9. Add a Control variable for the picture control and name it m_Preview.
10. To store the values for the controls on the dialog box, in the header file of the
dialog box, declare a private UINT array named CarPicture[10].
11. To initialize the array, type the following in the OnInitDialog event:

BOOL CSlider1Dlg::OnInitDialog()
{
CDialog::OnInitDialog();

SetIcon(m_hIcon, TRUE); // Set big icon


SetIcon(m_hIcon, FALSE); // Set small icon

// TODO: Add extra initialization here

CarPicture[0] = IDB_CIVIC;
CarPicture[1] = IDB_ELANTRA;
CarPicture[2] = IDB_ESCAPE;
CarPicture[3] = IDB_ESCORT;
CarPicture[4] = IDB_MARQUIS;
CarPicture[5] = IDB_MYSTIQUE;
CarPicture[6] = IDB_NAVIGATOR;
CarPicture[7] = IDB_SENTRA;
CarPicture[8] = IDB_FOCUS;
CarPicture[9] = IDB_SEPHIA;

return TRUE; // return TRUE unless you set the focus to a control
}

233
12. To display default values in the dialog box, on top of its OnPaint( ) event, type the
following:

void CSlider1Dlg::OnPaint()
{
CBitmap Bmp;
Bmp.LoadBitmap(CarPicture[0]);
m_Preview.SetBitmap(Bmp);
UpdateData(FALSE);

if (IsIconic())
{
CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM)
dc.GetSafeHdc(), 0);

// Center icon in client rectangle


int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon


dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}

13. Test the application and return to MSVC.


14. On the Controls toolbox, click the Slider button and click in lower-left section
of the dialog box.
15. While the slider control is selected on the dialog box, on the Properties window,
change its ID to IDC_SLIDER.
16. Check its Auto Ticks check box or set it to True.
17. Check its Tick Marks check box or set it to True.
18. Set its Point property to Top/Left.
Set to True the Tooltips property of the slider control.
19. Add a CSliderCtrl Control variable for the slider and name it m_CarSlider.
20. In the OnInitDialog event of the dialog class, set the range of values of the slider
to 0 to 9 and the frequency of its ticks to:

234
BOOL CControlsDlg::OnInitDialog()
{
CDialog::OnInitDialog();

// TODO: Add extra initialization here


m_CarSlider.SetRange(1, 10);
m_CarSlider.SetTicFreq(1);

return TRUE; // return TRUE unless you set the focus to a control
}

21. Save all and Test the application.


22. Change the OnPaint( ) event of the dialog class as follows:

void CCarInventoryDlg::OnPaint()
{
int CurPos = m_CarSlider.GetPos() - 1;
CBitmap Bmp;

Bmp.LoadBitmap(CarPicture[CurPos]);

m_Picture.SetBitmap(Bmp);
UpdateData(FALSE);

...
}

23. Using either the ClassWizard (MSVC 6) or the Messages button , for the dialog,
generate the WM_HSCROLL message and implement it as follows:

void CCarInventoryDlg::OnHScroll(UINT nSBCode, UINT nPos,


CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
CRect RectPicture;

// Get the location and dimensions of the picture area


m_Preview.GetWindowRect(&RectPicture);

// Convert the current coordinates from


// the monitor (Screen) to the dialog box (Client)
ScreenToClient(&RectPicture);
// Repaint the picture area
InvalidateRect(&RectPicture);

CDialog::OnHScroll(nSBCode, nPos, pScrollBar);


}

235
24. Test the application and you’ll find an output similar to the one shown in Figure
14.5.

Figure 14.5 Car Inventory Application

25. Finally close your application and return to MSVC.

236
REFERENCES

1. MSDN Library Visual Studio 6.0.


2. Mauer, Lowell, Sams Teach Yourself More Visual Basic 6in 21 Days, Sams
Publishing, 1998.
3. Rahmel and Dan, Sams Teach Yourself DatabaseProgramming with Visual
Basic 6 in 24 Hours, Sams Publishing, 1998.
4. Steven Holzner, Visual Basic 6 Black Book, Publisher: The Coriolis Group.
5. David Kruglinski, George Shepherd, Scot Wingo, Programming Microsoft
Visual C++, 5th Edition, Microsoft Press.
6. Rod Stephens, Ready-to-Run Visual Basic(r) Algorithms, 2nd Edition.
7. Microsoft Corporation (Editor), Desktop Applications for Microsoft VC++ 6.0:
MCSD Training Kit, Microsoft Press; Edition November 1999.
8. Charles Petzold, Programming Windows, Microsoft Press. 1998.
9. http://www.dotnetheaven.com/
10. http://www.tenouk.com/cnwin32tutorials.html
11. http://visualbasic.freetutes.com/
12. http://www.planet-source-code.com/PlanetSourceCode/
13. http://www.vb6.us/
14. http://www.functionx.com/win32/
15. http://www.codeguru.com/

237
APPENDIX A

EXERCISES
Part I – Visual Basic

Chapter 1

1. Try exploring the other types of projects available in VB6.0 New dialog window.
2. Explore the other properties of controls like command button, text box and label
controls.
3. Write a program to count the number of words in a text box.
4. Explore all the windows available in VB6.0 IDE.

Chapter 2

1. Create a form and change the background of the form every second using a timer.
2. Develop a standard project with multiple forms each with different back ground.
Display one form after the other every 5 seconds and display the name of the form
that gets active at every 5th second.
3. Explore the other form events and properties.

Chapter 3

1. Create a form that lists down a set of film names when the form gets loaded. Also
provide features like adding new film names and removing film names.
2. Design and implement an application using combo box that enables search
matching names as you type the characters in a name.
3. Find the last occurrence of Substring within a String.
4. Determine if a string contains a valid date.
5. Design an implement a scientific calculator.
6. Use a picture box that loads different images at different time intervals
using a timer.
7. Design an implement a menu driven program in VB6 that enables
selection of pixel thickness for drawing lines.
8. Make a survey of the various other intrinsic controls.

Chapter 4

1. Validate the various inputs to the simple math and scientific calculator
applications in the key press event.
2. Design an implement a menu driven program in VB6 that enables
selection of pixel thickness for drawing lines.

238
3. Create an application that identifies the key which a user presses and
loads the corresponding image containing that alphabet in a form or
picture box.
4. Create an application that displays images at four corners of a form.
Display the names of the images in the order in which the user clicks the
images.
5. Design an application that enables drag and drop of objects/images.

Chapter 5

1. Create a tab separated text file having the roll number, name and age of 10
students. Develop an application that reads the students information and displays
it in three text boxes on a form.
2. Modify the same application to append the text file with new student information.
3. Create an application that lists down the folders in a drive and also the free space
available in a drive using file access controls.
4. Create an application that reads the text in a file and displays the number of
characters, words, special characters, white spaces, etc., in that text.

Chapter 6

1. Try to implement program 6.1 and 6.2 using RDO and ADO controls.
2. Similarly try using other grid controls in program 6.4 and 6.5.
3. Design and implement a hostel management information system.
4. Create a payroll application for your organization in VB6.
5. Implement Exercise 4 in chapter 5 and save the results (i.e., number of characters,
words, special characters, white spaces, etc.) in a table and then display the counts
in a message box.

Part II – Visual C++

Chapter 1

1. Experiment out the program 1.1 with different window creation parameters and
styles.
2. Try creating multiples instances of a window using program 1.1.
3. Try all the exercise programs of chapter 3 & 4 using MFC based programming.

Chapter 2

1. Draw different shapes by identifying various key strokes.


2. Design an implement a menu driven program in VB6 that enables selection of
pixel thickness for drawing lines.
3. Create an application that identifies the key which a user presses and loads the
corresponding image containing that alphabet in a form or picture box.

239
4. Create an application that displays images at four corners of a form. Display the
names of the images in the order in which the user clicks the images.
5. Develop a video game which would call for interactions with the keyboard.
6. Write a program that identifies whether a mouse is attached or not; and if
attached, how may buttons are present on it/
7. Write a program that can identify whether the mouse buttons are swapped or not.
8. Write a program that displays an image wherever the user clicks the mouse left
button in the client area. Also try out the same for mouse double click events.
9. Write a program that displays which part of the client area has been clicked.
10. Create an application that closes when the user double clicks using the mouse
right button.
11. Write a program using which a user can click the client area of a window and drag
the window.

Chapter 3 & 4

1. Create your own pen to draw a line and a rectangle and also create your own
brush to fill the rectangle.
2. Try drawing some standard shapes like arch, pie, etc., in a window.
3. Draw a line from (100, 100) to (200, 200) with origin of the coordinate system
coinciding with the center of the window.
4. Draw a parabola using a PolyLine( ) function.
5. Display the names of students and their roll numbers in a class one below the
other in a window.
6. Display 4 bitmap images in the four corners of a window.
7. Create a simple dialog box with a static image in it.
8. Design an implement a simple loan calculator that gets input and displays the
monthly premium using the controls on a dialog window.
9. Try to obtain the dialog window in exercise 8 in the center of the screen.
10. Validate the various inputs to the controls on the dialog window of the simple
loan calculator application in exercise 8.
11. Create a modeless dialog application that computes the various components of the
salary given the basic pay of an employee.

Chapter 5 & 6

1. Create a simple window with a push button on it. Also load a bitmap image on the
push button.
2. Write a program that helps the user to select different windows style properties
using check boxes in the client area of the window and display window according
to the selected property(s).
3. Write a program that displays the names of students in your class (use list or
combo box control) and also allows performing search.
4. Write a program that displays all fonts available in your system in a list box.
5. Design an implement simple math calculator.
6. Try to explore different styles for caret.

240
Chapter 7

1. Explore the other possible ways of loading a menu without using CWnd::Create(
) function.
2. Create a menu driven program to draw different shapes and use the keys on the
keyboard to invoke different menu items.
3. Write a simple menu program that can be used to check and uncheck menu items.
4. Write a program that generates a popup menu at the position where the user clicks
the mouse right button.
5. Modify the above program by including bitmap images with the menu items in
the popup menu.
6. Write a program that display the mouse coordinates on the statusbar.
7. Write a program to increase the size of the buttons on the tool bar.
8. Modify exercise 2 by including tool bar buttons for drawing shapes and connect
them to the respective menu items.
9. Write a program to generate a status bar that shows the status of the Caps Lock,
Num Lock and Scroll Lock.

Chapter 8

1. Create a tab separated text file having the roll number, name and age of 10
students. Develop an application that reads the students information and displays
it in three text boxes on a form.
2. Modify the same application to append the text file with new student information.
3. Create an application that reads the text in a file and displays the number of
characters, words, special characters, white spaces, etc., in that text.

Chapter 9

1. Create an application that opens texts of different files in different child windows.
2. Simulate word software with basic functionalities using multiple document
interface concepts.
3. Write a simple MDI application that splits the child windows and displays images
in it.

Chapter 10

1. Write a paint application which has all the drawing logics in a dll file and uses it
for the purpose of drawing when a user selects a shape to draw.
2. Write a simple program that compute the factorial of a number. Define the
recursive function in a dll file.
3. Modify the exercise 2 in chapter 13 by writing all the database interactions in a dll
file.

241
Chapter 11

1. Create a simple TCP chat application.


2. Write an internet application that send text files from one machine to another,
3. Write a server program that reads a data file in the client and displays the number
of words in that file in the server end.

Chapter 12

1. Create a calendar control and use it in some of your projects.


2. Create simple ActiveX controls like simple text boxes displaying date and time,
text boxes that accepts numeric inputs, etc.

Chapter 13

1. Design and implement a hostel management information system.


2. Create a payroll application for your organization.
3. Design and implement a simple objective type question answering system that
tests a user and evaluates him/her based on the answer provides.

Chapter 14

1. Create a text editor that used spin button controls to select the font size.
2. Write a program that displays the status of some activity done in your system like
saving, opening a file in terms of the amount of job done and remaining job using
progress bars.
3. Create a video display window that uses a track bar and progress bar for
displaying the video status while playing.
4. Write a program that displays the folders and sub folders in a drive using a tree
view control.

242

You might also like