DMC1947
DMC1947
CHAPTER 1
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.
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.
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
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.
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:
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.
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.
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.
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.
5. With the help of Tool Box given on the left side of the interface, draw the interface as
shown in Figure 1.6.
5
6. Set the properties of the objects on the form as given in the table below:
7. Double click First Command Button and write the following lines of code:
9. Double click Second Command Button and write the following lines of code:
10. Run the project by clicking Run>>Start or Press F5 and you’ll see an output as
shown in Figure 1.7.
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.
2. Draw the interface as given in Figure 1.8 using the Tool Box.
5. Run the Project and enter the values and then click the “Calculate” command button to
see a result.
7
CHAPTER 2
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
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
Unload Me
The Unload event is also triggered with the user clicks the Windows "close" button ("X")
on the form.
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:
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.
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.
Program 2.2: Program to display the form exactly at the center of the screen using form
load event.
2. Double click on the form and the following code in the Form_Load event.
End Sub
10
3. Run the program and observe where the form gets displayed in the screen.
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:
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:
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:
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:
3. Add two labels and three command buttons and edit the following properties:
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
6. Add a command button with a name cmdExit and caption “Return to Main Form”
in Form2 and Form3 respectively.
12
Figure 2.2 Adding a new form to existing project
13
Private Sub cmdForm3_Click( )
Form3.Show vbModal
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.
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.
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.
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
The Visual Basic toolbox as in Figure 3.1 contains the tools you use to draw controls on
your forms.
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:
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.
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:
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:
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:
8. Now, go back to the form design window and double-click the Add button. The
code for cmdAdd_click() is as follows:
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.
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.
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.
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
End Sub
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:
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.
If cboFood.ListIndex = -1 Then
MsgBox "There is no item currently selected.", vbInformation, _
"Combo Box Demo"
22
Exit Sub
End If
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.
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.
23
Dim strStateAbbrev As String
Dim strStateName As String
intStateFileNbr = FreeFile
cboStateAbbrev.Clear
Do Until EOF(intStateFileNbr)
Input #intStateFileNbr, strStateAbbrev, strStateName
cboStateAbbrev.AddItem strStateAbbrev
Loop
Close #intStateFileNbr
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.
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.
intStateFileNbr = FreeFile
cboStateName.Clear
Do Until EOF(intStateFileNbr)
Input #intStateFileNbr, strStateAbbrev, strStateName
cboStateName.AddItem strStateName
Loop
Close #intStateFileNbr
End Sub
14. To add new states into the simple combo box use the following code in the
cmdAddNewName_Click( ) event.
25
Dim intX As Integer
' 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.
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.
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
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.
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.
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.
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'.
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.
28
2. To move the selected items from lstAvail to lstSelected, place the following code
in the cmdAdd_Click event:
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)
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:
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.
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:
For I = 1 To ItemCount
List1.AddItem Data.Files(I)
Next
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.
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.
3. Add the following lines of code in the command button’s click event:
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
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
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
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.
ShowOpen Open
ShowSave Save As
ShowColor Color
ShowFont Font
ShowPrinter Print
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.
3. The form has the following controls and properties set as shown below:
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
6. Write the following Open Dialog control logic in the click event of the cmdOpen
button:
With dlgDemo
.CancelError = True
.InitDir = mstrLastDir
.Flags = cdlOFNHideReadOnly
.FileName = ""
.Filter = "Text Files(*.txt)|*.txt|All Files(*.*)|*.*"
.ShowOpen
strFileToOpen = .FileName
End With
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:
cmdOpen_Click_Exit:
End Sub
7. Write the following Save dialog control logic in the click event of the cmdSave
button:
With dlgDemo
.CancelError = True
.InitDir = mstrLastDir
.Flags = cdlOFNOverwritePrompt + cdlOFNPathMustExist
.FileName = ""
.Filter = "Text Files(*.txt)|*.txt|All Files(*.*)|*.*"
.ShowSave
strFileToSave = .FileName
End With
intDemoFileNbr = FreeFile
Open strFileToSave For Binary Access Write As #intDemoFileNbr
strBuffer = txtTestFile.Text
Put #intDemoFileNbr, , strBuffer
Close #intDemoFileNbr
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:
With dlgDemo
.CancelError = True
.Flags = cdlPDHidePrintToFile + cdlPDNoPageNums _
+ cdlPDNoSelection
.ShowPrinter
intCopies = .Copies
End With
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:
With dlgDemo
.CancelError = True
.ShowColor
lngColor = .Color
End With
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:
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:
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:
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.
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.
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:
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.
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.
6. Run the project and click the various buttons in any order. A sample run is shown
in Figure 3.13.
42
Now let’s see how to design and develop 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.
2. Declare the following variables in the general part of your code window:
Option Explicit
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( )
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.
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)
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:
mintCurrKeyIndex = Index
strPressedKey = cmdCalc(Index).Caption
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 "%"
mdblSavedNumber = (Val(mstrDisplay) / 100) * mdblResult
mstrDisplay = Format$(mdblSavedNumber)
Case "="
If mblnNewEquals Then
mdblSavedNumber = Val(mstrDisplay)
mblnNewEquals = False
End If
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
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
End Sub
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.
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:
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:
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
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.
Program 4.1: Program that changes the position of a control on the form during the
MouseDown event.
51
Command1.Move X, Y
End Sub
4. Run the program and observe what happens when you click randomly on the
form.
Line -(X, Y)
End Sub
Program 4.3: Program to draw lines by clicking the mouse button and moving it and to
stop drawing the mouse button is released.
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.
4. When the user releases the mouse button drawing must not be done. Hence set the
DrawNow variable to FALSE in the MouseUp event.
52
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.
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:
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)
End Sub
53
Private Sub Form_MouseUp (Button As Integer, Shift As Integer, _ X As Single, Y
As Single)
End Sub
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.
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:
2. Add a Textbox control to the form and this procedure in the KeyDown event:
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.
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.
55
Private Sub txtPassword_KeyPress(KeyAscii As Integer)
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.
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.
Option Explicit
56
Private Const CB_SHOWDROPDOWN = &H14F
Private Const LB_FINDSTRING = &H18F
Private Const CB_ERR = (-1)
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:
4. Add the following combo box logic into the GotFocus( ) and KeyPress( ) event of
the combo box respectively:
Dim CB As Long
Dim FindString As String
If Combo1.SelLength = 0 Then
FindString = Combo1.Text & Chr$(KeyAscii)
Else
FindString = Left$(Combo1.Text, Combo1.SelStart) & Chr$(KeyAscii)
End If
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
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
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:
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
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:
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:
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:
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.
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)
' 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.
There are three main ways to access files in Visual Basic: as sequential files, as random
access files, and as binary 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.
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:
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.
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
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.
FileError:
MsgBox "File Error!"
End Sub
4. Run the application and you’ll find the file size in bytes displayed in a
message box.
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.
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.
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.
TPath = "C:\Windows\"
Filename = Dir(TPath)
End Sub
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.
68
3. The form has the following controls:
DoEvents
5. Now include the below lines of code in the click event of the list box:
69
'Get the drive letter from the list box
strDrive = Left(List1.List(List1.ListIndex), 1) & ":"
6. Run the application and check the free spaces in the drives in your system.
70
CHAPTER 6
DATABASE CONNECTIVITY
6.1 Introduction
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.
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.
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:
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.
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.
6. Click once on the data control and make sure that the following properties are set:
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.
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.
1. Copy the files from Program6.1 into a new folder and open the VBP file in the
new folder.
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:
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
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:
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
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.
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.
2. Place two data controls on the form and set their properties as follows:
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 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
79
Figure 6.4 Using MSFlexGrid Control
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.)
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. 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
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.
Let’s start with the first type of programming and see how a simple window can be
created and hence learn the steps involved.
82
Figure 1.1 New Project Dialog Window
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"
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
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
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
}
switch(msg)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
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:
86
15. To close the window, click its system Close button and return to your
programming environment.
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:
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:
Program 1.2: Creating a window and to change the display of window using
ShowWindow method.
87
Program 1.3: Creating a window and working the size of the window.
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
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
#include<windows.h>
long _stdcall func(HWND,UINT,UINT,long);WNDCLASS a;
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;
}
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.
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.
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>
mybrush=(HBRUSH)::GetStockObject(WHITE_BRUSH);
return 1;
}
};
myapp a;
92
CHAPTER 2
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
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:
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.
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;
h=CreateWindow("SimpleWnd","Title",WS_OVERLAPPEDWINDOW,20,20,300,200,0,0,i,
0); // Create Window Application
ShowWindow(h,3);
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.
95
Program 2.2: Simple line drawing in mouse events using MFC
public: myframe()
{
Create(0,"Click Left MouseButton In The Client Area");
}
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.
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.
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.
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.
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.
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:
Program2.4: A hit-test program involving mouse events and Windows mapping modes
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:
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.
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:
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.
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.)
103
void CMouseDlg::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
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);
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.
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
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:
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);
105
m_bCursor = TRUE;
// Set the screen cursor
SetCursor(lhCursor);
}
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
9. Build and Execute the program and observe the changes that happens when you
press the keys on the keyboard.
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.
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.
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( ).
pDC->TextOut(0,0,pDoc->StringData);
// TODO: add draw code for native data here
}
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.
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).
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:
Now let’s see how to create and embed cursors in the window that we create.
#include <windows.h>
109
LPCTSTR WndName = "Resources Fundamentals";
LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
110
return Msg.wParam;
}
5. Execute the application to test it. The Application development is not over.
Continue with the resource creation steps.
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:
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"
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
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.
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.
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.
hWnd = CreateWindowEx( 0,
ClsName,
AppCaption,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
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 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:
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:
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.
#include <windows.h>
117
#include <windows.h>
LPCTSTR Caption = "Application Programming Interface";
7. Execute the application and you’ll see a message box as indicated in Figure3.6:
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.
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);
return FALSE;
}
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:
120
CHAPTER 4
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.
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:
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:
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:
Painting with the BeginPaint( ) and EndPaint( ) functions must be performed in the
WM_PAINT message.
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:
To end the line, you use the LineTo() function. Its syntax is:
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).
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
124
#include "windows.h"
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;
ShowWindow(hwnd, nCmdShow);
125
return msg.wParam; // return the message struct's wParam
}
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;
}
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.
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:
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:
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.
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;
}
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:
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 }.
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;
}
130
Figure 4.7 Drawing shapes using PolyPloyline method
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:
This function uses the same types of arguments as the Polyline() function.
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.
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);
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;
}
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:
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.
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;
}
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.
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);
return static_cast<int>(Msg.wParam);
}
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-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:
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:
Now let us see how a bitmap image can be used in your windows program.
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.
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);
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);
140
}
return static_cast<int>(Msg.wParam);
}
switch(Msg)
{
case WM_DESTROY:
PostQuitMessage(WM_QUIT);
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
10. Test the application and you’ll find an output window as shown in Figure 4.13.
141
Figure 4.13 Using bitmap resources
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.
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:
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 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
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.
#include <windows.h>
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);
return static_cast<int>(Msg.wParam);
}
switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
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.
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.
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:
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:
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.
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.
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.
149
To create a pen, you can call the CreatePen function. Its syntax is:
The fnPenStyle argument is characteristic is referred to as the style of the pen. The
possible values of this argument are:
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:
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.
switch(Msg)
{
case WM_PAINT:
hDC = BeginPaint(hWnd, &Ps);
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
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.
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:
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.
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:
3. Return to your programming environment by clicking the close button the output
window.
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:
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.
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);
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.
3. Return to your programming environment by clicking the close button the output
window.
156
CHAPTER 5
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.
Now let’s use some of these standard controls to create a dialog application that invokes
another application.
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:
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.
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:
12. Select the ID of one of the controls that you need to attach a variable to, such as
IDC_MSG.
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:
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();
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
}
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
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
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
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
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
164
strPgmName.MakeUpper();
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.
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.
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.
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
.
.
};
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:
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();
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.
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
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.
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)
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:
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.
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.
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.
172
7. Add a CString data member to the CMenuDoc class. Edit the file MenuDoc.h
or use ClassView.
public:
CString m_strText;
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();
}
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.
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::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);
}
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.
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.
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:
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.
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.
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.
Program 7.2: Program to display the mouse co-ordinates in the status bar.
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.
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.
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
}
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:
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)
{
pCmdUISetCheck((m_wndStatusBar.GetStyle() & WS_VISIBLE) != 0);
}
These functions ensure that the View menu Status Bar command is properly
linked to the new status bar.
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.
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.
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.
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:
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.
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.
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.
184
CHAPTER 8
8.1 Serialization
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.
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.
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.
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 ProjectAdd to ProjectNew. 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=" ";
}
};
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();
11. We draw the text in the DataObject object using the DrawText( ) method in the
OnDraw( ) method.
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.
14. To serialize our DataObject object, we have to call its Serialize( ) method in
document’s Serialize( ) method :
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
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();
}
10. Execute the program and observe the output shown in Figure8.4.
191
CHAPTER 9
9.1 Introduction
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.
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.
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.
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.
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.
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.
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.
194
8. Initialize that string to an empty string in the document’s constructor, which
we find in MultiviewDoc.cpp.
CMultiviewDoc::CMultiviewDoc()
{
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( ).
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.
15. Test the above program to see the outputs as shown in Figure 9.1.
196
CHAPTER 10
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.
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,
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-
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.
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.
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.
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?
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.
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.
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.
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.
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
if(!pInternetSession) //Step 11
{
AfxMessageBox("Could not establish Internet Session",MB_OK);
return;
}
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
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
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.
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.
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
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.
207
CHAPTER 12
ACTIVEX CONTROLS
12.1 Introduction
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.
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:
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.
pdc->Rectangle(&box1); //Step 7
pdc->Rectangle(&box2); //Step 7
pdc->Rectangle(&box3); //Step 7
pdc->Rectangle(&box4); //Step 7
}
211
boolean fill1;
boolean fill2;
boolean fill3;
boolean fill4;
.
.
.
};
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:
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( ):
pdc->Rectangle(&box1);
212
pdc->Rectangle(&box2);
pdc->Rectangle(&box3);
pdc->Rectangle(&box4);
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.
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.
214
CHAPTER 13
DATABASE CONNECTIVITY
13.1 Introduction
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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);
}
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::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.
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.
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 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.
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.
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):
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.
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
srand(static_cast<unsigned>(time(NULL)));
return TRUE; // return TRUE unless you set the focus to a control
}
231
if( nIDEvent == IDT_TEN )
m_ten.SetValue(ten);
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
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();
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);
234
BOOL CControlsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
return TRUE; // return TRUE unless you set the focus to a control
}
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:
235
24. Test the application and you’ll find an output similar to the one shown in Figure
14.5.
236
REFERENCES
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.
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
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
Chapter 12
Chapter 13
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