VCLBook
VCLBook
VCLBook
Table of Contents
1 © FunctionX, Inc.
Table of Contents Borland C++ Builder
2 © FunctionX, Inc.
Table of Contents Borland C++ Builder
3 © FunctionX, Inc.
Table of Contents Borland C++ Builder
4 © FunctionX, Inc.
Table of Contents Borland C++ Builder
5 © FunctionX, Inc.
Table of Contents Borland C++ Builder
6 © FunctionX, Inc.
Table of Contents Borland C++ Builder
7 © FunctionX, Inc.
Table of Contents Borland C++ Builder
Position
Click
Double-click
Right-click
Drag
Click and hold down the left mouse button, then move the mouse to the new,
indicated location.
For one word or a group of words, position the mouse on one end and drag it to the
other end until the dragged section changes color.
For more techniques on using the mouse, the keyboard, or a combination, refer to the
Introduction to Microsoft Windows tutorial.
Highlight
8 © FunctionX, Inc.
Table of Contents Borland C++ Builder
The Keyboard
Type
Type a character or numeric value
N
Press the indicated to cause an action.
I+°
Press both keys simultaneously and release.
I+~
Press and hold the first key, then type the other key.
9 © FunctionX, Inc.
Table of Contents Borland C++ Builder
Chapter 1:
Borland C++ Builder IDE
10 © FunctionX, Inc.
Introduction to Objects Borland C++ Builder
There are various you can launch the program. The most common way consists of
clicking.
To create a shortcut on the desktop, in Microsoft Windows higher than Win95, click Start
Programs Borland C++ Builder, right-click C++ Builder 6 and click Send To
Desktop (Create Shortcut)
11 © FunctionX, Inc.
Windows Events Borland C++ Builder
Bcb’s IDE is structurally classical application. On top, there is a title bar that displays the
name of the application and the program currently running. The title bar itself is made of
three sections.
Fig 1.2
Title bar
4. The main section of the title bar displays the C++ Builder 5 name of the
application, and the name of the program that is running. A C++ Builder
program is called a project. When Bcb starts, it creates a starting project
immediately, and it names the starting project, Project1. If or when you add
other projects, they take subsequent names such as Project2, Project3, etc. This
main section of the title bar is also used to move, minimize, maximize the top
section of the IDE, or to close Bcb. On the right section of the title bar, there are
three system buttons with the following roles
Button Role
Minimizes the window
Maximizes the window
Restores the window
Closes the window
Under the title bar, there is a range of words located on a gray bar; this is called
the menu.
In this book, the word “Main Menu” refers to the menu on top of
the IDE.
To use a menu, you click one of the words and the menu expands.
1. Click File. There are four main types of menus you will encounter.
12 © FunctionX, Inc.
Windows Events Borland C++ Builder
As an example, on the main menu, click Tools and click Editor Options…
6. On the Editor Options dialog, click OK.
For example, on the main menu, click Edit and position the mouse on Flip
Children.
8. To dismiss the menu, click Edit.
9. To dismiss the menu, click Edit again.
10. Notice that on the main menu (and any menu), there is one letter underlined on
each word. Examples are F in File, E in Edit, etc. The underlined letter is called
an access key. It allows you to access the same menu item using the keyboard.
In order to use an access key, the menu should have focus first. The menu is
given focus by pressing either the Alt or the F10 keys.
To see an example, press Alt.
11. Notice that one of the items on the menu, namely File, has its border raised. This
means the menu has focus.
12. Press p and notice that the Project menu is expanded.
13. When the menu has focus and you want to dismiss it, press Esc.
For example, press Esc.
14. Notice that the Project menu has collapsed but the menu still has focus.
13 © FunctionX, Inc.
Windows Events Borland C++ Builder
15. Press f then press o. Notice that the Open dialog displays.
16. On most or all dialog boxes that have either an OK, Open, or Save buttons,
when you press Enter, the OK, Open, or Save button is activated. On the other
hand, most of those dialog boxes also have a Cancel button. You can dismiss
those dialogs by clicking Cancel or pressing Esc.
As an example, press Esc to dismiss the Open dialog.
17. On some menu items, there is a combination of keys we call a shortcut. This key
or this combination allows you to perform the same action on that menu using
the keyboard.
If the shortcut is made of one key only, you can just press it. If the shortcut is
made of two keys, press and hold the first one, while you are holding the first,
press the second key once and release the first key. Some shortcuts are a
combination of three keys.
To apply an example, press and hold Ctrl, then press S, and release Ctrl.
18. Notice that the Save As dialog box opens. To dismiss it, press Esc.
Click here then 1. Drag the grippers of one toolbar down and right:
drag down and
right
3. Borland’s toolbars (and almost anything you see) can be positioned anywhere on
the screen. To position the toolbar back or to somewhere else, drag its title bar to
the desired location.
14 © FunctionX, Inc.
Windows Events Borland C++ Builder
4. You can get a list of the toolbars that are currently displaying if you right-click
any button on any toolbar or menu.
For example, right-click a toolbar and notice the list of toolbars:
Fig 1.4
List of
Toolbars
As an example, position the mouse (don’t click) on the button that looks like a
piece of paper bent on its top right corner and see the hint:
Fig 1.5
Hint
7. Without clicking, move the mouse to another button and to other buttons. Notice
that some button’s hints also display a shortcut that would lead to the same
action.
8. To use a toolbar’s button, you click it. For example, click the New button .
Notice that the action calls the New Items dialog box.
9. Press Esc to dismiss the New Items dialog box.
10. Some buttons present an arrow on their right side. This arrow represents a menu.
To see an example, position the mouse on the Open button . Click the
arrow that appears and observe the menu.
11. Press Esc to dismiss the menu.
15 © FunctionX, Inc.
Windows Events Borland C++ Builder
Fig 1.6
The
Component
Palette
The Component Palette holds many objects that you will be using to create your
applications. The Component Palette, like a toolbar, can be moved to any location on the
screen; but it is a good idea, if possible, to always keep it at its default location.
The Component Palette is made of objects categorized in different tabs. To display a
particular tab, you click it.
Practical Learning
1. For example, click the Win32 tab.
Whenever the Component Palette cannot display all of its tabs; there are two
horizontal arrows that allow you to reveal the hidden tabs .
To reveal more tabs, click the right pointing arrow.
2. Click the ActiveX tab.
3. Click the Standard tab.
4. Once again, it is obvious to predict what a button is used for. The best
alternative is to position the mouse on a button for a few seconds until a hint
appears.
Position the mouse on any button on the Component Palette and observe the hint
that appears.
1. To see what the current application looks like, on the main menu, click Run
Run.
16 © FunctionX, Inc.
Windows Events Borland C++ Builder
2. Notice that a dialog box displays showing the evolution of compiling the
application:
Fig 1.7
Compilation
Process
Besides designing forms (and applications), one of your most regular jobs will consist of
writing code that directs the computer as to what to do, when, and how. This is done in an
appropriate window called the Code Editor.
The Code Editor is featured text editor adapted for coding purposes. It is programmed to
recognize the parts of a program that are recognized by C++ or not. To access the Code
Editor, if you have a form opened, you can press F12. The Code Editor manages your
jobs by organizing them into property pages (also called tabs). If your project contains
Fig 1.8 more than one file, you can click the desired tab to access one of the files. The basic
building block of a program is called a C++ file, and Borland calls it a Unit. Whenever
The Code
you start Bcb, C++ Builder creates a starting project that has a C++ file called Unit1
Editor
while the project is called Project. Eventually, you will change these names to those you
window
like. A typical code of a form, such as the one we have now, is built from at least two
files: a header file and a source file. The file displaying now is called the source file; it
gives direct instructions to the computer as to what to do on the form and why. The
foundation of this source file (which is also the foundation of the form is in a file called
the header file. By default, Bcb does not display this file at startup; you have to request it.
To display the header file of the form, you can right-click the source file and click Open
Source/Header File. Indeed, this action is used to toggle both displays. Since the source
and the header go in pairs (when using classes), they hold the same name but different
extensions.
17 © FunctionX, Inc.
Windows Events Borland C++ Builder
What is called an object in real world is referred to as an object in C++, and an object is
build using a class. To organize the objects involved in a program, C++ Builder uses a
special window called the Class Explorer. As its name implies, it is used to navigate to
various objects.
The Class Explorer is positioned on the left side (or section) of the Code Editor. It is
organized in a tree view format with the name of the project as the root. To view the
objects that part of a project, expand the tree.
You can close or hide the Class Explorer any time and bring it back at will. You can also
permanently hide or for a while, which we will do at this time.
18 © FunctionX, Inc.
Windows Events Borland C++ Builder
4. To bring back Class Expplorer, on the main menu, click View -> Class Explorer
5. To permanently hide the Class Explorer (for a while), on the main menu, click
Tools -> Environment Options…
6. Click ClassExplorer
7. Uncheck the Automatically Show Explorer
8. Click OK.
One of the best (if not the best) features of Borland C++ Builder (and other compilers of
the company) and its easy of use and accessibility of designing objects. This is even
enhanced by the presence of another special window called the Object Inspector. This is a
window that lists the characteristics of the object that you are using to design an
application.
We will review the various uses of the Object Inspector when we can take advantage of
them.
A program would not mean much unless it accomplishes the desired purpose. To examine
how your development is proceeding, as a beginning programmer, you should regularly
ask C++ to show you the result.
The (small) program we have written is really plain English, something we can read and
analyze. Unfortunately, the computer does not understand what it means; this is because
the computer "speaks" its own language called Machine Language. For the computer to
understand what your program means, you need an intermediary program that can
translate your English to machine language and vice versa. This program is called a
compiler, and it is supplied to you. The process of executing a program is done in various
steps that Borland C++ Builder can resume as one.
There are three ways you can execute a program in Borland C++ Builder. To execute a
program, you can press F9, you can also use the main menu where you would click Run ª
Run. On the toolbar, you can also click the Run button
1. On the Debug toolbar, click the Run button . As you see, the program does not
do much because we did not write a formal assignment.
2. To close the DOS window, press any key on your keyboard.
19 © FunctionX, Inc.
Windows Events Borland C++ Builder
There are two main sources of help available for Borland C++ Builder. The first source
of help is provided with the compiler, this is from the Borland Company. This help is
mainly electronic and hardly printed. Fortunately, you have access to this help even if
you are not designing an application. Everything considered, this is the closest and the
highest documentation that the compiler provides.
To access C++ Builder help, on the task bar, click Start Program Borland C++
Builder Help, and make your choice from the categories.
Another place you can find information is on the Internet. Fortunately, most of that help
is free. On the Borland’s help site, the company provides a list of some sites that deal
with Borland compilers. Unfortunately, many of these sites tend to treat C++ Builder and
Delphi as one entity, which is not the case.
Although the best challenger to Microsoft Visual C++, C++ Builder does not enjoy the
number of (independent) books that are published for MSVC. Fortunately, since there is a
good presence of Win32 API in C++ Builder, it is very important that you have access to
the Microsoft Developer Network documentation. It is available free from
http://msdn.microsoft.com and on CD-ROM or DVD.
20 © FunctionX, Inc.
Windows Events Borland C++ Builder
5. Notice that the help window displays, click the advance button .
21 © FunctionX, Inc.
Windows Events Borland C++ Builder
Chapter 2:
Applications Fundamentals
22 © FunctionX, Inc.
Windows Events Borland C++ Builder
A Windows control is a graphical object that allows the user to interact with the
computer. These controls are as varied as the needs and the goals are. Although controls
are meant to ease the user’s experience, their design and creation are left to the computer
programmer. Each company that publishes a compiler provides a set of controls that are
not necessarily available on other compilers. Borland C++ builder is enjoying the
reputation of providing (one of) the richest development environments in the world of
Windows.
A container is a control whose main purpose is to host other controls. To design it, you
pick up objects from the Component Palette and drop them where desired. The most
common and the most widely used container is the form. In Bcb, a form can be
configured to display like a regular dialog box or to become a Single Document Interface
(SDI).
The other system you will be using to control a window is with code, writing the
program. This is done by typing commands or instructions using the keyboard. This is
considered or referred to as Run Time. This is the only way you can control an object’s
behavior while the user is interacting with the computer and your program.
Even as the design and the run times provide the means of creating or testing your
application, there are three ways you can add a control to a program. The visual design is
the technique that allows you to visually add a control and manipulate its display. This is
the most popular, the most regularly used, and the easiest technique. Unfortunately,
23 © FunctionX, Inc.
Windows Events Borland C++ Builder
sometimes you will not be able to add a control when designing the application.
Therefore, the other technique consists of creating a control using code.
The form is the most fundamental control of Windows applications. By itself, a form
means nothing and is almost useless. Its importance is on its being a host for other
controls. Therefore, a form is considered a container.
There are various ways you can create a form in Borland C++ Builder. The easiest way is
provided by the IDE which automatically opens with a readily available form. Another
means of creating a form is by clicking the New Form button on the View toolbar.
If one form is not enough, you can add another and other forms to your application. To
do this, you have three options. You can click the New Form button on the View
toolbar. From the main menu, you can also click File New Form. As a third option,
you can either click the New button on the Standard toolbar, or on the main menu, you
click File New Other… When the New Items dialog box, also called the Object
Repopsitory, displays, you can double-click the Form icon. Any of these techniques adds
a new form to your application. The names of the forms are incremental, by default. For
example, the second form you visually add to your application is named Form2, the third
would be Form3, etc. Using the control properties, you can change the names of your
controls.
If you visually add two (or more) forms to your application, you will need to link them,
allow them to exchange information. Since each form is created in its own unit, to let one
form know the existence of another, you must include its unit. A form or unit that wants
to communicate with another is called a client of the form. For example, if Unit2 wants to
use information stored in, or controlled by, Unit1, Unit2 needs to include Unit1 in its list
of header files; and Unit2 becomes a client of Unit1. There are two simple ways you can
24 © FunctionX, Inc.
Windows Events Borland C++ Builder
do this. Imagine you have created Form1 stored in Unit1 and Form2 stored in Unit2. If
you want to have access to Form2 from Form1, using C++, on top of the source file of
Unit1, include Unit2’s header file:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
C++ Builder provides another technique. After making sure that either Form1 displays on
the screen or a Unit1 tab is displaying, on the main menu, click File Include Unit
Hdr… From the Use Unit dialog box, click the unit name you want to include to the
current unit and click OK. Bcb will automatically add the right and selected header to the
client.
There are various categories of controls and objects on the Component Palette, some of
which you will hardly use.
25 © FunctionX, Inc.
Windows Events Borland C++ Builder
8. Release the mouse. Notice that a memo has been added to the form.
9. There are other controls that do not use dimensions. You just click them and
click on the form. Their presence is more important on a form than their
physical location.
To see an example, on the Component Palette, click the Dialogs tab.
26 © FunctionX, Inc.
Windows Events Borland C++ Builder
When designing an application, you will usually position the desired controls on a form.
This is when you decide which control you need, where it will be positioned on the form
and with regard to other controls, and what behavior should be customized.
27 © FunctionX, Inc.
Windows Events Borland C++ Builder
Fig 1.15
Drawing a
Control
28 © FunctionX, Inc.
Windows Events Borland C++ Builder
15. To add another control, on the Standard tab, click the ActionList control .
16. Click and drag on the form to draw a tall and wide rectangle. Then release the
mouse.
17. Notice that the new control keeps a constant shape.
18. To add another form, on the View toolbar, click New Form .
19. While Form2 has focus, on the Standard tab, double-click the Edit control to
place it on Form2
22. Make sure the new panel is still selected. From the Standard tab, double-click
the Edit control:
Fig 2.17
Adding a
control to a
container
29 © FunctionX, Inc.
Windows Events Borland C++ Builder
23. Notice that the new edit box is positioned in the center of the panel and not in
the center of the form. This is because the Panel control is a “container” and can
hold its own controls.
24. On the Standard tab, click the Edit control.
25. Click inside the panel but just above the Edit2 edit box.
There are two main techniques used to give focus to a control. On the form, click the
desired control. On the other hand, you can select the desired control on the combo box
on the upper section of the Object Inspector. You can also select a control by clicking its
name in the Object TreeView.
To select a form, click an unoccupied area on the form. If the form is hidden, press F12 to
toggle between the form and the code. If your application has more than one form, to
display one of them, on the main menu, click View Forms and select the desired form
from the list.
30 © FunctionX, Inc.
Windows Events Borland C++ Builder
3. Click OK
4. To select one of the controls, click the memo box. Also notice the Name field in
the Object Inspector:
31 © FunctionX, Inc.
Windows Events Borland C++ Builder
10. While one of the controls, namely Edit1 is still selected, press the up, down, left,
and right arrow keys on the keyboard to select other controls on the form.
11. Click anywhere on the form and not on a control. Notice that the form is
selected. You can verify this by checking the name on the top section of the
Object Inspector.
12. On the form, click Memo1 to select it.
13. To dismiss the selected control, press Esc. Notice that the form is now selected.
14. To hide the form, press F12.
15. To display the form again, press F12.
16. To select two controls, on the form, click Edit2.
17. Press and hold Shift.
18. While you are still holding Shift, click Edit3 and click the ActionList button.
19. Release Shift. Notice that the controls have handles on their corners, indicating
that they are selected. The Object Inspector displays properties that are common
to the selected controls.
20. To make another selection, just under the lowest edit box on the form, click and
drag up and right as to draw a rectangle that would touch Edit2, Edit3, and
Memo1:
Fig 2.21
Drawing a
control
Starting Point
21. Then release the mouse. Notice that the touched controls are selected.
22. Press Shift + F12 to display the View Form dialog box.
23. Press the down arrow key to select Form2 and press Enter. Notice that Form2
displays.
32 © FunctionX, Inc.
Windows Events Borland C++ Builder
To move a control, click and hold your mouse on it; then drag your mouse to the desired
location. To move a group of controls, first select them; then click one of the selected
constrols and drag to the desired location. If the controls are hosted by another control,
you can move all of them when moving the container.
There are two valuable dialog boxes available to move controls. To solve alignment
issues, access the Align dialog from the main menu by clicking Edit Align… When
dealing with relative dimensions, call the Size dialog by clicking Edit Size…
The Alignment Palette is a window that can be used to deal with both alignments and
control spacing. To access it, on the main menu, click View Alignment Palette. To
find out what a button on that window is used for, position the mouse on a particular
button for a few seconds until a hint displays.
33 © FunctionX, Inc.
Windows Events Borland C++ Builder
34 © FunctionX, Inc.
Windows Events Borland C++ Builder
27. On the Size dialog box, in the Width section, click Shrink to Smallest:
28. Click OK
29. While the controls are still selected, on the main menu, click View Alignment
Palette.
30. On the Align window, click Align Left Edges
31. Notice all selected controls share the same left alignment.
32. Close the Alignment Palette.
33. To deselect, click anywhere on the form
Handle Role
Moves the seized border in the North-West <-> South-East
direction
Shrinks or heightens the control
Moves the seized border in the North-East <-> South-West
direction
Narrows or enlarges the control
35 © FunctionX, Inc.
Windows Events Borland C++ Builder
To change the properties of a control at design time, you will use the Object Inspector.
Each field on the Object Inspector has two sections: the property’s name and its field
valule. The box on the right side of each name represents the value of the property that
you can set for an object. There are various kinds of fields you will use to set the
properties. To know what particular kind a field is, click its name. But to set or change a
property, you use the box on the right side of the name.
36 © FunctionX, Inc.
Windows Events Borland C++ Builder
Fig 1.10
Error
Message Box
Fig 1.11
An error from
typing an
invalid value.
You can click OK to dismiss the error dialog and type a new valid value.
To collapse the field, click the – sign. Some of the set properties are created from an
enumerator. Since the field was created as a set, this allows the property to have more
than one value. For example, the BorderIcons property can have the minimize and the
maximum button. Some other fields that have a plus sign are actually complete classes or
a combination of classes.
37 © FunctionX, Inc.
Windows Events Borland C++ Builder
Action Fields: Some fields would require a list of items and need to be controlled by an
intermediary action. Such fields display an ellipsis button . When you click the button,
a dialog box would come up and you can set the value for the field. You can also double-
click the field value to call the dialog.
There are various types of selection fields. Some of them display just two items. To
change their value, you can just double-click the field. Some other fields have more than
two values in the field. To change them, you can click their arrow and select from the list;
you can also double-click until the desired value is selected. On some other properties,
you can double-click the field and a dialog would come up
Fig 1.12 Every control has a particular property as its default. This means that, when you visually
Error add the control to a form or container, its default property is selected in the Object
Message Box Inspector. If you start typing, that default property will receive your change. The default
property of the form is the caption. The caption of a form is the word or group of words
that display(s) on its title bar. Whenever you add a new form to your application, if you
start typing, the Caption field in the Object Inspector would receive the change.
At design time, you can only set the caption as text. At run time, you can control and
programmatically display anything on the caption of the form. To change the caption at
run time, you can use a function, a method, or an event. Just type “Caption = “ and the
sentence you want. For example, you can display today’s date on the caption as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::ChangingFormCaption()
{
Caption = "Today is " + Date();
}
//---------------------------------------------------------------------------
You can also indirectly control the caption. For example, after the user has typed his or
her name in an edit box, you can display it in the form’s caption as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::ChangingFormCaption()
{
Caption = Edit1->Text;
}
//---------------------------------------------------------------------------
38 © FunctionX, Inc.
Windows Events Borland C++ Builder
An important property of a control is its name. The name of a control allows you and the
compiler to relate to the control. To change the name of a control, when the control is
selected, on the Object Inspector, click the Name field to highlight it. Type a new name.
You should not try to change the name of a control at run time, unless you absolutely
know what you are doing. This is because the compiler needs to know the name of a
control all the time.
Except for the form, every window control of your application is hosted by another
control. The form, on the other hand is housed by the screen of your monitor. For this
reason, the positon of the form is relative to the screen. At design time, you can position
the form anywhere on your screen and when you run the application, the form would
appear following that position. This is based on the fact that the position of the form is
controlled by the TPosition enumerator. The default position of the form is recognized as
designed if you do not change the Position property.
The dimensions of a form are controlled by its Left, its Top, its Width, and its Height
properties. The measurement starts on the top-left corner of the window host where the
origin is set to 0,0. The Left property represents the length from the left border of the
screen to the left border of the form. In the same way, the Top property measures the
length from the top border of the screen to the top border of the form. As their names
indicates, the Width property represents the width of the form and the Height property is
the height of the form. These measurements are integer types:
Left
0,0
Top
Height
Width
To change the dimensions of the form at design time, click the name of the desired
property to highlight it and type a valid value. When you press Enter and/or move to
another field or property, the form will apply the new value.
To change a dimension at run time, in the function where you want to use it, type the
name of the property followed by = and followed by a valid value. For example, you can
change the width of a form named Form1 as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::ChangingFormWidth()
{
39 © FunctionX, Inc.
Windows Events Borland C++ Builder
Width = 248;
}
//---------------------------------------------------------------------------
If a form is hosting more than one visual control, you can control which control has focus
when the form launches. This is set using the ActiveControl property. To set the active
control, click the ActiveControl field to display its combo box. Click the arrow of the
combo box and select one.
The Align property is mostly used by controls other than the form. Therefore, I would
suggest you hardly use it for a form, although you can. The Align property allows you to
control how the form would be positioned relative to the screen when it starts.
The Anchors field controls how a control is positioned or dimensioned when its host
control is resized. You will hardly use this property with a form because the form usually
does not have a parent container: a form is already a container.
The BorderIcons property allows you to decide what system buttons the form would
display. By default, the form has the Minimize , the Maximize , and the Close
buttons. Optionally, if you are creating a dialog box, you can add a Help button. To
change the border icons, click the + on the property’s name to display the list. Since this
proerty is a set you can choose one or more of the sub-properties. To change a sub-
property, click it to show its combo box; you can change it by setting it to true or false, as
needed:
Fig 2.2
Setting the
system
buttons on a
form
The BorderStyle property is a good place to configure the appearance of the form.
40 © FunctionX, Inc.
Windows Events Borland C++ Builder
The WindowState property specifies how the form must appear when it opens. The
default value is wsNormal, which means that the window would display normally when
it launhes. If you want the form to be maximized when it is called, set this property to
wsMaximized. A form with wsMinimized WindowState would not appear on the screen
when it is called, but it would appear on the taskbar where the user can restore or
maximize it as desired.
41 © FunctionX, Inc.
Windows Events Borland C++ Builder
The Color property controls the background of a control. In this case, you can use it to
change the form’s color. When you click the Color name field, a combo box would
appear with a list of colors. You can then choose one color from the list. The list of colors
of the Color property is derived from the TColor enumerator:
Fig 2.3
Color
Property
If none of the colors suits you, double-click the field section, on the right column of
Color. A dialog box would come up; and you can use it to select or set a color:
To change the form’s background color at run-time assign a long integer to the Color
keyword. For example Color = 568698. If the number is not qualified, you would receive
a warning although the application would run fine. To avoid the warning, you should cast
the number as a TColor object. Here is an example:
The user of your application will have the ability to resize the form when using your
application. If the form is not a classic dialog box, by default, the user can resize it to any
dimensions allowed by the screen resolution; the minimum is to have the system buttons
and just a tiny part of the caption. You can set the minimum height, the maximum height,
42 © FunctionX, Inc.
Windows Events Borland C++ Builder
the minimum width, and the maximum width allowed on the form when the user decides
to resize it. This property is controlled by the Constraints property. The Constraints
property is controlled by the TSizeConstraints class which is inherited from the
TPersistent class. Although it is a class, you should never declare it. The control that uses
a Constraints class will create and initialize an instance of the class. The MinWidth,
MinHeight, MaxWidth, and MaxHeight are integer values you can set using the
keyboard. To set the constraints of a control that has this property, click the + sign of the
Contraints name in the Object Inspector, click the field desired and type an integer
value. To programmatically control the constraints of a control, call the
TSizeConstraints::Property and type the desired value. In the following example, when
the user tries to resize the Form1 form, the minimum and maximum dimensions of the
form are already set and would not change:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
Form1->Constraints->MinHeight = 300;
Form1->Constraints->MinWidth = 500;
Form1->Constraints->MaxHeight = 400;
Form1->Constraints->MaxWidth = 565;
}
//---------------------------------------------------------------------------
Fig 2.5
The Load
Picture
Dialog
43 © FunctionX, Inc.
Windows Events Borland C++ Builder
Fig 2.6
The Picture
Editor Dialog
44 © FunctionX, Inc.
Windows Events Borland C++ Builder
26. On the Color dialog box, click the Define Custom Colors >> button.
27. To change the color, double-click the Red edit box and type 255
28. Press Tab and, in the Green edit box, type 236
29. Press Tab and, in the Blue edit box, type 217
Fig 2.4
The Color
Dialog
3. From the Component Palette, click Edit and click on the form to add Edit1
4. Add other edit controls as Edit2, Edit3, and Edit4.
45 © FunctionX, Inc.
Windows Events Borland C++ Builder
5. From the Standard tab of the Component Palette, click Button to add a
button control to the form
6. Add one more button.
7. Add two more Edit controls as Edit5 and Edit6
8. Move and resize your controls and the form as follows:
Fig 2.14
Form Design
Fig 2.11
Tab Sequence
This Edit
Control has
focus
Fig 2.12
Form
Navigation
This Button
Control has
Focus
46 © FunctionX, Inc.
Windows Events Borland C++ Builder
21. Click OK
22. To test the form, press F9.
23. On the form, Press Tab a few times and notice the new sequence of navigation.
24. Close the form.
There are two main categories of events that will occur in your application, those from
your user doing something and those controlled by the operating system.
A user initiates an event based on what your application presents. For example, if you
expect the user to click a button, then an event associated with clicking the button will
47 © FunctionX, Inc.
Windows Events Borland C++ Builder
fire. If the user is supposed to type, then the appropriate event will be fired when the user
types.
The computer itself, that is, the operating system, has its own events and controls them.
For example, when the computer starts, the operating system controls many events that
occur. When you start Borland C++ Builder, the computer fires events that control how
Bcb displays on your screen. The computer also controls the time on your computer; this
is very important.
Your job as a programmer is to anticipate what event could occur for a particular control
that is part of your application. Not all controls have or can fire events, and not all
controls can fire the same events; but many controls share events of the same category.
We will review controls and their associated events when we learn to design each
particular control.
The users of your program will mainly use the mouse and the keyboard to interact with
your application. These two objects are the primary sources of using events. Therefore,
you will mainly deal with events associated with either the mouse or the keyboard.
Whenever possible, you should also give users the option of using either the mouse or the
keyboard to perform the same action. Whenever possible and necessary, make sure the
user can use the mouse or the keyboard without encountering different behaviors for the
same intended purpose.
As soon as you release the mouse button, the mouse fires another event called the
OnMouseUp event.
Whenever you are moving your mouse on a form or a control, the mouse is firing another
event called the OnMouseMove event. This is useful when you want to detect what the
user is doing or where the mouse pointer is located.
Since the mouse has two buttons and the user can use either of them, the program locates
the mouse at all times using a coordinate system with its origin on the top left corner of
your monitor.
48 © FunctionX, Inc.
Windows Events Borland C++ Builder
Mouse top
position
Mouse left position
Y
The axes of the mouse location are directed to the right and down. The horizontal
location of the mouse is represented by X (going right) and the vertical location is
represented by Y (going down). The compiler is designed to recognize not only the left
and right but also the middle – if any – buttons of the mouse. This is done using the
TMouseButton structure that has the mbLeft, mbRight, and mbMiddle values that
represent each button..
There are two actions you will take with regards to the mouse. You can consider the
previous three mice events separate. To program these events, you will ask the compiler
to find out which button was clicked.
C++ Builder also recognizes the currently popular mice with wheels. Therefore, you can
also program the OnMouseWheel, the OnMouseWheelDown, and the
OnMouseWheelUp events.
When the OnMouseDown and the OnMouseUp events are combined, the compiler
simply considers that the mouse was clicked. In this case, a special common event called
the OnClick event is fired. Actually, the previous mouse events completely depend on
the mouse and they are highly used in programs that involve intense mouse movements
where the programmer needs to usually find out what mouse button is or was pressed.
Examples of these programs are drawing, word processing, etc.
When the mouse click occurs, to make programming a little easier, the compiler hands
responsibility to the control where the mouse was clicked. That is, the control that
initiated the event. Therefore, the OnClick event, one of the most regularly used events,
belongs to the control. Besides finding out which button was clicked, you will also be
concerned with what should happen when a particular control is clicked.
Many other events relative to the mouse can be customized or configured when they
occur on the control
49 © FunctionX, Inc.
Windows Events Borland C++ Builder
When the user presses a key on the keyboard, the OnKeyDown event fires. When she
releases the key, the OnKeyUp event occurs. The OnKeyPress event occurs when the
user presses one key.
The keyborad events are useful when you need to find out which key was pressed on a
control. For example, you can perform different assignments of a form when the user
presses Enter or Tab and you can ask the application to ignore all the other keys. On the
other hand, you can write an application that would validate an action only if a certain
key or a combination of keys is pressed.
The names of the keys, as you will use them in your program, are listed in the winuser.h
file. Under no circumstance should you ever include that file in your application. Instead,
you can include the windows.h header file. To get an exaplanation of each key, in the
help file of Bcb, do a search on virtual key codes.
Many events are shared among controls that anticipate the user to perform a similar
action. For example, to use most controls, the user is supposed to click; therefore, many
controls have an OnClick event. Some other events are appropriate for particular
controls.
When the content of an edit or a memo control changes, the OnChange event fires; this
is appropriate because it happens almost all the time and you should take appropriate
actions, such as dismissing a wrong data the user has provided.
An event is qualified as default because it is the most likely event used on a control. For
example, when thinking about a button, the first action that comes in mind is to click it.
Therefore, OnClick is the default event of a button.
Depending on how the control was created and configured, when a control has a set of
events, if you double-click it from the form, it would open the Code Editor with the
default event ready to receive code.
50 © FunctionX, Inc.
Windows Events Borland C++ Builder
When an event has been initiated, you would be transported to the Code Editor and the
cursor would be positioned in the event, ready to receive your instructions. To customize
an event, the compiler divides its structure in three sections:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
{
// Write code associated with the event here
}
//---------------------------------------------------------------------------
The coding of an event starts with its return value. Most events in C++ Builder return a
void. All events use the fastcall convention.
The return type is followed by the name of the parent class from where the event would
be fired. This is mainly the class that controls the form. By default, the name of the
starting form is Form1. The class that controls the form holds the same name following
Borland’s convention of class names. Therefore, the class that creates Form1 is called
Tform1. If you rename the form, such as frmMain, the compiler would update the name
of the class; in this case the class would be renamed TfrmMain. The above event would
be changed to:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::FormMouseMove(TObject *Sender, TShiftState Shift,
int X, int Y)
51 © FunctionX, Inc.
Windows Events Borland C++ Builder
{
// Write code associated with the event here
}
//---------------------------------------------------------------------------
After the name of the class, the compiler rightly uses the class member access operator
(::) to call the event.
The name of an event is made of a combination of the control that “owns” the event and
the name of the event. For example, if a form fires the OnCreate event, the compiler
would name the event FormCreate. If a button called Button1 fires an OnClick event,
the compiler would call it Button1Click event.
Each event has at least one argument, the TObject *Sender. Some events use additional
arguments that we will review when coding such events.
The default event of a form is the OnCreate. This event is fired as soon as a form
displays on the screen. This is the favorite place you would programmatically initialize
the form and some of your variables. For example, if you want the form to be maximized
at startup, you can ask the compiler to take care of that when the form launches, using the
OnCreate event as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
WindowState = wsMaximized;
}
//---------------------------------------------------------------------------
The OnClick event occurs when the user clicks anywhere on the screen but outside of a
control.
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClick(TObject *Sender)
{
if( Color == 0x05F9C617 )
Color = TColor(0x00D9ECFF);
else
Color = TColor(0x05F9C617);
}
//---------------------------------------------------------------------------
When the user double-clicks an unoccupied area on the form the DblClick event fires.
52 © FunctionX, Inc.
Windows Events Borland C++ Builder
//---------------------------------------------------------------------------
void __fastcall TfrmSecond::FormCreate(TObject *Sender)
{
Width = 405;
Height = 350;
Caption = "I know you called me!";
}
//---------------------------------------------------------------------------
8. To display the main form, on the main menu, click View Forms…
9. On the View Form dialog box, click frmMain and click OK.
10. To include the header of the other form, on the main menu, click File Include
Unit Hdr…
11. From the list, Unit2 should be clicked already, otherwise click it
53 © FunctionX, Inc.
Windows Events Borland C++ Builder
13. On the Object Inspector, click the Events tab and double-click the event field of
the OnDblClick field.
14. Implement the event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::FormDblClick(TObject *Sender)
{
frmSecond->ShowModal();
}
//---------------------------------------------------------------------------
15. To test the program, press F9.
16. Move the form from its current position by dragging its title bar.
17. To call the second form, double-click in the middle of the form.
18. After viewing the form, close it. Also close the main form.
19. To add another form to your application, on the main menu, click File New
Form.
20. Change the name of the new form to frmFloater
21. On the Object Inspector, click the OnCreate name and double-click the event
field.
22. Implement the event as follows:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit3.h"
// Include the dependent header file
#include "Unit2.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmFloating *frmFloating;
//---------------------------------------------------------------------------
__fastcall TfrmFloating::TfrmFloating(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TfrmFloating::FormCreate(TObject *Sender)
{
// The appearance should be that of a floating window
BorderStyle = bsToolWindow;
// Keep this floating always on top
FormStyle = fsStayOnTop;
// Change the form's background color
Color = TColor(RGB(202, 238, 255));
// Make sure this window aligns with the top-left
// corner of the calling form
Top = frmSecond->Top;
Left = frmSecond->Left;
54 © FunctionX, Inc.
Windows Events Borland C++ Builder
25. Click OK
26. Press F12 to display the second form.
27. Press Alt + F11 to call the Use Unit dialog. Double-click Unit3.
28. On the Object Inspector, double-click the OnClick event.
29. Implement the event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmSecond::FormClick(TObject *Sender)
{
frmFloater->Visible = !frmFloater->Visible;
}
//---------------------------------------------------------------------------
30. To test the program, press F9
31. To display the second form, double-click the main form.
32. To display the floating form, click the second form. Notice that the floating
window appears.
33. Move the second form and try to position it on top of the floating window.
Notice that the floating window is always on top of the second window.
34. Click the second form again. Notice that the floating form reappears.
35. Click the second form again to display the floating window. Make sure the
floating window display.
36. Close the second window
37. Display the second form.
55 © FunctionX, Inc.
Windows Events Borland C++ Builder
//---------------------------------------------------------------------------
void __fastcall TfrmSecond::FormClose(TObject *Sender,
TCloseAction &Action)
{
if( frmFloater->Visible )
frmFloater->Close();
}
//---------------------------------------------------------------------------
40. Press F9 to test the program.
41. Display the second form.
42. Click the second form to display the floating window.
43. Close the second form. Notice that the floating window has been closed.
44. Close the main form.
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
TForm1* Former = new TForm1(this);
}
//---------------------------------------------------------------------------
The problem with a duplicate is that, unless you go through a big deal of code writing,
everytime you do anything on the form, the duplicate produces the same action. For
example, if you use the above code, everytime you double-click the form, a new
duplicate is created. Therefore, the second option you have on creating a local object is to
create a fresh form. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
TForm* Former = new TForm(this);
}
56 © FunctionX, Inc.
Windows Events Borland C++ Builder
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TForm* Comet;
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
If you try running the application, you would receive a noisy warning that seems
harmless:
If you insist, you can click No and the program would compile and run fine. But, this
would be unprofessional and unpredictable. This is because you would have declared a
non-visually added control to your application. The solution is to make sure you declare
your dynamic object in one of the other sections. If you want the form to be available
outside of the parent form that “owns” the header file, you must declare it in the public
section. Otherwise, you should declare it in the private section:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
TForm* Comet; // A dynamically created form
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
57 © FunctionX, Inc.
Windows Events Borland C++ Builder
After declaring the form, since you cannot initialize a variable in the header file, you can
use the constructor of the host form to initialize the dynamic form. This is done by using
the new operator and initializing the TForm class with the this pointer, like this:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Comet = new TForm(this);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
TForm* Former = new TForm(this);
Former->ShowModal();
}
//---------------------------------------------------------------------------
If the form was created globally, you can use almost any event to display it. The best way
to display such a form is through a button, which we will learn soon. Otherwise, to
display a glogally created form when the user double-clicks the main form, you can
write:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
Comet->ShowModal();
}
//---------------------------------------------------------------------------
After creating a form, such as Comet, you can programmatically set any of its properties
and use any of its methods.
58 © FunctionX, Inc.
Windows Events Borland C++ Builder
After creating and using a form, you should make sur the memory allocated to it is
regained. The Borland C++ Builder compiler can take care of cleaning your dynamic
controls when the application exists. Otherwise, you can delete it manually:
delete MyForm;
Furthermore, to avoid any memoly leak, you can reclaim the dynamically allocated
memory by assigning NULL to the deleted object:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
TForm1 *Cosmos = new TForm1(this);
Cosmos->ShowModal();
delete Cosmos;
Cosmos = NULL;
}
//---------------------------------------------------------------------------
A form’s scroll bar is a horizontal or vertical control used to navigate in two directions
along the form by clicking one of the arrows. A form is configured to automatically add
one or two scroll bars if needed; this happens when one or more of the hosted controls
goes “overboard”; instead of resizing itself, the form displays a scroll bar (or two if
necessary):
59 © FunctionX, Inc.
Windows Events Borland C++ Builder
There are three main ways to use a scroll bar. If you click one of the arrows, the content
of the form would slide in the opposite direction, revealing the previously hidden or
unavailable section of the form. You can also click the rectangular bar itself, hold the
mouse on it and drag. Another use of the scroll bar consists of clicking in the scrolling
region of the control.
If you dynamically create a form, its AutoScroll is set to true by default. If you do not
wish to ever display the scroll bars, specify it:
60 © FunctionX, Inc.
Windows Events Borland C++ Builder
The horizontal scroll bar of a form is configured using the HorzScrollBar property. The
vertical scroll bar of a form is controlled from the VertScrollBar property. To
manipulate any of these properties at design time, on the Object Inspector, click the + of
the desired properties to expand it:
Both the HorzScrollBar and the VertScrollBar properties are created from the
TControlScrollBar class.
For the scroll bar to display, its Visible property must be set to true, which is the default. If you do not
want to display one particular scroll bar, you can set this property to false. Although this setting seems to
apply the same property as the TScrollingWinControl::AutoScroll, the TControlScrollBar::Visible
property applies only to a specific scroll bar object. To change this property programmatically, you would
use code such as:
A scroll bar is configured to slide from one minimum value to a maximum. The minimum value is 0. The
maximum value is that of the ClientWidth property. This value is controlled by the Range property and is
set by default to 0. If you add a control that exceeds the right border of the form, a horizontal scroll bar is
added, then the compiler calculates the necessary value of the range based on the ClientWidth value of the
form and the usable (area that can be used) width of the far right control. This calculation results in a
Range long enough so the user can scroll and display the content of the form completely. If you want to
control this value, change the integer value of the Range field. If you set a value less than the
ClientWidth, the horizontal scroll bar would disappear and the user would not see hidden parts of the
exceeding control(s). You can also set this value so that only part of the exceeding control would appear.
As stated already, when you add a control that exceeds the right section of the form, the compiler sets the
range so enough room, but not more than enough, is available to display the whole control. By setting the
value of the Range to more than the “regular” value, you can display the form beyond the right border of
61 © FunctionX, Inc.
Windows Events Borland C++ Builder
the far right control. These rules apply in the same way to the Range property of the vertical scroll bar,
controlled by the VertScrollBar property, based on the form’s ClientHeight.
When a horizontal scroll bar appears, the rectangular bar is positioned on the far left side of the scroll bar.
If there is a vertical scroll bar, it would be on the top section of the control. The position of this bar is
controlled by the Position property which is an integer value. This property is set using an integer value
and is related to the Range value. When a form appears, by default, the Position is set to 0, which is the far
left for the horizontal and the top for the vertical scroll bars. As the user slides a scroll bar, the position of
the bar is: Position = Range – ClientWidth. At design time, you can set where the bar would be positioned
by setting the Position to a value less than Range – ClientWidth.
When the user clicks an arrow on a scroll bar, the control slides by one pixel in the opposite direction. This
value is controlled by the Increment property. If one pixel is not enough, you can set this value to your
liking.
The physical height of the horizontal scroll bar and the width of the vertical scroll bar are controlled by
their respecticve Size property. The side measurement of the arrow button on each side of the scroll bars is
controlled by the ButtonSize property.
For aesthetic reasons and others, there are three styles of scroll bars, controlled by the TScrollBarStyle
enumerator. The most common and default Style is ssRegular which results in raised border arrow buttons
and a raised bar. To get flat scroll bars, set the Style to ssFlat; this adds a “web” effect to the control. The
borders appear when the mouse is on top of an arrow button or the central bar. If you Style is set to
ssHotTrack, the arrow buttons or the bar reverses their color when the user positions the mouse on top.
As a visual control, a scroll bar can benefit from color that set it apart from the rest of the form. By default,
a scroll bar inherits the color of the form that hosts it. This is set from the ParentColor property. Since the
default color of a form is clBtnFace, this applies to the the scroll bar. To change this and assign a different
color to a scroll bar, change its Color property to any color you like. The new color would apply to the
scrolling region.
62 © FunctionX, Inc.
Windows Events Borland C++ Builder
Chapter 3:
Fundamental Controls
Forms
Command Buttons
Labels
Text Boxes
Introduction to Expressions
63 © FunctionX, Inc.
Windows Events Borland C++ Builder
There are various kinds of buttons. The most common and regular is a rectangular object
that the user can easily recognize and use. In some environments, the classic button is
called a Command Button. There are other controls that can serve as click controls and
initiate the same behavior as if a button were clicked. Such controls include a label, a
static control, or a panel.
From the programmer’s standpoint, a button needs a host; this could be a form, a toolbar,
or another container. Once you have decided where the button will reside, you can use
the drag n’ drop process of Borland C++ Builder to add it to your program
When adding a button to a form, the Caption field would have focus only if the last
action you performed on the Object Inspector was for a control that does not have
Caption. If the last control you were working on has a caption property but you
were setting another property, when you add a button, the Caption field would not
have focus.
The most popular captions are OK and Cancel. The OK caption is set for a dialog that
informs the user of an error, an intermediary situation, or an acknowledgement of an
action that was performed on the dialog that hosts the button. The Cancel caption is
usefull on a button whose parent (the form) would ask a question or request a follow-up
action from the user. Whenever a dialog box allows the user to dismiss it without
continuing the action, you should provide a button with a Cancel caption.
The easiest way to change the caption on a control, on the Object Inspector, click the
word Caption and type the desired caption.
64 © FunctionX, Inc.
Windows Events Borland C++ Builder
After adding a button to a form (by design or with code), you can change its caption with
code by calling the TControl::Caption property. For example, you can change the caption
of a button as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::ChangeButtonCaption()
{
Button1->Caption = "Let Me Go!";
}
//---------------------------------------------------------------------------
To the programmer, one of the most important properties of any control is the Name.
This allows you and the compiler to know what control you are referring to when the
program is running. By default, the first button you add to a form is named Button1, the
second would be Button2. Since a program usually consists of many buttons, it would be
a good idea to rename your buttons and give them meaningful names. The name should
help you identify what the button is used for. To change the name of a control, on the
Object Inspector, click the word Name and type a valid C++ name. Refrain from trying
to change the name of any control with code.
//---------------------------------------------------------------------------
void __fastcall TForm1::SetTheActiveControl()
{
ActiveControl = Button3;
}
//---------------------------------------------------------------------------
A very important property of a button is the Default property. The Default is a Boolean
property. If you set its value to true, this button will have a thick border; this means that
if the user presses Enter any time, the action associated with the button would be
executed. This is usually set on a dialog box with a button whose caption displays OK.
Another useful property that you should always set, or whenever possible, is the Cancel.
Using a Boolean variable, the Cancel property allows the user to press Esc to perform the
same action that would be used to dismiss a dialog box. This is important on a dialog box
if the button’s caption is Cancel or Close.
The position of the control is controlled by the Left and Top properties. The dimensions
of the control are set by the Width and Height properties.
65 © FunctionX, Inc.
Windows Events Borland C++ Builder
If the form or dialog that is hosting the button is not the first form
or dialog (in other words, if the form or dialog is accessed by a
call from another form or dialog), you can use the ModalResult
property to conveniently associate an action. By default, the
ModalResul is set to mrNone. The ModalResult property is an
integer that represents a button that the user has clicked on a
dependent dialog box. This is a very useful and convenient way to
find out what button the user clicked, without going through a lot
of code. To use a button as a valid integral ModalResult, set its
ModalResult property. When coding the result of the user clicking
one of the buttons, call the TForm::ShowModal() method (once
again, the ShowModal() method actually belongs to the
TCustomForm class) and assign it the corresponding value of the
TModalResult integer.
The following example uses two forms. The first form has a button used to call the
second. The second form has buttons with different ModalResult values.After the user
clicks the button on the first form, the second would display and the program simply
finds out what button was clicked and the programmer can act accordingly:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( Form2->ShowModal() == mrOk )
Caption = "I am OK now";
else if( Form2->ShowModal() == mrCancel )
Caption = "Soldier, dismiss!!!";
else
{
Form2->Close();
Caption = "What happended? Where are you?";
}
}
//---------------------------------------------------------------------------
Depending on what you are trying to do, sometimes you will not want the user to see a
control until another action has occurred. To hide a control, use the Visible property. As a
Boolean value, the Visible property toggles the appearance and the disappearance of a
control. To set the visibility of a control, give focus to the control. On the Object
Inspector, you can click the arrow of the combo box or you can double-click the value of
the field until the desired value is set. To programmatically hide a control, use the
TControl::Visible property. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::HideTheControl()
{
Button1->Visible = False;
}
//---------------------------------------------------------------------------
Another useful feature of C++ Builder comes in toggling the appearance and the
disappearance of a control. The only thing you have to do with the Visible property is to
reverse its state. This will come very handy when using menus and toolbars, etc (imagine
how easy it is to hide or display a control or a menu item with one line of code, no
pointer, no dynamic creation or declaration of any class). The following example toggles
the appearance of a form by checking whether the control (in this case the seond form) is
displaying or not. If the control (the second form) is visible, it gets hidden and vice-versa:
66 © FunctionX, Inc.
Windows Events Borland C++ Builder
//---------------------------------------------------------------------------
void __fastcall TForm1::ToggleControlAppearance()
{
Form2->Visible = !Form2->Visible;
}
//---------------------------------------------------------------------------
Also a Boolean value, the Enabled property allows you to enable or disable a control.
When a control is enabled, it can perform and respond to all of its normal operations. A
disabled button cannot receive focus and most, if not all, of its properties and actions
cannot be performed or acted on. You can set and control the Enabled property the same
way you would do with the Visible property.
If you position a (visual) control on a form, if the control is positioned on the top left
section of the form, when the user resizes the form, the control’s position would appear
static, it would not move. This is a concern if the control is positioned on the right, the
bottom or the lower right section of the form. When the user resizes the form, the
button’s position would not be updated. Sometimes you will want the control to have the
same measurement with regard to the bottom, the right, and/or the lower right corner of
the form. This ability is controlled by the Anchors property. The anchoring of a control
to its parent or host container is controlled using a set property derived from the
TAnchors enumerator. By default, when you add a control to a form, it is “glued” to the
top left corner of its container. Since this property is a Set, you can the control’s position
with regards to its container’s right and bottom borders.
.
3. Click on the form. Notice that a button has been drawn on the form.
4. To move the button, click and hold your mouse on it. Then drag to the desired
location, for example, move it to the upper left section of the form.
5. On the Standard tab of the Component Palette, double-click the Button control.
6. On the form, move the second button, Button2, and position it under Button1
7. On the form, click Button1 to select it.
8. On the Object Inspector, click Caption and type &Close
67 © FunctionX, Inc.
Windows Events Borland C++ Builder
9. Notice that its caption has changed. Also notice the Caption field in the Object
Inspector.
10. In the Object Inspector, click the Name field and type btnClose
11. On the form, click Button2 to select it.
12. Type btnQuit
13. Notice that this time, the name has changed because the Name field had focus.
14. On the Object Inspector, click the Caption field and type &Quit
15. To make this button dismiss its form when the Esc key is pressed, double-click
the false value of the Cancel field to change it to true.
16. Click anywhere on the form and change its dimensions to Height = 152 and
Width = 315.
17. To test the form, press F9.
18. After viewing the form, close it.
One of the most regular actions you will assign to a button is the close its parent form
when the user clicks the button. There are different reasons you will want to close a
dialog. If the form or the dialog that hosts the button displays an intermediary message to
the user, you should provide all the necessary code to follow up after the user has clicked
the button; this is the case of property sheets or wizard pages, among others. When
studying message boxes, we will review other situations of dismissing a dialog box by
clicking a button.
There are various ways you can close a dialog box from a button. The simplest way is to
call the TCustomForm::Close() method; this dismisses the form. To close a form, you
can also use the Win32’s PostQuitMessage() function. This function takes one argument
which is an integer. The argument could be set to almost any integer value although it
should be WM_QUIT.
Close();
3. Click the arrow of the combo box on the top section of the Object Inspector and
select btnQuit
68 © FunctionX, Inc.
Windows Events Borland C++ Builder
Note
The PostQuitMessage()
PostQuitMessage(WM_QUIT);
function is part of the 8. To test the form, on the Debug toolbar, click the Run button.
Win32 library
9. Click the Close button. Notice that this action closes the form.
10. Click the Run button again to execute the program.
11. Press Esc. Notice that the form closes also and this takes you back to Bcb.
12. Change the PostQuitMessage as follows:
PostQuitMessage(0);
13. Execute the program to test it. Click the OK button to close the form.
14. Press F12 to display the form.
15. Double-click the Quit button to get to the Code Editor. Notice that you are taken
back to the Code Editor. Edit the PostQuitMessage() function as follows:
PostQuitMessage(WM_DESTROY);
16. To test the form press F9. After viewing the form, close it.
17. To add another form, on the View toolbar, click the New Form button.
18. While the new form is still displaying, on the Object Inspector, click the
Properties tab and set the following properties for the second form: BorderStyle
= bsDialog; Caption = Mission and Assignment; Height = 260; Width = 395
19. Press and hold Shift. On the Component Palette, click the Button control.
Release the Shift key.
20. Click on the form three times to add three buttons
69 © FunctionX, Inc.
Windows Events Borland C++ Builder
21. On the Component Palette, click the arrow button to dismiss the Button
control selection.
22. Arrange the three buttons on the form to make them visible.
23. Set the properties of the first button as follows: Caption = OK; Default = true;
ModalResult = mrOk
24. Set the properties of the second button as follows: Cancel = true; Caption =
Cancel; ModalResult = mrCancel;
25. Set the properties of the 3rd button as follows: Caption = Abort; ModalResult =
mrAbort.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Form2->ShowModal();
}
//---------------------------------------------------------------------------
33. Add another button to the form and enlarge it to cover most of the unoccupied
area on the form. Set the name of the new button to btnMessage and its caption
to Message
70 © FunctionX, Inc.
Windows Events Borland C++ Builder
34. While the new button is still selected, on the Object Inspector, click the field on
the right side of the Font property (it displays (TFont).
35. Set the characteristics to Font = Times New Roman, Font Style = Bold, and
Size=14. Click OK
36. Double-click the new large button and implement its OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnMessageClick(TObject *Sender)
{
if( Form2->ShowModal() == mrOk )
btnMessage->Caption = "I came back OK";
else if( Form2->ShowModal() == mrCancel )
btnMessage->Caption = "I was dismissed!!!";
else if( Form2->ShowModal() == mrAbort )
btnMessage->Caption = "Mission Impossible";
else
btnMessage->Caption = "What's Happening?";
}
//---------------------------------------------------------------------------
37. To test the project, click the Run button.
38. After testing the application, close it
39. To create a new project, on the main menu, click File New…
40. Make sure Application is selected and click OK.
41. When asked to save the project, click No.
42. On the Object Inspector, click Caption and type Form and Buttons Interaction
43. Click Height and type 280
44. Click Width and type 380
45. From the Standard tab of the Component Palette, double-click Button.
46. On the Object Inspector, click Caption and type &Juventus
47. Click Name and type btnTeam
48. Click Left and type 16. Click Top and type 16
49. On the Component Palette, double-click Button
71 © FunctionX, Inc.
Windows Events Borland C++ Builder
50. On the Object Inspector, click the + of the Anchors properties. Set its
characteristics as follows: akLeft = false; akTop = false; akRight = true;
akBottom = true.
51. Click Caption and type &Sidney
52. Click Left and type 288
53. Click Name and type btnCity
54. Click Top and type 216
55. To test the project, press F9.
56. To resize the form, position the cursor on the lower-right corner then drag down
and right. Notice that the Sidney button is anchored to the bottom and right
borders of the form. Close the form
57. On the Component Palette, double-click Button.
58. Change its Caption to &Turtle, its Left value to 288, its Name to btnAnimal,
and its Top value to 16
59. On the Component Palette, double-click Button.
60. Set its Caption to &Hamburger, its Left value to 16, its name to btnFood, and
its Top value to 216
61. On the Component Palette, double-click Button
62. Change its Cancel field to true and its Caption to Close
63. Change its name to btnClose
Close();
66. Press F12 to display the form
72 © FunctionX, Inc.
Windows Events Borland C++ Builder
BtnClose->Enabled = False;
68. To test the form, on the View toolbar, click the Run button.
69. Click Juventus. Notice that the Close button is disabled.
70. Click the Close button on the form. Notice that it is not working
btnClose->Enabled = !btnClose->Enabled;
73. Press F12 to display the form
74. Double-click the Turtle button and implement its OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
btnAnimal->Left = Width - 92;
btnClose->Top = (ClientHeight - btnClose->Height) / 2;
btnClose->Left = (ClientWidth - btnClose->Width) / 2;
}
//---------------------------------------------------------------------------
82. Press F12 to display the for. To test the form, press F9.
83. Resize the form by enlarging or shrinking it. Notice how the turtle and the Close
buttons are anchored to the borders of the form.
73 © FunctionX, Inc.
Windows Events Borland C++ Builder
To create a dynamic button, use the TButton contructor. Declare a pointer to a TButton
object and use the new operator to assign the constructor. There are two important pieces
of information you need to provide. The instance of the object and the container of the
control.
//---------------------------------------------------------------------------
void __fastcall TForm1::CreateAButton()
{
TButton* Btn = new TButton(this);
Btn->Parent = this;
}
//---------------------------------------------------------------------------
The problem with a locally created object is that it is available only in the function or
event in which it is created. You cannot access it outside the function or event. The
alternative is to create the object globally in the header file of its host.
To create an object globally, in the private or the public section of the parent’s header
file, declare a pointer to the contructor:
private:
TButton* Foot;
In the constructor of the host, use the new operator to assign an instance of the object’s
contructor:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Foot = new TButton(this);
}
//---------------------------------------------------------------------------
74 © FunctionX, Inc.
Windows Events Borland C++ Builder
Once you have the object initialized, to display it, set its parent and the desired
properties:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Foot->Parent = Form1;
Foot->Caption = "I'm Running";
Foot->Left = 220;
Foot->Top = 205;
}
//---------------------------------------------------------------------------
3.2 Bevels
A bevel is a VCL control used to enhance the display of a form by adding a box, a frame
or a line. A bevel shares a lot of the other controls properties, this means that you can
modify them at design and/or run times.
The two most important properties of a bevel are its shape and its style. The Shape
property is a TBevelShape enumerator that controls how the bevel appears. You can set
the bevel to appear as a line, to show borders or to be empty. To set the shape of the
bevel, click it on the form to select it. On the Object Inspector, click Shape to reveal its
combo box and select from the list. To set the bevel’s shape programmatically, use code
such as this:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Bevel1->Shape = bsFrame;
}
//---------------------------------------------------------------------------
With the cursor positioned on the right side, press Ctrl + Space to displcy the valid values
and select from the list. The Style property is a TBevelStyle enumerator that specifies
whether the bevel will be lowered or raised with regard to the surface of its host
container.
75 © FunctionX, Inc.
Windows Events Borland C++ Builder
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Height = 228;
Bevel1->Visible = False;
}
//---------------------------------------------------------------------------
10. Press F12 to display the form. Double-click the Details button to initiate its
OnClick event. Implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( Height == 228 )
76 © FunctionX, Inc.
Windows Events Borland C++ Builder
{
Height = 456;
Bevel1->Visible = True;
Button1->Caption = "&No Details";
}
else if( Height == 456 )
{
Height = 228;
Bevel1->Visible = False;
Button1->Caption = "&Details >>";
}
}
//---------------------------------------------------------------------------
11. To test the application, on the Debug toolbar, click the Run button.
You should never call the TBevel class, if you want to dynamically create a bevel,
declare a TBevel object. Using the new operator, assign it the bevel constructor
specifying the control component as the form on which the bevel will be positioned. You
must also specify the control parent of the bevel. You can dynamically create a bevel
inside of a function or another control’s event. In the following example, a bevel is
created in an OnClick event of a button called Button2:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TBevel* Bvl = new TBevel(Form1);
Bvl->Parent = this;
}
//---------------------------------------------------------------------------
If you create a bevel in a function, the control would not be available to other sections of
a program. If you want the control to be global, declare a TBevel object in the unit’s
header file in the private or the public sections:
In the form’s constructor, initialize the control using the new operator and specifying the
component that would host the control:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Beauty = new TBevel(Form1);
}
//---------------------------------------------------------------------------
After creating the control, you can programmatically set its properties. If the control was
created locally, set these properties in the function or event:
77 © FunctionX, Inc.
Windows Events Borland C++ Builder
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TBevel* Bvl = new TBevel(Form1);
Bvl->Parent = this;
Bvl->Height = 115;
Bvl->Left = 8;
Bvl->Shape = bsFrame;
Bvl->Style = bsRaised;
Bvl->Top = 8;
Bvl->Width = 210;
}
//---------------------------------------------------------------------------
If you had created the control in the header file, you can use a function or event to
initialize the control:
//---------------------------------------------------------------------------
void __fastcall TForm1::ControlTheBevel()
{
Beauty->Parent = Form1;
Beauty->Left = 240;
Beauty->Width = 146;
Beauty->Top = 80;
Beauty->Height = 100;
Beauty->Style = bsRaised;
}
//---------------------------------------------------------------------------
To manipulate the control, you can use any event of the form. For example, the following
code sets the bevel’s anchors:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender)
{
Beauty->Anchors = TAnchors() << akRight << akBottom;
}
//---------------------------------------------------------------------------
78 © FunctionX, Inc.
Windows Events Borland C++ Builder
To add a panel to a form, click the Panel control from the Standard tab of the Component
Palette. Then click in the desired location on the form. Although you can create a panel to
be a container standing on its own, at design time, the only way you can use the control is
to add it to a form.
After adding a control to a container, you may want to “glue” it to one border or corner of
its host, as you would do with the Anchors property. Unlike anchoring a control, the
Align property allows you to fix a control to one border of its host:
79 © FunctionX, Inc.
Windows Events Borland C++ Builder
Most controls that use a caption allow you to control how such text would be aligned as a
paragraph. The Alignment property is a TAlignment enumerator that lets you align text
to the left (default), the center, or the right. If the control, such as a panel would not
display a caption, you can leave this property “as is”. To change the Alignment property,
click it on the Object Inspector to reveal its combo box. Click the arrow and select the
desired value: taLeft, taCenter, or taRight.
Three specific bevel properties allow you to customize the appearance of a panel. A panel
object is drawn with two borders: an inner and an outer borders. You can decide which
one or both would use the bvNone, bvLowered, bvRaised, or bvSpace. Using a
combination of these values on the BevelInner and BevelOuter fields, you can create
special effects for the apperance of a panel. The other property to take into consideration
is the BevelWidth value. This is an integer that controls the border value of a panel.
Playing with these three values can tremendously transform the appearance of a panel.
Another property that acts on a panel’s display is the BorderStyle; this controls the line
used to draw the contour of the panel.
A panel can be used as a button, in which case the user would click it to initiate an action.
A panel can also simply display a message to the user. In any case you want to display a
word or a group of words, you can use the Caption property to show it.
A property that is highly used on forms and panels is the Color. If you change the Color
property, the new color would cover the face of the panel:
80 © FunctionX, Inc.
Windows Events Borland C++ Builder
One of the most useful actions performed on a panel consists of involving it in drag and
drop operations. A panel can serve as the source or the destination on such an operation.
The DockSite property uses a Boolean value to indicate that the control, in this case the
panel, can serve as the host for a drag’n’drop operation. The DragKind property
specifies how the control participates in the drag’n’drop operation. If the control serves as
a docking host, set its DragKind property to dkDock. On the other hand, if the control
will itself be used when dragging, set its DragKind property to dkDrag. If a control is
“draggable”, use the DragMode property to specify how the dragging operation on the
control would be initiated. If you want the dragging operation to be possible when the
user clicks the control, set its DragMode property to dmAutomatic. Otherwise, some
controls, depending on the result you are trying to achieve, should be available for
dragging only depending on an intermediary action. In such a case, you can write your
program so that the dragging operation on a control would be available only after the
application or another event or control has called the TControl::BeginDrag() method. In
this case, set the DragMode property to dmManual.
3.4 Affiche
The form painted.
Practical Learning: Form Events
1. Double-click:
2. Press it.
3. .
4. Implement the FormClick event as follows:
81 © FunctionX, Inc.
Windows Events Borland C++ Builder
5. code to:
3. To .
4. Implement it as follows:
5. Scroll up on the Code Editor and, under the #include "Unit1.h" line, add the
following:
6. To field.
7. Implement it as follows:
82 © FunctionX, Inc.
Windows Events Borland C++ Builder
3.5 Exercises
83 © FunctionX, Inc.
Windows Events Borland C++ Builder
Chapter 4:
Introduction to Text Controls
84 © FunctionX, Inc.
Windows Events Borland C++ Builder
To add a label to a form, click it from the Standard tab of the Component Palette and
click on the form. You can also dynamically create a label.
A label is a child of the TCustomLabel class which itself is derived from the
TGraphicControl class.
When you type the caption of a label, C++ Builder helps its size itself so the caption can
be fit. If you edit the label, as you delete or add characters, the label resizes itself. If you
want to fix the size of the label regardless of its caption, set the Boolean property
AutoResize to false. By default, this property is set to false on most controls that use; but
on a label, it is set to true.
If you want to create a shadow effect using a label object, you can place one label on top
of another. Using the Transparent property, which is a Boolean value, you can make the
top label transparent.
2. To save the current project, on the Standard toolbar, click Save All
3. Loacte the C:\BcbExercises folder. Click the Create New Folder button to create
a folder.
4. Type Employment Application and press Enter twice to display the new folder
in the Save In combo box.
5. To rename the current unit, in the File Name box, replace the name with Main
and press Enter
6. Type Employment as the name of the project and press Enter.
85 © FunctionX, Inc.
Windows Events Borland C++ Builder
7. From the Standard tab of the Component Palette, click the Label control
8. Click on the form.
9. As the new label is still selected, on the Object Inspector, click Caption and type
Date &Hired:
10. To move the new label, click and drag it to the left section of the form. To
position it precisely, using the Object Inspector, set the label’s properties as
follows: Left = 16, Top = 96
11. To add another label, on the Standard tab, double-click the Label control
12. On the Object Inspector, click the Caption field and type &First Name:
13. Set its Left property to 16 and its Top to 120.
14. Add the following other labels:
15. To add another label, click the Label control and click on the top section of the
form.
16. On the Object Inspector, click the Caption field, type Employment Application
17. Click the gray box on the right side of the Font field. Notice the ellipsis button.
18. Click the ellipsis button to open the Font dialog.
19. Change the font to Times New Roman
20. In the Font Style combo box, click Bold.
21. In the Font Size combo box, select 24
86 © FunctionX, Inc.
Windows Events Borland C++ Builder
22. Click the arrow of the Color combo box and select Blue
23. Click OK
24. On the Object Inspector, click the Name field and type lblMainTitle
25. Double-click the box on the right side of the Transparent field. Instead of false,
it should now display true.
26. On the form, click the Employment Application label to select it.
27. On the main menu, click Edit Copy.
28. Click an unoccupied area on the form to make sure nothing is selected.
29. On the main menu, click Edit Paste.
30. As the new label is still selected, click the + on the Font field.
31. Under the Font field, click Color to reveal its combo box. Click the arrow of its
combo box and select clGray
32. Click the – on the Font field.
33. Click the Name field and type lblTitleShadow
34. Click the arrow on the top section of the Object Inspector and select
lblMainTitle
87 © FunctionX, Inc.
Windows Events Borland C++ Builder
40. Right-click on the group of those big labels. One of them will be selected. On
the context menu, click Send To Front. If the blue label does not come in front,
right-click again and click Bring To Back until the blue label is on top of the
white label:
41. To add another label on the form, on the Component Palette, double-click the
Label control.
42. While the new label is still selected, click the Caption field and type
Tenley Associates
88 © FunctionX, Inc.
Windows Events Borland C++ Builder
60. To save the project, on the Standard toolbar, click Save All.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TLabel* Lbl = new TLabel(Form1);
Lbl->Parent = Form1;
}
//---------------------------------------------------------------------------
To create a label object globally, declare a TLabel object in the private or the public
sections of the header file of the unit that owns it:
In the constructor of the unit, use the new operator to specify the component that owns
the control;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Team = new TLabel(Form1);
89 © FunctionX, Inc.
Windows Events Borland C++ Builder
}
//---------------------------------------------------------------------------
Once you have dynamically created a label, you can control it using functions or events:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TLabel* Lbl = new TLabel(Form1);
Lbl->Parent = Form1;
Lbl->Caption = "LaFace, Inc.";
Lbl->Left = 75;
Lbl->Top = 32;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
Team->Parent = this;
Team->Left = 120;
Team->Caption = "PSV Eindhoven";
Team->Top = 96;
}
//---------------------------------------------------------------------------
When your application exits, C++ takes care of cleaning all VCL objects that you had
dynamically created. If you want to perform this housekeeping yourself, delete the object
using the delete operator. It might also be a good idea to reclaim your memory to avoid
any memory leak. This is done by assigning the NULL constant to the dynamic object
previously used:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete Team;
Team = NULL;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::lblWordPadClick(TObject *Sender)
{
ShellExecute(NULL, NULL,
"C:\\Program Files\\Windows NT\\Accessories\\wordpad.exe",
NULL, NULL, SW_SHOWNORMAL);
}
//---------------------------------------------------------------------------
90 © FunctionX, Inc.
Windows Events Borland C++ Builder
Like most other controls, the role of an edit box is not obvious at first glance; that is why
it should be accompanied by a label that defines its purpose. From the user’s standpoint,
an edit box is named after the label closest to it. Such a label is usually on the left or the
top side of the edit box. From the programmer’s point of view, an edit box is a place
holder used for various things. For example, your can show or hide it as you see fit. You
can also use it only to display a text without allowing the user to change it.
To create an edit box, once again, Bcb provides a lot of choices. The most fundamental
edit box is designed with the Edit control of the Standard tab of the component palette.
Another important property of the Edit control is the Name. It makes it easy for you to
identify the control and its events when writing code.
Although it does not belong to an Edit control, the FocusControl property of a Label
control provides a convenient way to specify which control is associated with the label.
For example, if a label has a caption of &Country and you want the user to press Alt + C
to access the Edit control positioned under or on the right side of the label, select the
name of such an Edit control in the FocusControl field of the Label control.
The CharCase property allows the content of an Edit control to apply a character case of
your choice. The CharCase property is controlled by the TEditCharCase enumerator.
By default, it is set to normal, which respects whatever character case is typed in an edit
91 © FunctionX, Inc.
Windows Events Borland C++ Builder
box. Otherwise, you can set it to ecUpperCase or ecLowerCase to set the edit box’
charactrers to uppercase or lowercase respectively.
When using a form, the user can press Tab to move from one control to another. By
default, when such a control receives focus from the user pressing Tab, the whole text in
an edit control is selected. This is controlled by the AutoSelect property. If you do not
want that, you can set the AutoSelect Boolean property to false.
The Color property allows you to control the background color of an Edit control.
The Hint property provides a quick local help to the user. It is text that would appear if
the user positions the mouse on a control for a few seconds. The best or most effective
way to set this property is to set the form’s ShowHint property to true. To set the text
hint for a control, once the control is selected at design time, type a word or a few words
in the Hint field.
1. To add an Edit box, on the Standard tab of the Component Palette, click the Edit
control .
2. Click on the form.
3. To reposition the control, click and drag the Edit control to the right side of the
Date Hired label.
4. As the Edit control is still selected, on the Object Inspector, click the Name field
and type edtDateHired
5. Click the Text field and press Delete to empty its content.
6. Using the same process, add new labels and edit boxes as follows. The name of
an edit box starts with edt follows by the caption of the label omitting the
special characters:
7. Set the FocusControl property of each label to Edit control on its right.
8. To save the project, on the Standard toolbar, click Save All.
9. To test the form, press F9.
92 © FunctionX, Inc.
Windows Events Borland C++ Builder
The Edit control is equipped with many events. Some of these events are from its parent
class the TCustomEdit class and some others are from ancestor classes.
The OnEnter event occurs when the control receives focus. This happens when the user
clicks the edit box, after previously pressing Tab, to give focus to the control.
The OnChange event occurs as the user is typing text in the control. This happens as the
user is changing the content of an edit control; this sends a message that the content of
the edit box has changed or has been updated. You can use this event to check, live, what
the user is doing in the edit box. For example, if you create a dialog with a first and last
names edit boxes, you can use another edit box to display the full name. The controls
could be drawn as follows:
You can implement the OnChange event of the first name edit box as follows:
When the second edit box is being edited, you can implement its OnChange event as
follows:
The OnExit event occurs when the control loses focus. In the case of an edit box, this
could happen if the control has focus and the user presses Tab; the edit box would lose
focus.
93 © FunctionX, Inc.
Windows Events Borland C++ Builder
When a control receives focus, the OnEnter event fires. When a control loses focus, the
OnExit event fires. When the user presses a key, the OnKeyDown event fires. When the
user releases a key, the OnKeyUp event fires.
When implementing the keyboard events, you can also perform a particular operation
depending on the key that the user pressed. Each key has a virtual key code. You can find
the list of these keys in the winuser.h header file. You can shift focus when the user
presses Enter on an edit box using the following code:
4. Using the Text field on the Object Inspector, delete the content of each edit box.
5. Click Button1 to select it.
6. On the Object Inspector, click Caption and type &Reset
7. On the form, click Button2 and type E&xit.
8. Double-click the Exit button and implement its OnClick event as follows:
94 © FunctionX, Inc.
Windows Events Borland C++ Builder
Edit1->Text = "";
Edit2->Text = "";
Edit3->Text = "";
Edit4->Text = "";
}
11. To test the form, press F9
12. Type Something here and press Tab.
13. Type Another thing going on and press Tab.
14. Type Downsize and press Tab
15. Type Online outsourcing and press Enter.
16. Click Reset and notice that all buttons are empty.
17. Click Exit.
18. Press F12 to display the form.
19. Click the edit box on the top left section of the form.
20. On the Object Inspector, click the Events tab.
21. Double-click the box on the right side of OnKeyDown and implement it as
follows:
95 © FunctionX, Inc.
Windows Events Borland C++ Builder
31. On the Events tab, double-click the box on the right side of OnEnter and
implement its event as follows:
96 © FunctionX, Inc.
Windows Events Borland C++ Builder
52. To empty the second exit box when the first is empty, change the previous code
as follows:
To add a MaskEdit control to your form, from the Additional tab of the Component
Palette, click the MaskEdit button and click on the form.
Once there, you have various alternatives. The easiest way is to select one of the
available formats in the Sample Masks list. Once you select a sample, its formatted mask
displays in the Input Mask edit box. If the format is satisfying, you can click OK.
Otherwise, you can add or delete symbols in the Input Mask edit box as you see fit.
If none of the samples matches your desire and you know the symbols used, you can type
your own. You can also check masks created for foreign languages to see if one of them
97 © FunctionX, Inc.
Windows Events Borland C++ Builder
would have the mask you need. To do this, click the Masks… button. This would call the
Open Mask File dialog box:
Click one file with a .dem extension and click OK. With the new mask in the Input
Mask Editor, examine the samples in the Sample Masks list and select one. You can
still customize any of the available masks.
The 3rd alternative is to create your own list of masks. To do this, follow the format used
to create a mask. This is:
This line is made of three sections. The first and the second, then the second and the third
are separated by a beam. To see a sample file, using Notepad, locate the C:\Program
Files\Borland\Cbuilder6\Bin folder. After changing the Files of Type to All files, click
one of the files with .dem extensions:
Click Open:
98 © FunctionX, Inc.
Windows Events Borland C++ Builder
Create a new file following the example. Each mask is typed on its own line and press
Enter at the end of each mask. To save the file, locate the C:\Program
Files\Borland\Cbuilder5\Bin folder. In the Save dialog box, change the Save As Type to
All Files. Type a name in one-word followed by an extension .dem extension. To use
your list of masks, invoke the Input Mask Editor, click Masks… Locate the C:\Program
Files\Borland\Cbuilder5\Bin folder. Change the Files of Types to All files. Click the file
you created and click Open.
You can also set a mask programmatically using the symbols appropriate for the masks.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// Mask for an 8 character file name + 3-character extension
// The first character is automatically converted to uppercase
// After the first character, the user can enter an alphabetical
// character or a digit to complete the 8 characters.
// The other 7 characters and the extensions are converted to lowercase
edtFileName->EditMask = ">L<aaaaaaa.<LLL;1;_";
}
//---------------------------------------------------------------------------
As a text-based control, the content of the MaskEdit control is represented by the Text
property, which is an AnsiString object. Following the EditMask you had set in the
Input Mask Editor editor, you can use a default text that would display when the control
opens. To set this text, on the Object inspector, click Text and type a value that abides by
the rules of the EditText field. At design time, C++ Builder will assist you and make
sure that the value you type is appropriate. At runtime also, the user will have to follow
the rules of the mask.
When a mask is configured for a MaskEdit control, the compiler reinforces the rule to
make sure the user would follow number and types of characters allowed in the edit box.
If you add a MaskEdit control but do not apply a mask to it, you can limit the number of
characters tha the user can enter in the box. The maximum number of characters allowed
is set using the MaxLength property. This property has any effect only if no mask is
applied to the control. At design time, type an integer value for the property. At runtime,
assign an appropriate value to the control.
The IsMasked Boolean property can be used to check whether a MaskEdit control has
been configured with a mask already.
99 © FunctionX, Inc.
Windows Events Borland C++ Builder
.
4. Click on the right side of the Date Hired label on the form.
5. On the Object Inspector, click the Name and type edtDateHired
6. Click EditMask field to display the ellipsis button . Click the ellipsis button.
On the Input Mask Editor dialog, click Date. In the Input Mask edit box, change
the two zeros to four zeros:
7. Click OK
8. As the MaskEdit control still has focus, on the Object Inspector, click the Text
field and press Delete. Click its ellipsis button. Set the text to 12/05/1996:
9. Click OK.
10. On the Component Palette, click the MaskEdit control and click on the right side
of the Home Phone label. On the Object Inspector, click the Text field and
delete the content of the field. Click the EditMask field and click the ellipsis
button. Click Phone and click OK.
11. On the form, click the new masked edit box of the Home Phone box. On the
main menu, click Edit -> Copy. On the main menu again, click Edit -> Paste.
Move the new paste edit box to the right side of the Work Phone label.
12. Add another MaskEdit control to the right side of the Employee # label. Click
the EditMask and type 00-000;1;_
13. Add a MaskEdit control to the right side of the MI label. Set its EditMask to >L
and delete the content of the Text field.
14. Add a MaskEdit control on the right side of the ZIP label. Set its Text field to
00000 and set its EditMask to 99999
15. Add a MaskEdit control to the right side of the Ext label. Delete its Text field
and set its EditMask to #####;1;_
The external bevel around the edit boxes has a Lowered Style while the external
one has a Raised Style. The Close button resides on a Panel control. The
OnClick event of the Close button is implement with the Close(); line.
17. To test the application, on the Debug toolbar, click the Run button.
18. After viewing the form, close it.
This requires an instance of a TMaskEdit class. Using the new operator, specify the
owner of the control. You must also specify the parent of the variable. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TMaskEdit *Mascot = new TMaskEdit(Form1);
Mascot->Parent = Form1;
}
//---------------------------------------------------------------------------
A MaskEdit object created like this is just a classic Edit control. If you want to make a
true MaskEdit object, set its properties as needed, namely an EditMask and possibly a
Text properties. This time, not only will you have to work in a non-visual setting but you
should also make sure that the EditMask and the Text properties are synchronized.
Sometimes, this would involve trial-and-error.
To add a memo to a form or another container, from the Standard tab of the Component
Palette, click the Memo button and click on the desired position on the form.
As a text based control, the user mostly reads and/or enters text in the memo when
interacting with the control. At design time, you can set the text that world display when
the memo comes up. To enter this text, on the Object Inspector, click the Lines field to
reveal its ellipsis button. You can either double-click the field on the right side of Lines
or click the ellipsis button. This would call the String List Editor dialog box. If you
want the control to be empty at startup, delete the content of the String List Editor and
click OK. Otherwise, type the desired text and click OK.
The user, on the other hand has the ability to type text to alter the content of the memo
box. This is possible only if the ReadOnly property is set to true, which is the default. If
you want to prevent the user from altering the text in the memo, set the ReadOnly
property to false. You can also do this programmatically:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->ReadOnly = True;
}
//---------------------------------------------------------------------------
The user cannot enter, delete, or cut the text but can select or copy it. The application,
which means your programming, can still change the content of the memo.
When a memo box opens, the compiler registers the content of the control. If the user has
the ability to change the text in the control and if the user changes it, the compiler flags
the content as Modified. This allows you to take actions. You can acknowledge this by
programmatically setting the Modified property to true. If another control or some other
action alters the content of the memo, you can make sure that this property reflects the
change. You can change this programmatically as follows;
//---------------------------------------------------------------------------
void __fastcall TForm1::Memo1KeyPress(TObject *Sender, char &Key)
{
Memo1->Modified = True;
}
//---------------------------------------------------------------------------
Although the user can enter any number of characters into a memo box, you can set a
maximum number that would prevent the user from going over this number of characters.
At design time, you can set the maximum number of characters in the MaxLength field.
Programmatically, you can change it as follows;
//---------------------------------------------------------------------------
void __fastcall TForm1::Memo1KeyPress(TObject *Sender, char &Key)
{
Memo1->MaxLength = 24;
}
//---------------------------------------------------------------------------
If the control will be used to enter text, the user can press Enter at the end of a line to
move to the next line. This ability is controlled by the Boolean WantReturns property.
By default, this property is set to true, which means the user can press Return (also called
Enter) when typing text. If you do not want to validate the Enter key in the Memo
control, set this property to false. To set it programmatically, assign the desired value to
the WantReturns property:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Memo1->WantReturns = False;
}
//---------------------------------------------------------------------------
When the WantReturns property is set to false, if the user presses Enter while the memo
has focus, the Enter action would be transferred to the form as the parent. The form in
turn can find out what to do. For example, you can have configured the form to perform a
particular action when the Enter key is pressed. The typical example is by setting a
button’s default property to true. In this case, pressing Enter from the Memo control
would cause the action associated with the button. Even if the WantReturns of a memo
is set to false, the user can still press Ctrl + Enter to move to the next line.
In the same way, the user is accumstomed to pressing Tab to insert tab characters in the
text. By default, when the user presses Tab when interacting with your application, the
focus moves from one control to the next, following the TabOrder values of the form.
Even when using a memo to perform text editing, if the user presses Tab, the focus would
switch to another control or to the form. If you want a memo to receive focus when the
user presses the Tab key, set the WantTabs property from false (the default), to true.
Programmatically, you can do it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->WantTabs = True;
}
//---------------------------------------------------------------------------
When entering text in a Memo control, the characters start on the left side of the memo
and are subsequently added on the right side. The ability to align text is controlled by the
Alignment property. For a Memo control, the alignment is configured using the
TAlignment enumerator:
By default, the text is aligned to the left. To align the content of the memo to the center
section of the control, set its Alignment property to taCenter. To align it with regard to
the right side of the memo, set its Alignment to taRightJustify. You can also configure
this with code as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->Alignment = taRightJustify;
}
//---------------------------------------------------------------------------
As the user enters text in a memo box, the compiler considers that a paragraph starts from
the user typing a character until he or she presses Enter. Therefore, a paragrph could be
an empty space, a character, a word, a line of text, a whole page or an entire book.
Depending on the width of the Memo control, the text is incrementally added to the right
side of each previous character. If the caret gets to the right border of the control, the text
continues to the next line, although it is still considered as one paragraph. To start a new
paragraph, the user has to press Enter. The ability for the text to continue on the next line
when the caret encounters the right border of the memo is controlled by the WordWrap
property whose default Boolean value is set to true. If you do not want text to wrap to the
subsequent line, set the WordWrap property to false. You can also set it
programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->WordWrap = False;
}
//---------------------------------------------------------------------------
The Memo control is typically used to perform text editing and can therefore contain
many lines of text. Sometimes the user needs to scroll up, down, left, and right to read
different sections of the control. The memo scrollbars are set using the TScrollStyle
enumerator:
To apply the scrollbars on a memo, use the ScrollBars property on the Object Inspector.
By default, a newly added Memo control does not have scrollbars although the user can
still scroll vertically in the text. This is because its ScrollBars property is set to ssNone.
To display the vertical scrollbar, set this property’s value to ssVertical. A horizontal
scrollbar would display if this property has a value of ssHorizontal. If you need both
scrollbars, set this property to ssBoth. You can also set the scrollbars programmatically
as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
Memo1->ScrollBars = ssBoth;
}
//---------------------------------------------------------------------------
If you want to generate a memo needed only by an event or a function, create it locally.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TMemo *Notes = new TMemo(Form1);
Notes->Parent = Form1;
}
//---------------------------------------------------------------------------
Such a memo would not be accessible outside of the function or event in which it is
created. If you want to make the memo available to other functions or events, in the
header file of the control that would host it, declare a TMemo variable in the private or
public section:
private:
TMemo * Comments; // User declarations
Use the new operator to specify the owner of this control. This should be done in the first
event or function that would need to know about the dynamically crerated control.
Therefore, you should usually do this in the form’s constructor:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Comments = new TMemo(Form1);
}
//---------------------------------------------------------------------------
To display the memo, use the event or function that would initiate it. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnShowCommentsClick(TObject *Sender)
{
Comments->Parent = Form1;
}
//---------------------------------------------------------------------------
If you had created the memo locally, set any of the properties as necessary. You can
change just the default values or configure any that would affect the behavior of the
control. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnNotesClick(TObject *Sender)
{
TMemo *Notes = new TMemo(Form1);
Notes->Parent = Form1;
Notes->Left = 350;
Notes->Top = 20;
Notes->Height = 120;
Notes->Width = 320;
}
//---------------------------------------------------------------------------
If you created the memo globally, you can access it anywhere and change its properties
where appropriate:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnShowCommentsClick(TObject *Sender)
{
Comments->Parent = Form1;
Comments->Align = alLeft;
Comments->Width = 420;
Comments->Font->Color = clWindowText;
// A button called btnBackground was added to change
// or togglethe background color of the memo
btnBackground->Enabled = True;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnBackgroundClick(TObject *Sender)
{
if(Comments->Color == clWindow)
{
Comments->Color = clBackground;
Comments->Font->Color = clWhite;
}
else
{
Comments->Color = clWindow;
Comments->Font->Color = clWindowText;
}
}
//---------------------------------------------------------------------------
In order to use a memo, or any windowed control, the control must receive focus. This
could be done by the user clicking it. In the case of a memo box, the user usually gives it
focus by clicking inside of it or pressing Tab that could lead to the memo.
Programmatically, you can give focus to a control using the TWinControl::SetFocus()
method. Its syntax is:
This method does not perform any other action than to give focus to the appropriate
control. It is typically used in response to an action that should hand the window focus to
the needed control. For example, after changing the font of a memo, in order to continue
text editing, the control would naturally need to regain focus. To give focus to a memo,
you could write code such as:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnShowCommentsClick(TObject *Sender)
{
Comments->Parent = Form1;
Comments->Align = alLeft;
Comments->Width = 420;
Comments->Font->Color = clWindowText;
Comments->SetFocus();
// A button called btnBackground was added to change
// or togglethe background color of the memo
btnBackground->Enabled = True;
}
//---------------------------------------------------------------------------
The content of a memo box can have one of two states, either it is empty or it contains
something. If you want it empty, use the Clear() method. This would delete the whole
content of the control:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnClearMemoClick(TObject *Sender)
{
Memo1->Clear();
}
//---------------------------------------------------------------------------
One of the actions the user performs on a memo’s text is to select it. To select a portion
of text, the user would drag from one end of the text to the desired end. Alternatively, you
can allow the user to select the whole content of a text-based control using the SelectAll()
method. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSelectAllClick(TObject *Sender)
{
Memo1->SelectAll();
}
//---------------------------------------------------------------------------
If the user or another control or action had selected text on the memo, you can delete the
selection using the ClearSelection() method. This method first finds if some text is
selected. If so, the selected text would be discarded. If nothing is selected, the method
would not do anything. To delete a selected text, you can write:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnClearSelectionClick(TObject *Sender)
{
Memo1->ClearSelection();
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Memo1Change(TObject *Sender)
{
Caption = "* Untitled.txt";
}
//---------------------------------------------------------------------------
When the application focus moves from one to another control or the application itself to
a control, the OnEnter event is fired. When the control looses focus, an OnExit event is
fired.
Chapter 5:
A Study of VCL Strings
Many controls use AnsiString properties. All controls that use a caption (forms, panels,
labels, etc) have their Caption property set as an AnsiString. Many other controls such as
the edit box use the AnsiString class as the basis of their text. Based on these two facts,
you have already used and implemented AnsiString objects. In some other scenarios you
will need to declare and possibly initialize a string before using it.
AnsiString Country;
Since the AnsiString is a class with its own constructor, you can also declare its variable
with empty parenthese, which would be calling the class’ construtor. Here is an example:
AnsiString City();
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Country;
Country = "Madagascar";
Panel1->Caption = Country;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString City = "Antananrivo";
Edit1->Text = City;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Original = Edit1->Text;
if(Original == "")
Edit2->Text = "Why is Edit1 empty?";
}
//---------------------------------------------------------------------------
The AnsiString class provides its own function used to check whether a string is empty.
Its syntax is:
This function can be used to check whether a text-based control contains nothing but it
cannot empty a text control. The following example shows two ways of using the
AnsiString::IsEmpty() method:
//---------------------------------------------------------------------
void __fastcall TOKBottomDlg::OKBtnClick(TObject *Sender)
{
String UserName = edtUserName->Text;
if( UserName.IsEmpty() )
Panel1->Caption = "Please provide a User Name";
if( edtPassword1->Text == "" )
Panel1->Caption = "You need to type a password";
if( edtPassword2->Text.IsEmpty() )
Panel1->Caption = "Your account is not complete";
edtUserName->SetFocus();
}
//---------------------------------------------------------------------------
To remove any (empty) space on the left side of a string, you can use the
AnsiString::TrimLeft() method. Its syntax is:
If the original string has space on its left, this function would remove it and return a string
that is like the original without the leading space. If the original does not have any
leading space, the function would return the same string:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit2->Text = Edit1->Text.TrimLeft();
}
//---------------------------------------------------------------------------
Another function used to perform the same operation is the TrimLeft(). Its syntax is:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit2->Text = TrimLeft(Edit1->Text);
}
//---------------------------------------------------------------------------
If the original string has space on its right, this function would remove it and return the
same string without any trailing space. Otherwise, the original string would be returned:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit2->Text = Edit1->Text.TrimRight();
}
//---------------------------------------------------------------------------
Another function used to perform the same operation is the TrimRight(). Its syntax is:
The (global) TrimRight () function requires one argument as the string that needs to be
trimmed. The function returns the original string without the trailing space:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit2->Text = TrimRight(Edit1->Text);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit2->Text = Edit1->Text.Trim();
}
//---------------------------------------------------------------------------
Alternatively, you can use the global Trim() function to perform the same operation. Its
syntax is:
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit2->Text = Trim(Edit1->Text);
}
//---------------------------------------------------------------------------
• an interger
• a long integer
• a floating-point value:
• a double-precision number:
• a string
AnsiString Symbol('H');
AnsiString Int(120);
AnsiString GirlFriend("Micheline Phoon");
AnsiString WeeklyEarnings(675.15);
AnsiString Longer(-73495745);
AnsiString Silver(2.15e28);
Based on the configurations of the AnsiString constructors, you can convert any value
and make it available to a control that uses an AnsiString property. For example, you can
convert and display:
• a character:
• an interger
• a long integer
• a floating-point value:
• a double-precision number:
• a string
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
char Status[] = "Employee Status";
Caption = Status;
char *FullName = "Antoine Williams";
Edit1->Text = FullName;
}
//---------------------------------------------------------------------------
Based on this constructor, you can declare a C string, manipulate its value and use it in
your application.
This function is very valuable because it can help you perform various types of string
operations. Sometimes you will need to perform an operation that seems trivial but there
woule not be an AnsiString method that can accommodate your needs.
//---------------------------------------------------------------------------
#include <iostream.h>
#include <vcl.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
char Cont[20];
AnsiString Country;
This function considers an AnsiString variable and examines each one of its characters. If
a character is an alphabetic character in lowercase, it would be converted to uppercase. If
the character is either an alphabetical character in uppercase or it is not an alphabetic
character, it would be kept “as is”. This method also considers the Regional Settings of
the computer being used.
If you want to convert a single character to uppercase, after initializing or getting, call
this method. Here is an example:
//---------------------------------------------------------------------------
You can use this same method to convert a string to uppercase as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String S1 = "James N. Fame!";
String S2 = S1.UpperCase();
Edit1->Text = S2;
}
//---------------------------------------------------------------------------
Besides the the AnsiString method, you can use the UpperCase() function to convert a
character or string to uppercase. Its syntax is:
This function uses the same algorithm as the AnsiString::UpperCase() method. Here is
an example of using it:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String S1 = "James N. Fame!";
String S2 = UpperCase(S1);
Edit2->Text = S2;
}
//---------------------------------------------------------------------------
The AnsiUpperCase() function uses the same syntax as the UpperCase() function and
applies the same algorithm as the AnsiString::UpperCase() method. Unlike the
UpperCase() function, the AnsiUpperCase() function considers the Regional Settings of
the computer being used. Look at how these two functions convert the same French
string:
//------------------------------------------------------- //-------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject void __fastcall TForm1::Button1Click(TObject
*Sender) *Sender)
{ {
String S1 = "La maison? Ça a été brûlée!"; String S1 = "La maison? Ça a été brûlée!";
Using the Regional Settings, this function examines each character of the provided
AnsiString variable. If a character is an alphabetic character in uppercase, it would be
converted to lowercase. The case of all the other characters would be ignored.
If you want to convert a single character to uppercase, after initializing or getting, call
this method. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
String String1 = "[Borland C++ Builder]";
edtConvert->Text = String1.LowerCase();
}
//---------------------------------------------------------------------------
You can also use the LowerCase() function to convert a character or string to lowercase.
Its syntax is:
This function uses the same algorithm as the AnsiString::UpperCase() method. Here is
an example of using it:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
String String1 = "[Borland C++ Builder]";
edtConvert->Text = LowerCase(String1);
}
//---------------------------------------------------------------------------
If the local settings you are using or distributing your program to are a factor, you should
use the AnsiLowerCase() function. It processes the string in the same way as the
AnsiString::UpperCase() method but uses the same syntax as the UpperCase()
function:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
String S1 = "La version Française de Borland C++ Builder est là. "
"Elle est arrivée!";
edtConvert->Text = AnsiLowerCase(S1);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit3->Text = Edit1->Text + Edit2->Text;
}
//---------------------------------------------------------------------------
You can then use the addition operation to add as many strings as you see fit.
//---------------------------------------------------------------------------
void __fastcall TForm1::edtFirstNameChange(TObject *Sender)
{
edtFullName->Text = edtFirstName->Text + " " +
edtLastName->Text;
}
//---------------------------------------------------------------------------
6. Also implement the OnChange event of the edtLastName as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtLastNameChange(TObject *Sender)
{
edtFullName->Text = edtFirstName->Text + " " +
edtLastName->Text;
}
//---------------------------------------------------------------------------
7. Double-click the panel object to initiate its OnClick event. Implement its
OnClick event with Close();
8. To test the application, on the Debug toolbar, click the Run button.
To append two strings, besides the the addition operator “+”, you can use the
AppendStr() function. Its syntax is:
This function takes two arguments as strings. The source is added to the destination. The
function returns the destination already changed by the operation. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Destination = "Paul ";
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
char* S = Edit1->Text.c_str();
Edit2->Text = strlen(S);
}
//---------------------------------------------------------------------------
To get the length of an AnsiString variable, use the AnsiString::Length() method. Its
syntax is:
This function returns the length of the string as an integer. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString S = Edit1->Text;
Edit2->Text = S.Length();
}
//---------------------------------------------------------------------------
This method takes one argument which is the length you want the AnsiString variable to
have. If the NewLength argument is less than the length of the string, the resulting string
would be the first NewLength characters of the original string. If the NewLength
argument is less than the length of the string, the original would be preserved and
assigned to the resulting string:
//--------------------------------------------------- //---------------------------------------------------
void __fastcall void __fastcall
TForm1::Button1Click(TObject *Sender) TForm1::Button1Click(TObject *Sender)
{ {
AnsiString S = Edit1->Text; AnsiString S = Edit1->Text;
Edit2->Text = S.SetLength(7); Edit2->Text = S.SetLength(4);
} }
//--------------------------------------------------- //---------------------------------------------------
When comparing two strings, the compiler sometimes checks lowercase and uppercase
characters. Depending on the function you are using, you can ask the compiler to
consider the case of the characters; this is referred to as case-sensitivity. Some of the
functions, when performing their comparison on Dates or currency values, would refer to
the Regional Settings of your computer as set in the Control Panel.
The function requires two AnsiString variables and compares them. The comparison is
performed without case-sensitivy. If the strings are the same, the result is true (the integer
equivalent is 1); otherwise the comparison yields false (0).
You can use the SameText() function on a validation dialog like this one:
Then you can implement the OnClick() event of the OK button as follows:
//---------------------------------------------------------------------
void __fastcall TOKBottomDlg::OKBtnClick(TObject *Sender)
{
String Password1 = edtPassword1->Text;
String Password2 = edtPassword2->Text;
Boolean Result = SameText(Password1, Password2);
if(Result == False)
{
Panel1->Caption = "Your passwords do not match!";
edtPassword1->SetFocus();
}
else
{
Panel1->Caption = "Your account has been setup.";
Close();
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString String1 = Edit1->Text;
AnsiString String2 = Edit2->Text;
if(String1.AnsiCompare(String2) < 0)
Edit3->Text = "True";
else if(String1.AnsiCompare(String2) > 0)
Edit3->Text = "False";
else
Edit3->Text = "Equal";
}
//---------------------------------------------------------------------------
The function considers its own string and compares it to the string argument it takes. This
function returns:
1. a negative value if your string is less than the OtherString
2. a positive value if your string is greater than the OtherString
3. 0 if both strings are the same
To compare strings, you can also use the CompareStr() function. Unlike the
AnsiString::AnsiCompare() method, this function does not care about the Windows
Regional Settings. The syntax of this function is:
The function takes two string arguments and examines their characters incrementally.
After the comparison, the function returns:
4. a negative value if the First string is less than the Second
5. a positive value if the First string is greater tham the Second
6. 0 if both strings are the same
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString String1 = Edit1->Text;
AnsiString String2 = Edit2->Text;
if(String1.AnsiCompareIC(String2) < 0)
Edit3->Text = "True";
else if(String1.AnsiCompareIC(String2) > 0)
Edit3->Text = "False";
else
Edit3->Text = "Equal";
}
//---------------------------------------------------------------------------
Alternatively, you can use the CompareText() function to compare strings. Unlike the
AnsiString::AnsiCompareIC() method, this function does not care about the Windows
Regional Settings. The syntax of this function is:
The function takes two string arguments and examines their characters incrementally.
After the comparison, the function returns:
1. a negative value if the First string is less than the Second
2. a positive value if the First string is greater tham the Second
3. 0 if both strings are the same
You can also use the AnsiSameStr() function. Its syntax is:
The function takes the Windows Regional Settings into consideration when comparing
the First and the Second strings with case-sensitivity. If both strings are the same, the
function return true. If they are not the same, the result is false. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSendClick(TObject *Sender)
{
String EMail1 = edtEMail1->Text;
String EMail2 = edtEMail2->Text;
if(AnsiSameStr(EMail1, EMail2))
{
frmCongratulations->ShowModal();
Close();
}
}
//---------------------------------------------------------------------------
Alternatively, to compare two strings, you can use the AnsiSameText() function. Both
functions use the same syntax. Like the AnsiSameStr() function, the AnsiSameText()
considers the Regional Settings. Unlike the AnsiSameStr() function, the AnsiSameText()
function does not consider the case of the characters in the strings.
If the strings you want to compare label captions, such as those you see on a form, it
would be cumbersome to write a comparison function that would examine them. This is
because the captions on a form usually have an ampersand used to underline one of their
characters. Examples include First Name, Address, City, Full Name or Department.
Fortunately, Borland provides the AnsiSameCaption() function. Its syntax is:
This function takes two captions and compares them considering the Regional Settings .
Regardless of where the ampersand is positioned, the other characters of the captions
would be examined. If tboth captions are the same, the function would return true. In the
following example, two captions are set as First Name and First Name respectively. A
regular comparison would find them different, but the AnsiSameCaption() function
finds that both strings are the same:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
lblCaption1->Caption = "&First Name";
lblCaption2->Caption = "First &Name";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCompareCaptionsClick(TObject *Sender)
{
String Caption1 = lblCaption1->Caption;
String Caption2 = lblCaption2->Caption;
if(AnsiSameCaption(Caption1, Caption2))
Panel1->Caption = "Same captions";
else
Panel1->Caption = "Completely Different";
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(Edit1->Text == Edit2->Text)
Panel1->Caption = "Same Text";
else
Panel1->Caption = "Different Stuff";
}
//---------------------------------------------------------------------------
On the other hand the != operator checks whether two strings are not the same:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(Edit1->Text != Edit2->Text)
Panel1->Caption = "The strings are different";
else
Panel1->Caption = "The same thing everywhere";
}
//---------------------------------------------------------------------------
We learned different techniques of comparing strings and finding out whether one was
greater than the other. Using Boolean operators, you can find out solely if one string is
greater or less than another.
The < operator is used to find out whether one string is less than another. The strings are
written on both sides of the operator, like this: S1 < S2. If the left string is less than the
right string, the comparison returns true:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String S1 = Edit1->Text;
String S2 = Edit2->Text;
if(S1 < S2)
Panel1->Caption = "The first is less than the second strings";
else
Panel1->Caption = "I don't understand this!";
}
//---------------------------------------------------------------------------
The <= operator is used to find out whether one string is less than or equal to another.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String S1 = Edit1->Text;
String S2 = S1;
Edit2->Text = S2;
}
//---------------------------------------------------------------------------
You can use this method to find out the last character of a given string. In the following
example, the last character of the string in the Edit1 edit box displays in the Edit2 edit
box when the user clicks the Button1 control:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String S = Edit1->Text;
Edit2->Text = S.AnsiLastChar();
}
//---------------------------------------------------------------------------
If the AnsiString is used on a console application, you can use this same method to find
the last character of an AnsiString variable:
This function takes two integer arguments. The first argument specifies the position
where the compiler would start considering the deletion. The second argument specifies
the number of characters that should be deleted from the AnsiString variable.
If you declare an AnsiString variable called Country. You can use Country.Delete(14, 11)
to delete 11 characters starting at the 14th character:
puts(Country.c_str());
After = Country.Delete(14, 11);
puts(After.c_str());
This function takes one string, the Source argument, and returns it added the Quote
characters on both sides of the string. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtQuotedExit(TObject *Sender)
{
char *BookTitle = edtQuoted->Text.c_str();
char Quote = '"';
This function takes one string and returns it after adding a single-quote on both sides.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtQuotedExit(TObject *Sender)
{
char *BookTitle = edtQuoted->Text.c_str();
This function takes two arguments. The Source parameter is a null-terminated string that
is returned as an AnsiString value. When using the function, you must specify what
character or symbol is used as Quote. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtQuotedExit(TObject *Sender)
{
char *BookTitle = edtQuoted->Text.c_str();
char Quote = '"';
This function takes two arguments as integers. From the original string, the first argument
specifies the position of the character where the new string would start. The second
argument specifies the number of characters that would be considered when creating the
new string. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString Original = Edit1->Text;
AnsiString SubOne = Original.SubString(9, 4);
Edit2->Text = SubOne;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#include <stdio.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
AnsiString FirstName("Suzanne");
AnsiString LastName("ZOO");
AnsiString FullName = FirstName + " " + LastName;
puts(FirstName.c_str());
puts(LastName.c_str());
puts(FullName.c_str());
return 0;
}
//---------------------------------------------------------------------------
The StringReplace() function will look for the LookFor character or substring in the
Original string. If it finds it, then it will replace the LookFor character or subtring with
the ReplaceWith character or substring. You control how this operation is performed by
using the FlagToUse argument. The values you can use are to replace all occurrences of
LookFor with ReplaceWith; the flag used would be rfReplaceAll. You can also ask the
compiler not to take the character(s) case into consideration, which is done with
rfIgnoreCase. Once the TReplaceFlags argument is a set, you can use one or both of the
flags. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Edit1->Text =
StringReplace(Edit1->Text, " ", "",
TReplaceFlags() << rfReplaceAll);
}
//---------------------------------------------------------------------------
Chapter 6:
Applications Accessories
The most classic mode of WinHelp consists of a directory or table of contents that leads
to the topics that consistitute the body of the help system. WinHelp has other customized
variations such as a better looking but less commonly used Windows Explorer-like
interface with a table of contents on the left frame and the associated topics on the right
frame.
The WinHelp has almost disappeared from Microsoft products. In fact, one of the most
significance differences between Microsoft Office 97 and Microsoft Office 2000 and
later is the absence of WinHelp (but not completely). Almost the whole help system on
the new office family is built on HtmlHelp. But as you will see, there are many areas
where Microsoft did not have much choice, because of the limitations of HtmlHelp
(especially on context sensitive help issues).
The main reason I would encourage you to learn both systems is because each has its own
limitations that the other can complete.
The primary WinHelp window is vertical rectangular dialog box made of a title bar, a tab
section and three buttons at the bottom.
The title bar allows you to move the window around the screen. It is also equipped with
two buttons. The question mark button allows you to get help while using the WinHelp
dialog box. The Close button allows you to exit from the application.
On the bottom section of the windows, the left button changes its caption depending on a
particular situation on the tabs above. The Print button allows you to print something.
You can exit any time by clicking Cancel or pressing Esc.
When you open an instance of a Winhelp document, you will likely first face the
directory of Help Topics, which is represented by the Contents property page. The
Contents tab displays the chapters or issues in a tree format. Each of these chapters is
called a topic and is represented by an icon that resembles a closed book . To view the
content of a book, you have two options. You can click a topic to highlight it, then click
the Open button; you can also double-click the topic. When a topic is opened, its icon
changes from a closed book to an open one . Depending on how the issue was
configured, some topics have sub-topics. Therefore, when you open a topic, you will see
one of two icons. If a book has only chapters, each displays with an icon that has a
question mark: . If a book consists of other books, it would display other closed-book
icons. Only the question-mark icons enclose readable chapters. To open a readable topic,
you can click it to highlight it, then click the Display button; you can also double-click it.
While the Contents tab provides library of books in a tree format, the Index tab presents a
list of words in a dictionary format. To select a word, you can scroll in the list, once you
find the desired word, you can click it and click Display; or you can double-click it. To
find the explanation of a word, you can also start typing it. As you type, WinHelp will try
to match it with a word. If you do not completely type a word, the closest match would be
highlighted, you can just press Enter to display its explanation. If you type a word that
does not exist in the Index and press Enter, you would receive an error. This means
WinHelp can address only the words that are part of its index.
The Find tab allows you to compile a list of words. Once again, its list are organized like
an dictionary and you can use it to find the explanation of a topic. The Find property page
(usually) encloses the same words as the Index and adds more (depending on how the
Help file was created.
If you work for a medium to big business, it is likely that you will be writing the help file
of an application you did not create. In a small business or for your own assignments, you
will usually be writing the help file of your own application. In one or the other scenario,
you should be fairly familiar with the application.
You do not have to create your whole help document in a row. You can start by creating
a document. The best way is to simply start make your notes, sometimes by
brainstorming (the technique of writing “down” anything that comes in your mind) ideas
as related to the application. Organize your ideas in paragraphs, as many as you want. For
example, if you are writing a help file intended to guide employees when filling out a
time sheet, think of how they should interact with the application. When creating the help
file(s), you should have the aplplication with you; in fact, you should have used it a few
times. After making your notes and writing your ideas, organize and refine them by
sections of interest. Plan how the items of interest are related. Start dividing the document
in separate sections such as chapters. Each of these sections will be called a topic. A
section in this context could be made of one or various paragraphs.
After creating the main document (remember, you can continue adding words and
sections as necessary), save the document as a Rich Text Format. To do this, in Microsoft
Word, on the main menu, click File Save As… (the shortcut is F12). On the Save As
dialog box, locate the folder you want to use. It does not have to be the same folder in
which the application was created. You can even create a new folder for the help file.
Then click the arrow of the Save as Type combo box and select Rich Text Format. In the
File Name box, set the name to your liking. Click Save.
In Microsoft Word, there are two main ways you can create a page break in a document:
using the main menu, or creating the break manually. To create a page break using the
main menu, click Insert Break… From the Break dialog box, click the Page Break
radio button and click OK. To manually create a page break, click the break position and
press Ctrl + Enter. Meanwhile, in Microsoft Word, it is usually a good idea to display
non-printing characters while creating a help file. This is done by clicking the Show/Hide
button .
There will be two main types of links in your help files. A linked topic will allow the user
to jump from one topic or section to another. Another type of topic will display a pop-up
window when the user clicks it. Here is an example:
Each one of these topics must have its own Topic ID. The first category of topics consists
of those we have reviewed so far. To create the others, each one must be on its own page,
as if it were a book’s complete chapter.
The title of a topic is created as a footnot using the $ tag. To do this, click on the left
section of the title header. Then on the main menu, click Inser Footnote… In the
Footnot and Endnote dialog box,click the edit box in the Numbering section, type $ and
click OK.
A topic’s title can be a letter from a to z (in uppercase or lowercase), a word, or group of
words of up to 255 characters. You should type it in one word (although different words
are allowed), no space (although spaces are allowed), and in uppercase (although it does
not matter). An example would be INTRO
You must create a Topic ID for each topic that will need a link, whether the link will
allow to jump to another part of the help file or it will popup a (local) message. For the
help files created for our application, make a Topic ID in one word that starts with IDH_
Keywords used for indexing are created from the footnote using the A flag. To do this, in
Microsoft Word, click on the left of a topic header. On the main menu, click Insert
Footnote… In the Footnote and Endnote dialog box, in the edit box of the Numbering
section, type A and press Enter.
A dialog box is a window container used as a platform for user interaction with the
computer. By itself, a dialog box means nothing; the controls it hosts accomplish the role
of dialog between the user and the machine.
If the user is supposed to change some settings on the dialog that would affect the
subsequent application, provide at least two buttons: OK and Cancel. Configure the OK
button so that after the user has used the dialog, whatever change was made would be
validated. Therefore, set the Default property of the OK button to true so that after the
user has made changes, he or she can press Enter. Configure the Cancel button so that if
the user changes his or her mind after making changes, he or she can click Cancel or
press Esc, dismissing the dialog and discharging any change.
As you know already, when Bcb starts, it opens with a starting form. To make that form a
dialog box, simply change its BorderStyle property to bsDialog. All you have to do is
configure the dialog to behave as you see fit.
To make your development experience even faster, C++ Builder ships with a lot of dialog
boxes ready for use. These dialog boxes are equipped with an OK and a Cancel butons.
These dialogs are available on the Dialogs property page of the New Items dialog box.
2. On the New Itrems dialog box, click the Dialogs tab. Click Standard Dialog
(Vertical):
3. Click OK.
4. Press F12 to access the Code Editor. Click Unit1.cpp to display its code.
5. Once Unit1.cpp is displaying, right-click in the Code Editor and click Close
Page. You will be asked whether you want to Save the changes of the Unit1
unit:
6. Click No.
7. To test the dialog box, on the main menu, click Run Run.
8. After viewing the form, close it.
Borland C++ Builder ships with a set of ready-made objects referred to as Windows
Common Dialogs. Indeed, these dialogs are part of the operating system and are equipped
with all the necessary operations pertinent to their functionality.
To use a standard Windows dialog, from the Dialogs tab of the Component Palette, click
the desired dialog’s button and click anywhere on the form. The position of the control on
the form has no importance because it is only a representative; it will not appear when the
form is running. Once the desired dialog’s icon is on the form, place a button that will be
used to call the dialog. A dialog is called using the DialogName->Execute() method. You
can find out what button the user clicked when closing the dialog, and act accordingly.
To add a Windows common dialog to your application, you will select it from the
Dialogs page of the Component Palette.
The Color dialog box is used by various controls to change their background color. It can
also be used to control any type of color as part of the application. When the dialog
displays, at any time the user can get a larger preview of the selected color on the
Color|Solid box. The user can change the color in four different areas. The top left section
displays a list of 48 predefined colors. If the desired color is not in that section, the user
can click and drag the mouse in the colored palette. The user can also drag the right bar
that displays a range based on the color of the palette; the user can scroll up and down by
dragging the arrow. For more precision, the user can type the Red, Green and Blue value;
each uses a integral value that ranges from 1 to 255.
To add a Color dialog box to your application, click the ColorDialog button on the
Component Palette and click anywhere on the form.
The most important and most obvious property of the Color dialog is the selected color
once the user has made a choice. When the user opens the dialog you can set the default
color on the Object Inspector using the Color property. You can also set this color
programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::FormCreate(TObject *Sender)
{
ColorDialog1->Color = clRed;
}
//---------------------------------------------------------------------------
When the user has finished using the Color dialog box and clicked OK, you can find out
what color was selected by using the TColorDialog::Color property.
The regula size of the dialog is half of the picture above. By default, this normal size is
also the one the user sees when the dialog opens. You can control the regular or full size
of the dialog using the Options property. At design time, to manipulate the options, on the
Object Inspector, click the + on the Options field to expand. Since the options are
controlled by the TColorDialogOption set, you can specify as many as you want:
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::FormCreate(TObject *Sender)
{
ColorDialog1->Color = clRed;
ColorDialog1->Options << TColorDialogOption() << cdFullOpen << cdAnyColor;
}
//---------------------------------------------------------------------------
If you want to supply the user with a set of colors of your choice, you can do this using a
list of custome colors. To create this list, click the CustomColor field to reveal its ellipsis
button, then click that button to display the String List Editor dialog box. You can specify
up to 16 colors. The colors are named ColorA, ColorB, ColorC, and so on up to ColorP.
To create the list, type the ordinal name and assign it an integer number. Here is an
example:
The most important method of the Color dialog is the Execute() function. This method
occurs when the user clicks OK or presses Enter after selecting a color. You can use it to
get the selected color and use it as you see fit. The following example displays a Color
dialog when the user clicks a button on the form. When the user clicks OK on the Color
dialog, the selected color is applied to the background of the form:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ColorDialog1->Execute();
Color = ColorDialog1->Color;
}
//---------------------------------------------------------------------------
The most efficient approach is to make sure that the dialog was opened and closed
successfully, then retrieve the color if the user clicked OK to close the dialog. This is
done through a conditional call, as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(ColorDialog1->Execute())
Color = ColorDialog1->Color;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateColorClick(TObject *Sender)
{
TColorDialog* Dlg = new TColorDialog(this);
}
//---------------------------------------------------------------------------
After creating it, you can use it as a regular control. For example, you can change the
color of an Edit control on the form as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateColorClick(TObject *Sender)
{
TColorDialog* Dlg = new TColorDialog(this);
if(Dlg->Execute())
edtFullName->Color = Dlg->Color;
}
//---------------------------------------------------------------------------
To make a dynamically created Color dialog available to more than one event or
function, declare an instance of the TColorDialog class in the private or public sections of
the header file of a form or the unit that would use it:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
TColorDialog *ChangeIt;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
In the constructor, use the new operator to specify the control that would own the
dynamic object:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ChangeIt = new TColorDialog(Form1);
}
//---------------------------------------------------------------------------
When creating the object, you can specify the desired properties as you wish. Once the
object has been created, you can call it wherever you want in the object in which it is
created:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ChangeIt = new TColorDialog(Form1);
ChangeIt->Options << TColorDialogOption() << cdFullOpen << cdSolidColor;
ChangeIt->CustomColors->Add("ColorA=999662");
ChangeIt->CustomColors->Add("ColorE=668684");
ChangeIt->CustomColors->Add("ColorF=4457945");
ChangeIt->CustomColors->Add("ColorC=582558");
ChangeIt->CustomColors->Add("ColorB=2551286");
}
//---------------------------------------------------------------------------
The Visual Component Library ships with other dialog boxes useful for tasks that would
require a lot of work, such as letting the user browse the hard drive.
The VCL library provides a convenient dialog box used to browser one of the drives of
the user’s computer to locate a folder. This dialog is invoqued using the SelectDirectory()
function. Its syntax is:
This function takes three arguments and returns two values. The Caption argument
displays under the title bar but above the tree view of the dialog box. The Root is a string
that represents the name of the root drive. The Directory string is the default path folder.
This function returns a Boolean value upon exiting. Here is an example of using the
SelectDiretory() function:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDirectoryClick(TObject *Sender)
{
AnsiString Caption = "Select a Directory";
const WideString Root = "C:\"";
AnsiString Directory = "C:\\Program Files";
SelectDirectory(Caption, Root, Directory);
}
//---------------------------------------------------------------------------
When the dialog box opens, it displays two buttons OK and Cancel. The OK button is
disabled because no directory would have been selected. To use the Browse For Folder
dialog box, the user clicks the + signs to expand a folder, and the – (if any) sign to
collapse a floder. Once the user locates the desired folder, he or she must click it to
highlight it, which enables the OK button.
After using the Browse For Folder dialog box, if the user clicks Cancel or presses Esc,
whatever change was made would be dismissed and the function would return false. If
the user clicks OK or presses Enter, the function would return the full path of the folder
the user has selected. This path is the returned Directory argument. You can use a
conditional statement to find out what button the user would have clicked then use the
returned Directory string as you see fit. Here is an example:
//---------------------------------------------------------------------------
Lik the other SelectDirectory() function, this version returns two values: a Boolean and a
string. Once again, the Directory argument is required, although it is used as a sample
that the user can change. Since the root drive is not a directory, you cannot set its value as
“C:”, “C:\””, “A:”, “A:\”” or the likes. The Directory must be a valid path of an existing
folder. When the dialog displays, the string of the Directory is selected, which enables the
OK and the Cancel buttons. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
AnsiString Directory = "F:\\Corel\\WordPerfect Office 2002\\Graphics";
SelectDirectory(Directory,
TSelectDirOpts(),
0);
}
//---------------------------------------------------------------------------
Once again, the user can change the displaying folder. This time, to proceed, the user
would double-click a folder in the Directories tree view to expand the folder. Once the
user has located the desired folder, he must click it to highlight it. After selecting a folder,
the user would click OK In this case the function returns true and the path of the folder.
Two options not available on the first CreateDirectory() version can be used here. If you
want to display the Directory Name edit box, set the TSelectDirOpts set to at least:
If the user wants to use a directory that does not exist, if the directory can be created, add
the sdPerformCreate option to the set as follows:
If the user types a directory that does not exist, it would be created transparently. If you
want the user to confirm that she wants to create a new folder, add the sdPrompt option to
the set. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
AnsiString Directory = "C:\\Program Files\\Borland\\Delphi4\\Projects";
SelectDirectory(Directory,
TSelectDirOpts() << sdAllowCreate << sdPerformCreate << sdPrompt,
0);
}
//---------------------------------------------------------------------------
The last option allows you to specify a help file to provide context sensitive help to the
user. To use it, associate an integer that is mapped to the appropriate identifier in the help
file. Once you set this argument and the application has a help file, a Help button would
appear on the dialog box. Here is an example of using the help argument:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
AnsiString Directory = "C:\\Program Files\\Borland\\Delphi4\\Projects";
const int HelpMe = 12;
SelectDirectory(Directory,
A message box is a relatively small dialog box used to display a message and provide one
or more buttons. A message box is used to provide information to the user or to request a
decision (from the user). By clicking one of the buttons, the user makes a decision and
the program continues.
Message boxes are created from built-in functions from Borland and the Win32 library;
these functions shipped with the compiler.
A message box created with the ShowMessage() function uses the name of the project as
its caption. The message to display is a string that can be provided by the developer. Here
is an example:
The string can also derive from another control such as the content of an edit box, a
memo, or any text control. Here is an example:
13. To display the message on more than one line, change the event as follows:
int __fastcall MessageBox(const char * Text, const char * Caption, int Flags);
Caption
Message
Flags
The MessageBox() function takes three arguments. The first argument, Message, is a
null-terminated string representing the message that the user would read. The Text string
could be a static sentence. It could be constructed from another control. Or it could be a
combination of different strings appended using C/C++ string functions and operations.
You can create a simple message box similar to one implemented using the
ShowMessage() function to display a simple message with an OK button. In this case,
you would provide only the Message argument. Set the other two arguments as NULL.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Application->MessageBox(
"This operation can only be performed by an administrator.",
NULL, NULL);
}
//---------------------------------------------------------------------------
The second argument, also a string, is the caption that would display on the title bar of
the dialog box. You can also set it when creating the message box or you can build it
from what would be available at runtime. If you do not have a caption, you can set the
value of this argument as NULL. In that case the title bar would display Error. Therefore,
to create a less boring message box, provide the Caption argument. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Application->MessageBox("Make sure the music is playing.",
"CD PLayer Instructions", NULL);
}
//---------------------------------------------------------------------------
The third argument specifies the flags that would display on the dialog box: one or more
buttons and an optional picture. You can create a simple message box with OK as the
only button. In that case, set the third argument as MB_OK. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Application->MessageBox("Make sure the music is playing.",
"CD PLayer Instructions", MB_OK);
}
//---------------------------------------------------------------------------
To display more than one button, use a constant integer that represents a group of the
available buttons. Here are the constants and their buttons:
MB_OKCANCEL
MB_ABORTRETRYIGNORE
MB_YESNOCANCEL
MB_YESNO
MB_RETRYCANCEL
MB_CANCELTRYCONTINUE
MB_HELP
For example, to create a message box that displays the Yes and No buttons, you could
write:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
If you provide the MB_HELP as the only button, the message box would display with an
OK and a Help buttons.
The enhance your dialog and accentuate your message, you can display an icon using one
of the Win32 defined integer constants. Although you can use any icon with any button,
you should be tactful and make sure that the appearance is in accordance with the
message. The values and icons are:
The icons are used in conjunction with the buttons constant. To combine these two flags,
use the bitwise OR operator “|”. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Application->MessageBox("Do you hear any music now or any sound at all?",
"CD Player Instructions", MB_YESNOCANCEL | MB_ICONQUESTION);
}
//---------------------------------------------------------------------------
When a message box is configured to display more than one button, the operating system
is set to decide which button is the default. The default button has a thick border that sets
it apart from the other button(s). If the user presses Enter, the message box would behave
as if the user had clicked the default button. Fortunately, if the message box has more
than one button, you can decide what button would be the default. To specify the default
button, use one of the following constants:
To specify the default button, use the bitwise OR operator to combine the constant
integer of the desired default button with the buttons constant and the icon. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Application->MessageBox("Do you hear any music now or any sound at all?",
"CD Player Instructions",
MB_YESNOCANCEL | MB_ICONQUESTION | MB_DEFBUTTON2);
}
//---------------------------------------------------------------------------
Since the combination of these buttons is using the OR bitwise operator to construct the
Flags argument, it does not make a difference which constant appears first:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Application->MessageBox("Do you hear any music now or any sound at all?",
"CD Player Instructions",
MB_YESNOCANCEL | MB_DEFBUTTON3 | MB_ICONQUESTION);
}
//---------------------------------------------------------------------------
After reading the message displaying on the dialog box, the user would click one of the
buttons and the dialog would be closed. Each one of the buttons has a constant integer
number that is assigned and recognized by the compiler. You can use this number to find
out what button the user had clicked. This means the MessageBox() function returns an
integer value as in the following table:
Therefore, you can use one of these integers to act depending on the button clicked:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if (Application->MessageBox(
"Do you hear any music now or any sound at all?",
"CD Player Instructions",
MB_YESNOCANCEL | MB_ICONQUESTION) == IDNO)
Panel1->Caption = "We will stop these tests now. Let the machine rest!";
}
//---------------------------------------------------------------------------
2. Change the Caption of the new button to Simple &1 and its name to
btnSimpleMsg
The MessageDlg() function is Borland’s enhanced message box and it provides a good
alternative to the Win32’s MessageBox() function.
The first argument, Message, is the message addressed to the user. It can be a simple
static sentence, a paragraph or any combination of strings.
The IconType is an icon used to enhance the dialog box. The icon is set using a constant
integer as follows:
Value Icon
mtWarning
mtError
mtInformation
mtConfirmation
mtCustom None
The Buttons argument is used to specify the type(s) of button(s) to display on the dialog
box. The buttons are defined using the TMsgDlgButtons set as follows:
The last argument is used if there is a help file available, in which case you would specify
the particular index related to this message box. This message box uses the name of the
project as its caption.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
MessageDlgPos("The right side of the main form displays "
"a \"Read-Only\" list of currently registered students.\n"
"This only includes students with good records.",
mtInformation,
TMsgDlgButtons() << mbRetry << mbIgnore,
0, 20, 120);
}
//---------------------------------------------------------------------------
This function takes three arguments similar to those of the MessageDlg() function. You
construct it by specifying the string message, the icon type, and the button type. To create
this dialog box, assign its construction to a dynamic form. To do this, you could create a
local form in a function or event, but since a local dynamic control in accessible only in
the event or function in which it is created, this would deceive the purpose of using the
CreateMessageDialog() function. Therefore, declare an instance of the Tform class in
the private or public sections of the unit or form that would use the message box:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *Button1;
TButton *Button2;
TPanel *Panel1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
void __fastcall FormCreate(TObject *Sender);
void __fastcall Panel1Click(TObject *Sender);
private: // User declarations
TForm* Mine;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Next, use the new operator to specify the owner of the form:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Mine = new TForm(this);
}
//---------------------------------------------------------------------------
To create the custom message box, assign the return value of the
CreateMessageDialog() function by creating it. The message box can be as simple as a
single string, an icon, and a button:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Mine = new TForm(this);
Mine = CreateMessageDialog("Custom Dialog Box",
mtWarning, TMsgDlgButtons() << mbYes);
}
//---------------------------------------------------------------------------
The message could also comport any of the available icons combined with any common
buttons:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Mine = new TForm(this);
Mine = CreateMessageDialog("Is this the best song or what?",
mtInformation,
TMsgDlgButtons() << mbYes << mbAbort << mbCancel << mbNo);
}
//---------------------------------------------------------------------------
With the message box created, you can call it from any section or control that needs it in
your application:
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Mine = new TForm(this);
Mine = CreateMessageDialog("Is this the best song or what?",
mtInformation,
TMsgDlgButtons() << mbYes << mbAbort << mbCancel << mbNo);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Mine->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Mine->ShowModal();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Panel1Click(TObject *Sender)
{
Mine->ShowModal();
}
//---------------------------------------------------------------------------
The Caption argument specifies the string that would display on the title bar of the dialog
box. The Prompt is a sentence that would display to the user as to what to type in the
provided edit box. The Default argument is a suggested value you can display in the edit
box to guide the user as the type of value expected. If you do not want to specify a default
value, you can set its string value to empty. Here is example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnInputClick(TObject *Sender)
{
InputBox("Temperature Conversion",
“Type the temperature in Celsius:", "");
}
//---------------------------------------------------------------------------
Although the Default argument is a string, you can initialize it to any value the
AnsiString class can interpret using one of its constructors. This means the default value
can be a character, a floating number or an integer:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnInputClick(TObject *Sender)
{
InputBox("Temperature Conversion",
If you specify the Default argument and the user clicks OK without changing the content
of the edit box, the compiler would consider the default value as valid.
After using the dialog box, the user would click OK, press Enter, click Cancel, or press
Esc. If the user clicks OK or presses Enter, the function returns the value that the user
would have typed in the edit box. This allows you to write a conditional statement that
would consider the new value returned by clicking OK on the InputBox dialog:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnInputClick(TObject *Sender)
{
Edit1->Text = InputBox("Distance and Measurement",
"Enter the distance in kilometer:", 0.00);
}
//---------------------------------------------------------------------------
If the user clicks Cancel or presses Esc, whatever the edit box was displaying would be
ignored. But the function would still return the default value.
If the returned value is intended for mathematical, date, or time calculations, you should
convert it accordingly.
InputBox("Student Registration",
"Type the Student's Gender", "");
5. Press F9 to test the form. Click the Input Box button. Notice that the content of
its edit box is empty.
6. Close the Input Box and the form.
7. To provide a default value to the user, change the content of the previous
function as follows:
InputBox("Student Registration",
"Type the Student's Gender", "Male");
8. Test the form and click the Input Box button
9. To use the content of another control, such as an edit box, as the default value,
change the above code as follows:
InputBox("Music Collection",
"Enter the category of music to register",
edtMessage->Text);
10. To test the form, press F9.
This takes three strings. The Caption argument is a string that displays on the title bar of
the dialog box. The Prompt argument is the sentence that indicates to the user what to
type in the edit box. Like the InputBox() function, the Value argument provides a default
and sample value to the user. Like the InputBox() function, the user can type a new value.
Here is an example of using the InputQuery() function:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnQueryClick(TObject *Sender)
{
InputQuery("Exiting Application",
" Are you sure you want to exist (y=Yes/n=No)?", 'n');
}
//---------------------------------------------------------------------------
Unlike the InputBox() function that returns a string, the InputQuery() function returns
two values. By its declaration, this function returns a Boolean value of true or false. If the
user clicks OK or presses Enter after using the dialog box, the function returns true. If the
user presses Esc or clicks Cancel, the function returns false.
If the user clicks OK (or presses Enter), like the InputBox() function, whether the user
had changed the value of the edit box or not, the content of the edit box, provided as the
Value argument, would be returned. Because Value is passed by reference, the function
can return two values. Unlike the InputBox() function, if the user clicks Cancel (or
presses Esc) after dealing with the dialog box, the value of the Value argument would be
ignore.
You can validate the returned value of Value by writing a conditional statement that
examines whether the user had clicked OK or Cancel. In the following example, when the
user clicks the Input button, the compiler finds out if the user had clicked OK; in which
case it would display the returned value of the Value argument in an Edit control of the
form:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnQueryClick(TObject *Sender)
{
AnsiString Answer = 'Y';
if(InputQuery("Exiting Application",
"Are you sure you want to exist (Y=Yes/Y=No)?", Answer) == True)
edtExiting->Text = Answer;
}
//---------------------------------------------------------------------------
Chapter 8:
The Math Libraries
By default, the content of a text control, such as an edit box, is a string, which is an array
of characters. If you want the value or content of such a control to participate in a
mathematical operation, you must first convert such a value to a valid data type and
proceed from there.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int Number1 = Edit1->Text.ToInt();
int Number2 = Edit2->Text.ToInt();
int Subtract = Number1 - Number2;
Edit3->Text = Subtract;
}
//---------------------------------------------------------------------------
If the control whose string needs to be converted is displaying an invalid integer, the
program would crash by throwing an error. The AnsiString provides a viable alternative.
The AnsiString::ToIntDef() allows you to supply a default value if the conversion fails.
Here is an example that uses it:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int Value1 = Edit1->Text.ToIntDef(0);
int Value2 = Edit2->Text.ToIntDef(1);
int Remainder = Value1 % Value2;
Edit3->Text = Remainder;
}
//---------------------------------------------------------------------------
This function takes as an argument, the string that you are trying to convert. In the
following example, the strings of two edit boxes are converted to integers and an addition
is performed on their values:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int Number1 = StrToInt(Edit1->Text);
int Number2 = StrToInt(Edit2->Text);
int Addition = Number1 + Number2;
Edit3->Text = Addition;
}
//---------------------------------------------------------------------------
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double Value1 = Edit1->Text.ToDouble();
double Value2 = Edit2->Text.ToDouble();
double Value3 = Value1 + Value2;
Edit3->Text = Value3;
}
//---------------------------------------------------------------------------
This function takes one argument which is the string to convert. The function returns a
long double-precision value. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double Value1 = StrToFloat(Edit1->Text);
double Value2 = StrToFloat(Edit2->Text);
double Value3 = Value1 + Value2;
Edit3->Text = Value3;
}
//---------------------------------------------------------------------------
Following the C system of passing arguments, this function can at least display a string.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Edit2->Text = Edit2->Text.sprintf("The best movie of the year");
}
//---------------------------------------------------------------------------
On the other hand, you can use this function to format a floating-point number. In the
following example, the values of the dimensions of a sphere are calculated and display in
appropriate edit boxes:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
double Radius, Diameter, Circumference, Area, Volume;
Radius = edtRadius->Text.ToDouble();
Diameter = Radius * 2;
Circumference = Radius * 2 * M_PI;
Area = Radius * Radius * M_PI;
Volume = Radius * Radius * Radius * 4.00 * M_PI / 3;
edtDiameter->Text = Diameter;
edtCircumference->Text = Circumference;
edtArea->Text = Area;
edtVolume->Text = Volume;
}
//---------------------------------------------------------------------------
When the same values are configured using the AnsiString::sprintf() method, the
diameter and the circumference can be set to display two decimal values while the area
and the volume display three, as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
double Radius, Diameter, Circumference, Area, Volume;
Radius = edtRadius->Text.ToDouble();
Diameter = Radius * 2;
Circumference = Radius * 2 * M_PI;
Area = Radius * Radius * M_PI;
Volume = Radius * Radius * Radius * 4.00 * M_PI / 3;
In some operations, the number considered will need to be only positive even if it is
provided in a negative format. The absolute value of a number x is x if the number is
(already) positive. If the number is negative, its absolute value is its positive equivalent.
For example, the absolute value of 12 is 12, while the absolute value of –12 is 12.
To get the absolute value of a number, you can use one of the C/C++ abs() functions. Its
syntax is:
This function takes an integer as the argument and returns its absolute value equivalent.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnAbsoluteClick(TObject *Sender)
{
int Number = edtNumber->Text.ToInt();
edtResult->Text = abs(Number);
}
//---------------------------------------------------------------------------
This function takes a long integer as argument and returns its equivalent absolute value:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnLongAbsoluteClick(TObject *Sender)
{
int Longer = StrToInt(edtNumber->Text);
edtResult->Text = labs(Longer);
}
//---------------------------------------------------------------------------
13
12.155
12
On the other hand, consider a number such as –24.06. As this number is negative, it is
between –24 and –25, with –24 being greater.
In arithmetics, the ceiling of a number is the closest integer that is greater or higher than
the number considered. In the first case, the ceiling of 12.155 is 13 because 13 is the
closest interger greater than or equal to 12.155. The ceiling of –24.06 is –24.
The function takes one argument, which is the floating number to be evaluated, and the
function returns a double-precision number that is the integer that is greater than or equal
to Value. Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double Value1 = 155.55;
double Value2 = -24.06;
cout << "The ceiling of " << Value1 << " is " << ceil(Value1) << endl;
cout << "The ceiling of " << Value2 << " is " << ceil(Value2) << endl;
The Ceil() function takes an argument that represents a long double value. The function
returns the greater or equal integer of Value. To use the Ceil() function, include the
math.hpp header to your program. Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
Extended Value1 = 312.44;
Extended Value2 = -4002.35;
cout << "The ceiling of " << Value1 << " is" << Ceil(Value1) << endl;
cout << "The ceiling of " << Value2 << " is" << Ceil(Value2);
The floor() function takes the considered value as the argument and returns the integer
that is less than or equal to Value. Here is an example:
cout << "The floor of " << Value1 << " is " << floor(Value1) << endl;
cout << "The floor of " << Value2 << " is " << floor(Value2) << endl;
The Value argument of the function represents the number that is being considered. The
function returns the integer that is less than or equal to Value. Here is an example:
cout << "The floor of " << Value1 << " is " << Floor(Value1) << endl;
cout << "The floor of " << Value2 << " is " << Floor(Value2) << endl;
The C++ frexp() and frexpl() functions are used to get the mantissa and the exponent
portions of a floating-point number. Each of these functions takes two arguments. The
Number argument represents the value that will be examined. For the frexp() function,
this value is a double-precision number. If the number is larger, then use the frexpl()
version whose argument is a long double. The Exp argument is passed as a pointer to an
integer. This allows the function to return a second value.
The result returned, Mantissa, is a double (frexp) or a long double (frexpl) number in the
range 0.5 (included) to 1 (excluded). The Exp argument, passed as a pointer, is returned
as
For the following example, a form is equipped with three Edit controls named
edtNumber, edtMantissa, and edtExponent. It also has a Button control named
btnCalculate with the Default property set to true. The user must type a number in the
Number edit box and press Enter. Then the OnClick event of the button executes to
perform the frexp() function which leads to displaying the results in the appropriate edit
boxes :
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
double Mant, Number = edtNumber->Text.ToDouble();
int Exp;
The Frexp() function is the VCL’s version of the frexp() function. This function takes
three arguments. The number to be examined is the Number argument passed as a lond
double. The number to be returned, also a long double, is the Matissa argument, also
passed by reference. The Exp argument, also passed as a reference is returned as the
exponent value. The numbers are dealt with according to the formula:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Extended Number, Mant;
int Exp;
Number = StrToFloat(Edit1->Text);
Frexp(Number, Mant, Exp);
Edit2->Text = FloatToStr(Mant);
Edit3->Text = Exp;
}
//---------------------------------------------------------------------------
The pow() function is used to calculate the value of one number or expression raised to
the power of another number. This follows the formula: ReturnValue = xy
The pow() function takes two required arguments. The first argument, x, is used as the
base number to be evaluated. The second argument, y, also called the exponent, will raise
x to this value. The powl() function performs the same calculation on long double
numbers and returns a long double.
In the following example, a form is equipped with a Button control and an Edit control.
When the user clicks the button, the constant 205.38 is raised to the power of 4.12. The
result displays in the edit box:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
const double Source = 205.38;
const double Exp = 4.12;
double Result = pow(Source, Exp);
Edit1->Text = Result;
}
//---------------------------------------------------------------------------
The VCL’s IntPower() function is used to raise a number, Base, to the integral Exponent
power. The first argument of this function, Base, can be an integer, a float, a double-
precision number or a long double. The Exponent argument is the factor about which the
Base number will be raised.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Extended Number, Base;
int Exp;
Base = StrToFloat(Edit1->Text);
Exp = StrToInt(Edit2->Text);
Number = IntPower(Base, Exp);
Edit3->Text = FloatToStr(Number);
}
//---------------------------------------------------------------------------
The Power() function takes a number (any number, including integers, floating, double
or long double-precision numbers) as the Base argument and raises it to the power of the
Exponent argument, which also can be any number (int, float, double, long double).
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int Source = 205;
float Exp = 5.25;
double Result = Power(Source, Exp);
Edit1->Text = Result;
}
//---------------------------------------------------------------------------
The exp() function calculates the exponential value of a number. The argument, a double-
precision value, represents the number to be evaluated.
If the value of x is less than -708.395996093 (approximately), the result is reset to 0 and
qualifies as underflow. If the value of the argument x is greater than 709.78222656
(approximately), the result is INF and qualified as overflow:
//---------------------------------------------------------------------------
#include <iostream.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
cout << "\nThe exponential of " << 709.78222656
<< " is " << exp(709.78222656);
Therefore, the value of the argument should be between these two extremes. For a larger
number, use the expl() function:
As opposed to an 8-byte value, this version of the function takes a 10-byte variable,
calculates its exponent, and returns a long double.
The C/C++ ldexp() function takes the mantissa and the exponent numbers and returns a
floating number. The function uses the formula:
Result = x * 2y
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double x, Result;
int y;
x = StrToFloat(Edit1->Text);
y = StrToInt(Edit2->Text);
Result = ldexp(x, y);
Edit3->Text = FloatToStr(Result);
}
//---------------------------------------------------------------------------
The ldexp() function works on double-precision numbers while the ldexpl() uses long
doubles.
The VCL’s Ldexp() function is used to calculate a number that is derived from a known
mantissa and an exponent numbers. To perform this calculation, the function uses the
formula:
Result = X * 2P
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
float Source = 450.04;
float Exp = 10.25;
double Result = Ldexp(Source, Exp);
Edit1->Text = Result;
}
//---------------------------------------------------------------------------
8.2.8 LnXP1
The LnXP1() function is used to calculate the natural logarithm of a number that is being
incremented to 1. The syntax of this function is
When executing, this function takes one argument, X, adds 1 to X, and then calculates the
natural logarithm, also called the Napierian logarithm, of the new number. The formula
used is Result = ln(X+1). Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Extended X, Result;
X = StrToFloat(Edit1->Text);
Result = LnXP1(X);
Edit2->Text = FloatToStr(Result);
}
//---------------------------------------------------------------------------
8.2.9 Log10
The Log10() function calculates the base 10 logarithm of a number. The syntax of this
function is:
The number to be evaluated is passed as the argument X. The function returns the
logarithm on base 10 using the formula:
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Extended X, Result;
X = StrToFloat(Edit1->Text);
Result = Log10(X);
Edit2->Text = FloatToStr(Result);
}
//---------------------------------------------------------------------------
8.2.10 Log2
The Log2() function is used to calculate the logarithm of a number on base 2. The syntax
of the function is:
The variable whose logarithmic value will be calculated is passed as argument X to the
function. The function uses the formula:
//---------------------------------------------------------------------------
X = StrToFloat(Edit1->Text);
Result = Log2(X);
Edit2->Text = FloatToStr(Result);
}
//---------------------------------------------------------------------------
8.2.11 LogN
The LogN() function is used to calculate the logarithmic value of a number to the desired
base. Its syntax is:
This function takes two arguments. The second, Number, is the variable whose value will
be evaluated. The first argument, Base, is used as the base of the logarithm. The formula
used by this function is:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Extended Base, Number, Result;
Base = StrToFloat(Edit1->Text);
Number = StrToFloat(Edit2->Text);
Result = LogN(Base, Number);
Edit3->Text = FloatToStr(Result);
}
//---------------------------------------------------------------------------
The sqrt() function is used to calculate the square root of a double-precision number. Its
syntax is:
This function takes one argument as a positive floating number. After the calcultion, the
function returns the square root of x:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
double Number = Edit1->Text.ToDouble();
double Result = sqrt(Number);
Edit2->Text = Result;
}
//---------------------------------------------------------------------------
For a large or larger number, you can use the sqrtl() function. Its syntax is:
This second form takes a long double number as a variable and returns a long double
number as the square root of x.
After the calculation, if a function succeed, it would return the square root. If it fails, it
would throw an error.
2. Change the names of the Edit controls as follows: edtA, edtB, edtC, edtRoot1,
edtRoot2. Change the name of the main button to btnProcess and its caption to
Process.
3. Double-click the Process button and implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnProcessClick(TObject *Sender)
{
double A, B, C;
A = edtA->Text.ToDouble();
B = edtB->Text.ToDouble();
C = edtC->Text.ToDouble();
if( A == 0 )
return;
double A2 = 2 * A;
double D = (B * B) - (4 * A * C);
double Delta = sqrt(D);
double Root1 = (-B - Delta) / A2;
double Root2 = (-B + Delta) / A2;
edtRoot1->Text = Root1;
edtRoot2->Text = Root2;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
4. To test the program, on the main menu, click Run Run. Test the program with
A = 1, B = -6, and C = 9.
5. Return to Bcb
When an item is acquired for the first time as “brand new”, the value of the asset is
referred to as its Cost. The declining value of an asset is referred to as its Depreciation.
At one time, the item will completely lose its worth or productive value. Nevertheless,
the value that an asset has after it has lost all its value is referred to its Salvage Salue. At
any time, between the purchase value and the salvage value, accountants estimate the
value of an item based on various factors including its original value, its lifetime, its
usefulness (how the item is being used), etc.
8.3.1 DoubleDecliningBalance
The Double Declining Balance is a method used to calculate the depreciating value of an
asset. The function used to perform this calculation is the DoubleDecliningBalance() and
its syntax is:
The first argument, Cost, represents the initial value of the item. The Salvage argument is
the estimated value of the asset when it will have lost all its productive value. The Cost
and the Salvage values must be given in their monetary values. The value of Life is the
length of the lifetime of the item; this could be the number of months for a car or the
number of years for a house for example. The Period is a factor for which the
depreciation is calculated. For the Double Declining Balance, this Period argument is
usually 2.
In the following example, a form is equipped with five Edit controls named edtCost,
edtSalvage, edtLife, edtPeriod, and edtDepreciation. After entering the necessay values
and pressing Enter, the OnClick event of the Calculate button retrieves the values and
calls the DoubleDecliningBalnace() function to calculate the Depreciation and display it
the appropriate edit box:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.hpp>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Cost = StrToFloat(edtCost->Text);
Extended Salvage = StrToFloat(edtSalvage->Text);
Integer Life = StrToInt(edtLife->Text);
Integer Period = StrToInt(edtPeriod->Text);
Extended Depreciation = DoubleDecliningBalance(Cost, Salvage, Life, Period);
edtDepreciation->Text = FloatToStr(Depreciation);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnExitClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
8.3.2 SLNDepreciation
The VCL provides another method used to calculate the depreciation of an item. This
time, the depreciation is considered on one period of the life of the item. The function
used, SLNDepreciation, is:
The Cost argument is the original amount paid for an item (refrigerator, mechanics
toolbox, high-volume printer, etc). The Life represents the period during which the asset
is (or was) useful; it is usually measured in years. The Salvage, also called the scrap
value, is the value that the item will have (or is having) at the end of Life.
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Depreciation, Cost, Salvage;
int Life;
Cost = StrToFloat(edtCost->Text);
Salvage = StrToFloat(edtSalvage->Text);
Life = StrToInt(edtLife->Text);
Depreciation = SLNDepreciation(Cost, Salvage, Life);
8.3.3 SYDDepreciation
The Sum-Of-The-Years’-Digits provides another method for calculating the depreciation
of an item.
Imagine that a restaurant bought a commercial refrigerator (“cold chamber”) for $18,000
and wants to estimate its depreciation after 5 years using the Sum-Of-Years’-Digits
method. Each year is assigned a number, also called a tag, using a consecutive count; this
means that the first year is appended 1, the second is 2, etc. This way, the depreciation is
not uniformly applied to all years.
The total count is made for these tags. For our refrigerator example, this would be
Sum = 1 + 2 + 3 + 4 + 5 = 15
Each year is divided by this Sum, also called the sum of years, used as the common
denominator:
This is equivalent to 1. As you can see, the first year would have the lowest divident
(1/15 ≈ 0.0067) and the last year would have the highest (5/15 ≈ 0.33).
To calculate the depreciation for each year, the fractions (1/15 + 2/15 + 3/15 + 4/15 +
5/15) are reversed so that the depreciation of the first year is calculated based on the last
fraction (the last year divided by the common denominator). Then the new fraction for
each year is multiplied by the original price of the asset. This would produce:
The VCL function used to calculate the depreciation of an asset using the sum of the
years is called SYDDepreciation and its syntax is:
The Cost argument is the original value of the item; in our example, this would be
$18,000. The Salvage is the value the asset would have (or has) at the end of its useful
life. The Life is the number of years of the asset would have a useful life. The Period is
the particular period or rank of a Life portion; for example, if the Life of the depreciation
is set to 5 (years), the Period could be any number between 1 and 5. If set to 1, the
depreciation would be calculated for the first year. If the Period is set to 4, the
depreciation would calculated for the 4th year. You can also set the Period to a value
higher than Life. For example, if Life is set to 5 but you pass 8 for the Period, the
depreciation would be calculated for the 8th year. If the asset is worthless in the 8th year,
the depreciation would be 0.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended DeprecYear1, DeprecYearN, Cost, Salvage;
int Life;
Cost = StrToFloat(edtCost->Text);
Salvage = StrToFloat(edtSalvage->Text);
Life = StrToInt(edtLife->Text);
DeprecYear1 = SYDDepreciation(Cost, Salvage, Life, 1);
DeprecYearN = SYDDepreciation(Cost, Salvage, Life, Life);
The Present Value is the current value of an investment or a loan. For a savings account,
a customer could pledge to make a set amount of deposit on a bank account every month.
The initial value that the customer deposits or has in the account is the PresentValue as
referenced in the VCL functions. The sign of the variable, when passed to a function,
depends on the position of the customer. If the customer is making deposits, this value
must be negative. If the customer is receiving money (lottery installment, family
inheritance, etc), this value should be positive.
The Number Of Periods is the number of periods that make up a full cycle of a loan or
an investment. This period could be the number of months of a year, which is 12; but it
could be another length. This variable is passed as NPeriods. Suppose a customer is
getting a car loan that would be financed in 5 years. This is equivalent to 5 * 12 = 60
months. In the same way, a cash loan can stretch from 0 to 18 months, a carpenter truck
loan can have a life financing of 40 months, and a condominium can be financed for 15
years of 12 months plus an additional 8 months; this is equivalent to (15 * 12) + 8 = 188
months.
The Interest Rate argument is a fixed percent value applied during the life of the loan or
the investment. The rate does not change during the length of the NPeriods. For deposits
made in a savings account, because their payments are made monthly, the rate is divided
by the number of periods (the NPeriods) of a year, which is 12. If an investment has an
interest rate set at 14.50%, the Rate would be 14.50/12 = 1.208. Because the Rate is a
percentage value, its actual value must be divided by 100 before passing it to the
function. For a loan of 14.50 interest rate, this would be 14.50/12 = 1.208/100 = 0.012.
The Payment is the amount the customer will be paying. For a savings account where a
customer has pledged to pay a certain amount in order to save a set (goal) amount, this
would be the amount the customer would pay every month. If the customer is making
payments (car loan, mortgage, deposits to a savings account), this value must be negative.
If the customer is receiving money (lottery installment or annuity, family inheritance,
etc), this value must be positive.
The Payment Time specifies whether the payment is made at the beginning or the end of
the period. For a monthly payment, this could be the beginning or end of every month.
The PaymentTime uses one of the values of the TPaymentTime enumerator. When
passing this variable, select one of the members of the enumerator:
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, Payment, TheRate;
int Period;
Present = StrToFloat(edtPresent->Text);
Payment = StrToFloat(edtPayment->Text);
Period = StrToInt(edtPeriod->Text);
TheRate = StrToFloat(edtRate->Text) / 12;
double Rate = TheRate /100;
Future = FutureValue(Rate, Period, Payment, Present, ptEndOfPeriod);
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, TheRate, Payments, NPeriod;
Present = StrToFloat(edtLoan->Text);
Future = StrToFloat(edtFuture->Text);
Payments = StrToFloat(edtPayments->Text);
TheRate = StrToFloat(edtRate->Text) / 12;
Future, ptStartOfPeriod);
// Since the number of periods is really an integer, find its ceiling
Extended Actual = Ceil(NPeriod);
// Display the number of periods
edtNPeriods->Text = FloatToStr(Actual);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnExitClick(TObject *Sender)
{
PostQuitMessage(0);
}
//---------------------------------------------------------------------------
In the following examples, a customer is applying for a car loan. The car costs $15500. It
will be financed at 8.75% for 5 years. The dealer estimates that the car will have a value
of $2500 when it is paid off:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, TheRate, Payments, NPeriod;
Present = StrToFloat(edtLoan->Text);
Future = StrToFloat(edtFuture->Text);
TheRate = StrToFloat(edtRate->Text) / 12;
NPeriod = StrToFloat(edtNPeriods->Text);
}
//---------------------------------------------------------------------------
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, TheRate, PPayment;
int Periods, NPeriod;
Present = StrToFloat(edtLoan->Text);
Future = StrToFloat(edtFuture->Text);
TheRate = StrToFloat(edtRate->Text) / 12;
Periods = StrToInt(edtPeriod->Text);
NPeriod = StrToInt(edtNPeriods->Text);
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, TheRate, Payments;
int NPeriod;
Future = StrToFloat(edtFuture->Text);
Payments = StrToFloat(edtPayments->Text);
TheRate = StrToFloat(edtRate->Text) / 12;
NPeriod = StrToInt(edtNPeriods->Text);
The PresentValue is the current value of the item. It could be the marked value of the car,
the current mortgage value of a house, or the cash amount that a bank is lending. The
NPeriods is the number of periods that occur during a yearly cycle of the loan. The Rate
argument is a fixed percent value applied during the life of the loan. The Period argument
represents the payment period. The FutureValue is the total amount that the customer will
have paid when the loan is paid off. The PaymentTime specifies whether the periodic
(such as monthly) payment of the loan is made at the beginning or end of the period.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, Payment, TheRate;
int Periods, NPeriod;
Present = StrToFloat(edtPresent->Text);
Future = StrToFloat(edtFuture->Text);
Periods = StrToInt(edtPeriod->Text);
NPeriod = StrToInt(edtNPeriods->Text);
TheRate = StrToFloat(edtRate->Text) / 12;
double Rate = TheRate /100;
All of the arguments are the same as described for the InterestPayment() function. Here
is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
Extended Present, Future, Payments, Rate;
int NPeriod;
Present = StrToFloat(edtPresent->Text);
Future = StrToFloat(edtFuture->Text);
Payments = StrToFloat(edtPayments->Text);
NPeriod = StrToInt(edtNPeriods->Text);
The CashFlows is an array of cash amounts that a customer has made on an investment.
For example, a customer could make monthly deposits in a savings or credit union
accounts. Another customer could be running a business and receiving different amounts
of money as the business is flowing (or losing money). The cash flows do not have to be
the same at different intervals but they should (or must) occur at regular intervals such as
weekly (amount cut from a paycheck), bi-weekly (401k directly cut from paycheck,
monthly (regular investment), or yearly (income). The CashFlows argument must be
passed as an array and not an amount; otherwise you would receive an error.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
double Goal;
double Month1, Month2, Month3, Month4, Month5, Month6;
Extended InterestGuess;
int Periods;
8.4.9 NetPresentValue
The NetPresentValue() function uses a series of cash flows to calculate the present value
of an investment. Its syntax is:
The Rate is the rate of discount during one period of the investment.
The PaymentTime specifies whether the payment occurs at the beginning or end of the
period. It uses the TPaymentTime enumerator.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCalculateClick(TObject *Sender)
{
double Goal;
double Month1, Month2, Month3, Month4, Month5, Month6;
Extended Rate;
int Periods;
A
R
C B
A circle is a group or series of distinct points drawn at an exact same distance from
Note
Equidistant
another point referred to as the center. The distance from the center C to one of these
means “same equidistant points is called the radius, R. The line that connects all of the points that are
distance” equidistant to the center is called the circumference of the circle. The diameter is the
distance between two points of the curcumference to the center; in other words, a
diameter is double the radius.
To manage the measurements and other related operations, the circumference is divided
into 360 portions. Each of these portions is called a degree. The unit used to represent the
degree is the degree, written as ˚. Therefore, a circle contains 360 degrees, that is 360˚.
The measurement of two points A and D of the circumference could have 15 portions of
the circumference. In this case, this measurement would be represents as 15˚.
The distance between two equidistant points A and B is a round shape geometrically
defined as an arc. An angle, ө, is the ratio of the distance between two points A and B of
the curcumference divided by the radius R. This can be written as:
Therefore, an angle ө is the ratio of an arc over the radius. Because an angle is a ratio and
not a “physical” measurement, which means an angle is not a dimension, it is
independent of the size of a circle. Obviously this angle represents the number of portions
included by the three points. A better unit used to measure an angle is the radian or rad.
A cycle is a measurement of the rotation around the circle. Since the rotation is not
necessarily complete, depending on the scenario, a measure is made based on the angle
that was covered during the rotation. A cycle could cover part of the cycle in which case
the rotation would not have been complete. A cycle could also cover the whole 360˚ of
the circle and continue there after. A cycle is equivalent to the radian divided by 2 * Pi.
The VCL ships with functions used to perform conversions of values between different
units. To use any of these functions, you must include the VCL math header file as:
#include <math.hpp>
8.5.1 Pi
The word п, also written as Pi, is a constant number used in various mathematical
calculations. Its approximate value is 3.1415926535897932. The calculator of Windows
represents it as 3.1415926535897932384626433832795. Borland had included its value
in the math.h library as M_PI 3.14159265358979323846.
A diamter is two times the radius. In geometry, it is written as 2R. In C++, it is written as
2 * R or R * 2 (because the multiplication is symmetric). The circumference of a circle is
calculated by multiplying the diamter to Pi, which is 2Rп, or 2 * R * п or 2 * R * Pi.
A radian is 2Rп/R radians or 2Rп/R rad, which is the same as 2п rad or 2 * Pi rad.
To perform conversions between the degree and the radian, you can use the formula:
8.5.2 CycleToRad
Extended __fastcall CycleToRad(Extended Cycles);
The CycleToRad() function is used to convert the measurement of an angle from radians
to cycles. This function is equivalent to using the formula Radian = 2Pi * Cycle.
Here is an example:
//---------------------------------------------------------------------------
#include <MATH.HPP>
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConversionClick(TObject *Sender)
{
Extended Cyc = StrToFloat(edtCycle->Text);
Extended Rad = CycleToRad(Cyc);
edtRadian->Text = FloatToStr(Rad);
}
//---------------------------------------------------------------------------
8.5.3 DegToRad
Extended __fastcall DegToRad(Extended Degrees);
The DegToRad is used to calculate the equivalent value of an angle from degrees to
radians. This function follows the formula:
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConversionClick(TObject *Sender)
{
Extended Deg = StrToFloat(edtDegrees->Text);
Extended Rad = DegToRad(Deg);
edtRadians->Text = FloatToStr(Rad);
}
//---------------------------------------------------------------------------
8.5.4 RadToCycle
Extended __fastcall RadToCycle(Extended Radians);
The RadToCycle() is used to convert the measurement of an angle from radians to cycles.
This function is equivalent to using the formula Cycle = Radian / 2Pi.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConversionClick(TObject *Sender)
{
Extended Rad = StrToFloat(edtRadian->Text);
Extended Cyc = RadToCycle(Rad);
edtCycle->Text = FloatToStr(Cyc);
}
//---------------------------------------------------------------------------
8.5.5 RadToDeg
The RadToDeg() function is used to calculate the equivalent value of an angle from
radians to degrees. This function applies the formula:
360˚ = 2 * Pi which is 1˚ = 2 * Pi
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConversionClick(TObject *Sender)
{
Extended Rad = StrToFloat(edtRadians->Text);
Extended Deg = RadToDeg(Rad);
edtDegrees->Text = FloatToStr(Deg);
}
//---------------------------------------------------------------------------
8.6 Statistics
8.6.1 MaxIntValue
The MaxIntValue() function calculates the maximum value of an array of integers. The
first argument of the function, Data, represents the name of the array. The second
argument, Data_Size is the number-1 of members of the array.
To get the maximum value of a group of integers, declare an integral array of numbers.
You can initialize such a variable or request the values of its members from the user. The
value of the Data_Size argument must be 1 less than the total number of the array
members.
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
int n, Numbers[100];
getchar();
return 0;
}
//---------------------------------------------------------------------------
8.6.2 MaxValue
The MaxValue is a numeric value that represents the maximum number of items of an
array. This function takes two arguments. The first argument, Data, represents an array of
integers or double-precision numbers. The second argument is the number-1 of the items
of the array; for example, if the considered array has 4 members, the Data_Size argument
would be 3.
To use the MaxValue() function, declare an array that involves the necessary numbers.
You can initialize such a variable or request the numbers from the user. To calculate the
maximum value of a range, supply the array and its size. If you do not know the
dimension of the array, you can use the sizeof operator to find it out. Here is an example
of using the MaxValue() function:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double Values[] = { 12.55, 10.15, 980.22, 50.50, 280.12 };
int Size = (sizeof(Values)/sizeof(double)) - 1;
getchar();
return 0;
}
//---------------------------------------------------------------------------
8.6.3 Mean
The Mean() function considers an array of numbers and calcuates the average value of
those numbers. The function takes two arguments. The first, Data, is the name of the
array of numbers. These number could integers or floating numbers. The second
argument, Data_Size represents the number-1 of members of the array. You can type an
integral number as the Data_Size or you can use the sizeof operator to get the dimension
of the array and subtract 1 from it. After the calculation, the function returns a long
double-precision number as the average of the numbers.
Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double Values[] = { 12.55, 10.15, 980.22, 50.50, 280.12 };
int Size = (sizeof(Values)/sizeof(double)) - 1;
getchar();
return 0;
}
//---------------------------------------------------------------------------
8.6.4 MinIntValue
The MinIntValue() function calculates the minimum value of an array of integers. The
Data argument of the function is the name of the array. The second argument, Data_Size
is the number-1 of members of the array.
To get the minimum value of a group of integers, declare an integral array of numbers.
You can initialize the variable or request the values of its members from the user. The
value of the Data_Size argument must be 1 less than the total number of members.
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
int n, Numbers[100];
getchar();
return 0;
}
//---------------------------------------------------------------------------
8.6.5 MinValue
The MinValue() function gets a numeric value that represents the minimum value of the
items of an array. This function takes two arguments. The first argument, Data, represents
an array of integers or double-precision numbers. The second argument is the number-1
of the items of the array; for example, if the considered array has 4 members, the
Data_Size argument would be 3.
To use the MinValue() function, declare an array that involves the necessary numbers.
You can initialize such a variable or request the values from the user. To calculate the
minimum value of a range, supply the array and its size. If you do not know the
dimension of the array, you can use the sizeof operator to find it out. Here is an example
that uses the MinValue() function:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
double Values[] = { 12.55, 10.15, 980.22, 50.50, 280.12 };
int Size = (sizeof(Values)/sizeof(double)) - 1;
getchar();
return 0;
}
//---------------------------------------------------------------------------
8.6.6 Sum
The Sum() function is used to calculate the sum value of a group of numbers. The first
argument of this function, Data, is the name of an array that holds the numbers
considered. The Data_Size argument isthe dimension of the array minus 1.
To get the sum of a group of numbers, declare an array to hold the necessary numbers.
The numbers can be integers or double precision values. You can initialize the array with
these numbers or request their values from the user.
Here is an example of calculating a total number after requesting grades from the user of
a program:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
8.6.7 SumInt
The SumInt() function is used to calculate the total of a group of integral numbers. This
function takes two arguments. The first, Data, is the name of the array that holds the
numbers. The numbers must be integers. If you want to calculate a total of floating-point
numbers, use the Sum() function. The second argument, Data_Size is the size of the array
minus one.
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
Company Inventory
Type the number of items of each category
Desktops: 12
Laptops: 2
Printers: 8
Fax Machines: 2
Chairs: 18
Tables: 14
Book Shelves: 10
Books: 20
Trash Cans: 15
Pens: 120
Pencils: 144
Others: 212
8.6.8 SumOfSquares
To calculate the total of the squares, declare an array variable. You can initialize the array
by providing the necessary list of numbers. Otherwise, request the different numbers
from the user. The function will take care of the rest.
Here is example:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
cout << "The sum of the squares is: " << TotalOfSquares;
cout << "\n\nTo end, press Enter...";
getchar();
return 0;
}
//---------------------------------------------------------------------------
8.6.9 SumsAndSquares
void __fastcall SumsAndSquares(const double * Data, const int Data_Size, Extended
&Sum, Extended &SumOfSquares);
The SumsAnsSquares() function performs two operations and returns two values. Using a
group of numbers, the function calculates their total, Sum. It also calculates the square S
of each number then calculates the total of the S values, which produces a
SumOfSquares. The first argument, Data, is the array of the numbers considered. The
Data_Size argument is the number of items in the array minus 1. The Sum and the
SumOfSquares arguments are passed by reference, which allows the function to return
these last two values.
Here is an example:
//---------------------------------------------------------------------------
#include <iostream.h>
#include <math.hpp>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma argsused
Size = (sizeof(Values)/sizeof(double)) - 1;
SumsAndSquares(Values, Size, Total, TotalOfSquares);
8.7.1.1 Cosine
double cos(double x);
long double cosl(long double x);
Example: A form contains an Edit control named edtValue. After the user has typed a
value and presses Enter, the OnKeyPress event retrieves the number typed in the edit box,
calculates its cosine and displays it in the same Edit control:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtValueKeyPress(TObject *Sender, char &Key)
{
if( Key == VK_RETURN )
{
double Value = edtValue->Text.ToDouble();
double Cosinus = cos(Value);
edtValue->Text = Cosinus;
}
}
//---------------------------------------------------------------------------
ArcCos
Calculates the inverse cosine of a given number.
Cosh
ArcCosh
Consider AB the length of A to B, also called the hypothenuse to point A. Also consider
CB the length of C to B, which is the opposite side to point A. The sine represents the
ratio of CB/AB; that is, the ratio of the opposite side, CB over the hypothenuse AB.
The sin() function takes a double-precision number and returns one between –1 and 1.
The sinl() function is used for 10-byte values.
Example: A form contains an Edit control named edtValue. After the user has typed a
value and presses Enter, the OnKeyPress event retrieves the number typed in the edit box,
calculates its sine and displays the result in the same Edit control:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtValueKeyPress(TObject *Sender, char &Key)
{
if( Key == VK_RETURN )
{
Example: A form contains an Edit control named edtValue. After the user has typed a
value and presses Enter, the OnKeyPress event retrieves the number typed in the edit box,
calculates its tangent and displays the result in the same Edit control:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtValueKeyPress(TObject *Sender, char &Key)
{
if( Key == VK_RETURN )
{
double Value = edtValue->Text.ToDouble();
double Tangent = tan(Value);
edtValue->Text = Tangent;
}
}
//---------------------------------------------------------------------------
The atan() function takes one argument, x, that represents the angle BA AC. After the
evaluation, the function returns a double-precision number between –PI/2 and PI/2.
If the number to be evaluated is larger than a double, use the atanl() function:
This function takes a long double argument and returns a long double.
9.1 Dates
The date and time are at the core of computer use. The date is a unit that measures the
number of years, months, or days elapsed in a specific period. To represent the dates,
computers, applications, and compilers are configured with appropriates techniques. The
C++ Builder compiler counts dates from 12/30/1899 at midnight. With this compiler,
dates and related operations are dealt with using a class called TDateTime. Since this
class is not a control, you can use it with any control that displays text.
The dates used in your applications will mostly be based on the TDateTime class. To
perform most operations in your programs, you will need to know when, how, and where
to use this class. As an object, you will need to declare it.
TDateTime Mine;
If not assigned a value, this variable is initialized to 12/30/1899 at midnight. If you know
the exact date that you want to initialize, you have two alternatives. You can initialize the
variable using a string. Here is an example:
TDateTime Mine("12/05/1990");
AnsiString S = "05/04/1988";
TDateTime Mine = S;
You can also provide the integer values of the year, the mont, and the day respectively.
Here is an example:
To initialize a date, you can also provide an integer that represents the number of days
passed since 1899 to the specified date. Here is and example:
If the user types a valid date into an edit box, such as 10/4/1988, this is still considered a
string and you would not be able to use it in an operation. To convert a string to a date,
you can use the StrToDate() function. The syntax is:
This function takes an argument as the string that needs to be converted. The string must
be provided in a recognizable format, following the Regional Settings of the Windows
Control Panel. For example, in the United States, the components of a date are separated
with a forward slash “/”. The typical formats of a date are:
If the string contains an invalid date, the conversion would fail and the program would
throw an error. If the conversion is successful, the function would return a valid date.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm2::btnConvertClick(TObject *Sender)
{
TDateTime Value = StrToDate(edtSource->Text);
edtTarget->Text = Value;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime AFewMonthsAgo("04/28/1998");
Edit1->Text = AFewMonthsAgo;
}
//---------------------------------------------------------------------------
The operator AnsiString() function allows any valid TDateTime value to be automatically
converted to a string when needed. You can also explicitly use the function if necessary.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDisplayClick(TObject *Sender)
{
TDateTime AFewMonthsAgo("04/28/1998");
AnsiString Converted = AFewMonthsAgo.operator AnsiString();
edtResult->Text = Converted;
}
//---------------------------------------------------------------------------
If you have a date value that needs to be converted to a string, you can use the
DateToStr() function. Its syntax is:
This function takes one argument, which is the date value that needs to be converted. If
the argument is not a valid date, the conversion would fail and the program would throw
an error (in simple but practical terms, the program would crash). If the conversion is
successful, the function returns a string.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
AnsiString Current = DateToStr(Date());
edtTarget->Text = Current;
}
//---------------------------------------------------------------------------
Alternatively, you can use the TDateTime::DateString() function to convert a valid date
to a string. The syntax of the DateString() method is:
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime Today = Date();
The double data type was overloaded in the TDateTime class to allow converting a
TDateTime variable to a fractional equivalent. The number can be made of two parts. If
the number is round, that is, without a decimal value, it represents the number of days
elapsed since 12/30/1899. If the number has a decimal part, the decimal portion
represents a fraction of the day over a 24-hour period.
The operator double() function can be used to get the number of days and the amount of
time elapsed since 12/30/1899 at midnight and the time of the current date. In the
following example, the difference between the current date an time and 12/30/1899 at
midnight is displayed as a double-precision number in an Edit control of a form when the
form comes up:
//---------------------------------------------------------------------------
void __fastcall TForm2::FormCreate(TObject *Sender)
{
TDateTime RightNow = Now();
}
//---------------------------------------------------------------------------
To convert a TDateTime value to double using the double overloaded operator, declare a
double variable and assign the TDateTime variable to it by calling the operator double()
function. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDifferenceClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
edtDifference->Text = d;
}
//---------------------------------------------------------------------------
To get the equivalent number of days of a TDateTime value, declare an integer and
assign it the desired TDateTime value by calling the operator int() function. If the
operator is applied on a variable that holds a particular date, the operator int() function
would produce the number of days elapsed since 12/30/1988. In the following example,
the number of days since 12/30/1988 to the current date is displayed in an Edit control
when the user clicks the button:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnShowDaysClick(TObject *Sender)
{
TDateTime Today = Date();
int Days = Today.operator int();
edtDifference->Text = Days;
}
//---------------------------------------------------------------------------
From the Date, Time, Language, and Regional Options window, click either Change the
Format of Numbers, Dates, and Times or Regional and Language Options. From the
Regional or Language Options, click the Regional Options property page and click the
Customize button:
The computer uses two main categories of date display. These categories are based on the
language used by your computer. For example, most user computers that reside in the
United States use a standard known as US English. This commands how the date displays
in the continental US. Each category uses specific characters to represent its value. The m
or M is used for a month, the d or D is used for a day, and the y or Y is used for the year.
The months hold the values 1=January, 2=February, 3=March, 4=April, 5=May, 6=June, 7=July,
8=August, 9=September, 10=October, 11=November, 12=December. Instead on numbers, a month is
represented with the letter m; the computer has the responsibility of finding the right month.
The computer refers to the following characters and it depends on how these characters
are retrieved:
ShortDateFormat = “Format”;
//---------------------------------------------------------------------------
void __fastcall TfrmDates::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
ShortDateFormat = "d";
edtd->Text = DateValue;
ShortDateFormat = "dd";
edtdd->Text = DateValue;
ShortDateFormat = "M";
edtM->Text = DateValue;
ShortDateFormat = "MM";
edtMM->Text = DateValue;
ShortDateFormat = "y";
edty->Text = DateValue;
ShortDateFormat = "yy";
edtyy->Text = DateValue;
ShortDateFormat = "yyy";
edtyyy->Text = DateValue;
ShortDateFormat = "yyyy";
edtyyyy->Text = DateValue;
}
//---------------------------------------------------------------------------
Besides using any of these characters to display their corresponding portion of a date, you
can also combine these characters to display a semi or complete date. To do this, you will
need a symbol or character that separates the portions of a date. In the US English, the
most common character used to separate the portions of a date is the forward slash “/”.
Another character used is the dash “-“.
Using a set of combinations of the above characters, the operating system proposes a list of possible
formats for date display. To access this list, from the Regional Options property page of the Regional and
Language Options dialog box, you can click the arrow of the Short Date Format combo box. The
combinations are:
Here are examples of displaying the formats specified by the operating system:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
ShortDateFormat = "M/d/yyyy";
edtMdyyyy->Text = DateValue;
ShortDateFormat = "M/d/yy";
edtMdyy->Text = DateValue;
ShortDateFormat = "MM/dd/yy";
edtMMddyy->Text = DateValue;
ShortDateFormat = "MM/dd/yyyy";
edtMMddyyyy->Text = DateValue;
ShortDateFormat = "yy/MM/dd";
edtyyMMdd->Text = DateValue;
ShortDateFormat = "yyyy-MM-dd";
edtyyyyMMdd->Text = DateValue;
ShortDateFormat = "dd-MMM-yy";
edtddMMMyy->Text = DateValue;
}
//---------------------------------------------------------------------------
To display the date using the Long Date Format formats, the computer uses the following
combinations:
d: The single d is used to display the numeric day of a month. Each month starts at 1,
then 2, and so on. The month of February can have 28 or 29 days depending on whether
the year is a leap year. The other months have 30 or 31 days. If the day occurs before the
10th, the number would display without the leading 0.
dd: The double d as dd displays the numeric day of the month, from 1 tom 31 depending
on the month and whether it is a leap year for February. If the month occurs before
October, it would display with the leading 0.
M: The single M is used to display the numeric position of the month. January is 1,
February is 2 and December is 12. If the month occurs before October, it would display
without the leading 0.
MM: The double M as MM displays the numeric position of a month from 1 to 12. If the
number is less than 10, it would display with the leading 0.
MMM: The triple M as MMM displays the name of the month using three letters. It uses
a global variable called ShortMonthNames. This variable is defined by the operating
system. By default, the names of the month are Jan, Feb, Mar, Apr, May, Jun, Jul, Aug,
Sep, Oct, Nov, and Dec.
MMMM: The quadruple M as MMMM displays the complete name of a month as
defined as the operating system. The variable used is called LongMonthNames. The
names of the months are January, February, March, April, May, June, July, August,
September, October, November, and December.
Y or YY: The single y or double yy is used to display the numeric year with the last two
digits.
YYY or YYYY: The triple y as yyy or the quadruple one as yyyy is used to display all
four digits of a year.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime Mine;
Edit1->Text = DateToStr(Mine);
}
//---------------------------------------------------------------------------
If the date is initialized with a valid date value, you can omit the conversion function:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime Mine("12/05/1990");
Edit1->Text = Mine;
}
//---------------------------------------------------------------------------
If you supply the integer values of the variable, the compiler would take care of
displaying the equivalent date:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime Mine(1990, 11, 26);
Edit1->Text = Mine;
}
//---------------------------------------------------------------------------
In the same way, if you initialize the variable with a number of days as an integer, the
compiler would calculate and display the corresponding date;
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime Mine = 33895;
Edit1->Text = Mine;
}
//---------------------------------------------------------------------------
In the following example, the current date is stored in a TDateTime variable. Then the
year, month, and day of the variable are extracted before constructing a sentence to
display on a label:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TDateTime Today = Date();
If you want to display a better English version of the sentence above, you can format the
date components to your liking. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TDateTime Today = Date();
AnsiString Dayth, Monthth;
if( Day == 1 )
Dayth = "st";
else if( Day == 2 )
Dayth = "nd";
else if( Day == 3 )
Dayth = "rd";
else
Dayth = "th";
if( Month == 1 )
Monthth = "st";
else if( Month == 2 )
Monthth = "nd";
The DecodeDate() function comes in two versions. Besides the TDateTime’s, the VCL
provides another version whose syntax is:
Since this version is class-independent, the first argument you must supply is a
TDateTime value or variable. This time, the year, the month, and the day values are
passed by reference, which also allows the function to return them altered.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDecodeClick(TObject *Sender)
{
TDateTime Typed = StrToDate(edtDate->Text);
Word Year, Month, Day;
edtDay->Text = Day;
edtMonth->Text = Month;
edtYear->Text = Year;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
If you want to get or display the English name of the decoded month, you can write a
conditional switch whose cases would represent the months by their integral position.
You can also declare an AnsiString variable to hold the names of months and retrieve the
necessary one when needed. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDecodeClick(TObject *Sender)
{
TDateTime Typed = StrToDate(edtDate->Text);
Word Year, Month, Day;
AnsiString Months[] = { "",
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December" };
edtDay->Text = Day;
edtMonth->Text = Months[Month];
edtYear->Text = Year;
}
//---------------------------------------------------------------------------
This function takes three positive integers (unsigned short) that represent:
The following form is equipped with four Edit controls named edtDay, edtMonth,
edtYear and edtDate. When the user clicks the Encode button named btnEncode, the
OnClick event retrieves the values of the day, the month, and the year from their
respective edit box. Then the compiler creates a date from those and displays it in the
Date edit box:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnEncodeClick(TObject *Sender)
{
Word Day, Month, Year;
Day = edtDay->Text.ToInt();
Month = edtMonth->Text.ToInt();
Year = edtYear->Text.ToInt();
This function takes an unsigned short integer argument variable and examines it. If the
argument, which must be a valid year number, is a leap year, the function returns true;
otherwise, it would return false. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if( IsLeapYear(Edit1->Text.ToInt()) )
Edit2->Text = "Leap Year";
else
Edit2->Text = "Not";
}
//---------------------------------------------------------------------------
The following example starts by requesting a date value from the user using an
InputBox() function. Then the date is decoded to retrieve the year value. The year is
examined to find out whether it is a leap year, using the IsLeapYear() function. The
function displays a message box to show its findings:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnLeapYearClick(TObject *Sender)
{
unsigned short Year, Month, Day;
AnsiString Value =
InputBox("Date and Time", "Enter a date: ", "01/01/1900");
To use this function, pass a TDateTime value or variable to the DayOfWeek() function.
The TDateTime object passed as argument must hold a valid date value. After execution,
the function returns an integer between 1 (included) and 7 (included) that represents the
position of the day. Sunday is referred to as the first day of the week and has a value of 1;
Monday is 2, etc.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnGetItClick(TObject *Sender)
{
TDateTime Value = StrToDate(edtDate->Text);
int Day = DayOfWeek(Value);
edtDay->Text = Day;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
Of course, sometimes you will want to get or display the English name of the day. To do
this, you can write a switch conditional statement that would display a name accordingly.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnGetItClick(TObject *Sender)
{
TDateTime Value = StrToDate(edtDate->Text);
int Day = DayOfWeek(Value);
AnsiString DayName;
switch(Day)
{
case 1:
DayName = "Sunday";
break;
case 2:
DayName = "Monday";
break;
case 3:
DayName = "Tuesday";
break;
case 4:
DayName = "Wednesday";
break;
case 5:
DayName = "Thursday";
break;
case 6:
DayName = "Friday";
break;
case 7:
DayName = "Saturday";
}
edtDay->Text = DayName;
}
//---------------------------------------------------------------------------
An alternative would be to declare an array of AnsiString strings to hold the names of the
week days, then retrieve the necessary one using its corresponding position. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnGetItClick(TObject *Sender)
{
TDateTime Value = StrToDate(edtDate->Text);
int Day = DayOfWeek(Value);
AnsiString DayName[] = { "", "Sunday", "Monday", "Tuesday",
"Wednesday", "Thursday", "Friday", "Saturday" };
edtDay->Text = DayName[Day];
}
//---------------------------------------------------------------------------
The DayOfWeek() function comes in two versions. Besides the VCL’s, the TDateTime
class also is equipped with this method. Its syntax is:
This version does not take an argument. Instead, it is called by a TDateTime variable that
needs it. This function returns an integer that represents the weekly position of the day if
the execution is successful. The equivalent version of the above program would be:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnGetItClick(TObject *Sender)
{
TDateTime Value = StrToDate(edtDate->Text);
int Day = Value.DayOfWeek();
edtDay->Text = Day;
}
//---------------------------------------------------------------------------
This function takes two arguments. The first is the date value or variable that serves as
the source or reference to work on. This argument must hold a valid TDateTime date
value; otherwise the execution would fail. The second argument, Months is an integer
that represents the number of months to be added to the first argument. If the addition is
successful, the IncMonth() function returns a new TDateTime value.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtMonthsExit(TObject *Sender)
{
TDateTime StartDate = edtStartDate->Text;
int Months = edtMonths->Text.ToInt();
edtNextPeriod->Text = NextPeriod;
}
//---------------------------------------------------------------------------
The IncMonth() is used to both add and subtract months from a date. To subtract
months, pass the Months argument with a negative value. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtMonthsExit(TObject *Sender)
{
TDateTime StartDate, NextPeriod;
int Months;
if(edtMonths->Text != "")
{
StartDate = edtStartDate->Text;
Months = edtMonths->Text.ToInt();
NextPeriod = IncMonth(StartDate, Months);
edtNextPeriod->Text = NextPeriod;
}
else
edtNextPeriod->Text = edtStartDate->Text;
}
//---------------------------------------------------------------------------
The ReplaceDate() function allows replacing one date with another. On the function, the
Target argument is the new date whose value needs to be replaced by that of the Source
argument. Since the starting point of the TDateTime class is on 12/30/1899, if the Source
argument occurs before that the date, the ReplaceDate() function takes care of reconciling
the negative date. Here is an example of using the function:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnReplaceClick(TObject *Sender)
{
TDateTime Original = StrToDate(edtOriginal->Text);
TDateTime Replacement;
ReplaceDate(Replacement, Original);
edtReplacement->Text = DateToStr(Replacement);
}
//---------------------------------------------------------------------------
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
if(Start == End)
pnlComparison->Caption = "Both dates are the same";
else
pnlComparison->Caption = "Those are different dates!";
}
//---------------------------------------------------------------------------
This comparison is possible because the Equality operator “==” was overloaded in the TDateTime class. Its
syntax is:
To compare two dates using the overloaded Equality operator, call the operator==() on
the desired date and supply the argument date value that is being compared against ar the
Target. The above could have been written:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
This comparison is possible because the inequality operator “!=” is overloaded in the TDateTime class. Its
syntax is:
To compare two dates using the overloaded inequality operator, call the operator==() on
the desired date and supply the argument date value that is being compared against ar the
Target. The above could have been written:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
Alternatively, you can use the overloaded “less than” operator to find out when one date
is less than another. The syntax used is:
To perform the above “less than” comparison, you could implement the event as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
if( Start.operator<(End) )
pnlComparison->Caption = DateToStr(Start) + " occurs prior to " +
DateToStr(End);
else
pnlComparison->Caption = "I can't make up my mind";
}
//---------------------------------------------------------------------------
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
This comparison operator is useful because the “less than or equal to” operator “<=” was
overloaded in the TDateTime class. Its syntax is:
Using the <= overloaded operator, The comparison in the above event could have been
written as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
This “greater than” comparison between two date values is possible because its operator
was overloaded in the TDateTime class. Its syntax is:
Using the overloaded operator, the previous event could have been implemented as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
Using this comparison, you can validation an intermediary operation. Even after finding
out whether the first date is greater than or equal to the second, you can further refine
your comparison inside of the comparison. In the following example, a message box
displays if the “greater than or equal to” comparison returns false:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
This comparison operator is useful because the “greater than or equal to” operator “<=”
was overloaded in the TDateTime class. Its syntax is:
To perform the comparison in the above event using the <= overloaded operator, call the
operator>=() method on the source date value and include the compared date as the
Target argument. The above event could be written as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::pnlComparisonClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
//---------------------------------------------------------------------------
void __fastcall TForm1::edtNbrOfDaysExit(TObject *Sender)
{
TDateTime Start, End;
int NbrOfDays;
Start = StrToDate(edtStartDate->Text);
NbrOfDays = StrToInt(edtNbrOfDays->Text);
if(NbrOfDays <= 1)
{
End = Start;
edtEndDate->Text = End;
}
else
{
edtEndDate->Text = "";
edtEndDate->SetFocus();
}
}
//---------------------------------------------------------------------------
Alternatively, the TDateTime has the assignment operator overloaded to allow assigning
a date variable to another. The syntaxes of the function are:
To assign one date to another using the operator =() function, use a valid TDateTime
value or declare a TDateTime variable and call the operator=() overloaded function by
supplying the intended target TDateTime variable. The above event could be rewritten as;
//---------------------------------------------------------------------------
void __fastcall TForm1::edtNbrOfDaysExit(TObject *Sender)
{
TDateTime Start, End;
int NbrOfDays;
Start = StrToDate(edtStartDate->Text);
NbrOfDays = StrToInt(edtNbrOfDays->Text);
if(NbrOfDays <= 1)
{
End.operator =(Start);
edtEndDate->Text = End;
}
else
{
edtEndDate->Text = "";
edtEndDate->SetFocus();
}
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnAdditionClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
edtAddition->Text = Addition;
}
//---------------------------------------------------------------------------
You can also get the number of days from the user by using another control on the
application. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnEstimateClick(TObject *Sender)
{
TDateTime DepositDate = edtDepositDate->Text;
int Days = edtDays->Text.ToInt();
TDateTime PickupDate = DepositDate + Days;
edtPickupDate->Text = PickupDate;
}
//---------------------------------------------------------------------------
}
//---------------------------------------------------------------------------
The addition operation is possible on a date value because its operator is overloaded in
the TDateTime class. The TDateTime class provides a mechanism of adding a number of
days to a date value. The syntaxes of the overloaded operator are:
When applied to a TDateTime value, the addition operator “+” adds a number of days to
a date. If the number added exceeds the end of year, the class will calculate and encode a
date that corresponds to the date of the subsequent year:
To add a number of months to a date value, decode the date to retrieve its year, month,
and day values. Add the intended number of months to your date and re-encode the date.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnAdditionClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtDate->Text);
int Months = StrToInt(edtValue->Text);
unsigned short Year, Month, Day;
Close();
}
//---------------------------------------------------------------------------
To add a number of years to a date value, decode it to extract the year, month, and day
values. Add the integral number of years to the source year. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnAdditionClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtDate->Text);
int Years = StrToInt(edtValue->Text);
unsigned short Year, Month, Day;
To add an number of days to an existing date value, you can use the += operator as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDisplayClick(TObject *Sender)
{
TDateTime OneDay = StrToDate(edtDate->Text);
TDateTime Added;
OneDay += 5;
edtResult->Text = DateToStr(OneDay);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDifferenceClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
int Diff = End - Start;
edtDifference->Text = Diff;
}
//---------------------------------------------------------------------------
To get the difference of years between two dates, apply the subtraction operator on their
values to get the integral number of days. Then divide this number by 365. This
difference produces the number of years in ranges of 365 days. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDifferenceClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
int Years = End - Start;
edtYears->Text = (Years / 365);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
As an alternative, you can decode both dates and subtract their year values; this would
produce the difference of years with regards to the years, not the real dates. For example,
the difference between 12/31/2001 and 01/01/2002 would produce a year. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDifferenceClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
unsigned short StartYear, StartMonth, StartDay,
EndYear, EndMonth, EndDay;
To get the difference of months between two dates, perform the subtraction operator on
their values to get the number of days elapsed and divide the result by 30. This would
produce a number of months. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDifferenceClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
The subtraction operator “-“ is overloaded in the TDateTime class to allow getting the
difference of days, that is, the elapsed number of days between two dates. The subtraction
is performed as Date2 – Date1. In this case, if Date2 occurs after Date1, the result would
be a positive number; otherwise a negative value would indicate that Date2 occurs before
Date1.
You can also use the operator int() overloaded function to get the difference of days
between two dates. To do this, declare an integer that stores the subtracted number
between two TDateTime dates. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDifferenceClick(TObject *Sender)
{
TDateTime Start = StrToDate(edtStart->Text);
TDateTime End = StrToDate(edtEnd->Text);
edtDifference->Text = Days;
}
//---------------------------------------------------------------------------
To subtract a number of days from a date, you can use the subtraction operator. To assign
the subtracted value to the original date, use the -= operator. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDisplayClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
int IntValue = StrToInt(edtSubtract->Text);
DateValue -= IntValue;
edtResult->Text = DateToStr(DateValue);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
static TDateTime Start = StrToDate(edtStartDate->Text);
edtStartDate->Text = Start--;
}
//---------------------------------------------------------------------------
The TDateTime class allows subtracting one day from a TDateTime value. This is done
using the overloaded decrement operator whose syntaxes are:
To decrement a date value using the -- overloaded operator, you have two options. To use
the pre-decrement operator, as if you were using “--Value”, call the operator--() function.
This would apply the operator before recalling the variable. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
static TDateTime Start = StrToDate(edtStartDate->Text);
edtStartDate->Text = Start.operator --();
}
//---------------------------------------------------------------------------
To use the post-increment operator, which is the same as “Value--“, in which case the
statement is called before being incremented, use the operator--(int) method. The int
argument is not specific but you must supply it. Therefore, type any integer number
between the parentheses. Remember that the argument supplied is not the decrementing
value; it is only a “witness” but it is necessary. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
static TDateTime Start = StrToDate(edtStartDate->Text);
edtStartDate->Text = Start.operator --(2);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnIncrementClick(TObject *Sender)
{
static TDateTime Original = StrToDate(edtDate->Text);
edtIncremented->Text = Original++;
}
//---------------------------------------------------------------------------
The TDateTime class allows you to add one day from a TDateTime value. This is done
using the overloaded increment operator with the following syntaxes:
To apply the pre-increment operator, as if you were using “++Value”, call the
operator++() function. This would apply the operator before recalling the variable. Here
is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnIncrementClick(TObject *Sender)
{
static TDateTime Original = StrToDate(edtDate->Text);
edtIncremented->Text = Original.operator ++();
}
//---------------------------------------------------------------------------
To use the post-increment operator, which is the same as “Value++“, in which case the
statement is called before being incremented, use the operator++(int). The int argument
is not specific but you must supply it. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnIncrementClick(TObject *Sender)
{
static TDateTime Original = StrToDate(edtDate->Text);
edtIncremented->Text = Original.operator ++(12);
}
//---------------------------------------------------------------------------
This was the opening dialog box: This was performed after the first click:
To control how a date value displays, the TDateTime class uses the FormatString()
method. Its syntax is:
Alternatively, the VCL has its own function that performs the same operation. Its syntax
is:
The FormatDateTime() function takes two arguments. The Format argument is a string
that specifies how the date should be formatted. Since this function is not part of the
TDateTime class, it needs a valid TDateTime date value to work on; that is the role of the
DateValue argument.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime DateValue("10/22/2001");
Edit1->Text = DateValue.FormatString("c");
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime DateValue("10/22/2001");
Edit1->Text = FormatDateTime("c", DateValue);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatStringClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("d");
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatDateTimeClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatDateTime->Text = FormatDateTime("d", DateValue);
}
//---------------------------------------------------------------------------
When the day has a numeric value that is less than 10, the default “c” and the “d” formats
display its value without the leading 0. To display the leading 0 as in 02 or 08, use the
“dd” format. Here is an example implemented using the TDateTime::FormatString()
method:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("dd");
}
//---------------------------------------------------------------------------
Using the FormatDateTime() function, you could have written the same event as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = FormatDateTime("dd", DateValue);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("ddd");
}
//---------------------------------------------------------------------------
The same event using the FormatDateTime() function would be written as:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = FormatDateTime("ddd", DateValue);
}
//---------------------------------------------------------------------------
To display the weekday and the numeric day of the month, you can create a format that
combines both strings. When creating this string, the format must be separated inside the
string so the compiler would know which format to apply and where. To separate the
formats, you can use (almost) any character but you should conform to those used in your
regional settings. One of the most regularly used separators on dates is the comma but the
simplest separator is an empty space. Here is an example (using the
TDateTime::FormatString() method):
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("ddd dd");
}
//---------------------------------------------------------------------------
To display the complete name of a weekday, use the “dddd” format string. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("dddd");
}
//---------------------------------------------------------------------------
You can also display the weekday followed by the numeric day of the month. Here is an
example that uses the FormatDateTime() function:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
To display the numeric range of a month, use the “m” format. The months are numbered
as follows: 1=January, 2=February, 3=March, 4=April, 5=May, 6=June, 7=July,
8=August, 9=September, 10=October, 11=November, and 12=December. Here is an
example that displays the numeric month of a date, using the
TDateTime::FormatString() method:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("m");
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = FormatDateTime("m/dd", DateValue);
}
//---------------------------------------------------------------------------
In the same way you can combine a weekday short name followed by the combination of
day/month (or month/day) as you see fit. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = FormatDateTime("ddd m/dd", DateValue);
}
//---------------------------------------------------------------------------
When using the “m” format, if the number of the month is less than 10, the compiler
would display it as 1, 2, 3, 4, 5, 6, 7, 8 or 9, without the leading 0. If you want to display
the leading zero for a month between 1 and 9, as 01 or 07, use the “mm” format. Here is
an example with the TDateTime::FormatString() method:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("mm");
}
//---------------------------------------------------------------------------
You can also use this format when constructing a combined date:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("dddd, mm/dd");
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("mmm");
}
//---------------------------------------------------------------------------
This time, the name of the month would become more explicit in a combined format,
allowing the application to be more explicit. To create such a combined date, apply the
rules we have reviewed so far. The following TDateTime::FormatString()
implementation displays a date as short weekday-day-short month name combination:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
You can also use a comma and space to separate the name of the weekday from the other
components. The following event uses the FormatDateTime() function:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = FormatDateTime("dddd, dd mmm", DateValue);
}
//---------------------------------------------------------------------------
To display a complete name of a month, use the “mmmm” format. The name would
display as one of the following: January, February, March, April, May, June, July,
August, September, October, November, and December; confirming to the Regional
Settings of your computer. Here is an example that uses the
TDateTime::FormatString() method:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
AnsiString Formatter = "ddd, d mmmm";
edtFormatString->Text = DateValue.FormatString(Formatter);
}
//---------------------------------------------------------------------------
Another implementation that uses the FormatDateTime() function can display the
weekday-day-month combination with an empty space as the separator:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
AnsiString Formatter = "dddd, dd mmmm";
edtFormatString->Text = FormatDateTime(Formatter, DateValue);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("y");
}
//---------------------------------------------------------------------------
To make the displays we have used so far a little more explicit, you can include the year
value in a combined date string, as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("ddd dd mmm yy");
}
//---------------------------------------------------------------------------
Therefore, you can apply any combination of the formats we have used so far to display a
date, as illustrated in the following FormatDateTime() function call:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
AnsiString Formatter = "dddd dd mmmm yy";
edtFormatString->Text = FormatDateTime(Formatter, DateValue);
}
//---------------------------------------------------------------------------
A year value represented with two digits is hardly explicit, unless you have a good reason
for using it. The alternative is to use all four digits to display a year. This format is
created with the “yyy” or the “yyyy” strings. Here is an example with the
TDateTime::FormatString() method:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
edtFormatString->Text = DateValue.FormatString("yyy");
}
//---------------------------------------------------------------------------
Since this format would be the only one with four digits in a combined string, it makes a
date easier to read. Once again, you can apply the rules we have used so far, to create and
display a combined date. The default format used by Microsoft Windows for the English
language is as Sunday, January 27, 2002. You can use the TDateTime::FormatString()
method to create such a format as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
AnsiString Formatter = "dddd, mmmm dd, yyyy";
edtFormatString->Text = DateValue.FormatString(Formatter);
}
//---------------------------------------------------------------------------
Using these rules, you can display a date as you wish. The following FormatDateTime()
function display a date differently than the event above:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFormatClick(TObject *Sender)
{
TDateTime DateValue = StrToDate(edtDate->Text);
AnsiString Formatter = "dddd d mmmm yyyy";
edtFormatString->Text = FormatDateTime(Formatter, DateValue);
}
//---------------------------------------------------------------------------
As done with dates, most of the operations performed on time values are centered around
the TDateTime class. This class is based on a double-precision number initialized at 0.00.
The constant 0.00 corresponds to 12/30/1899 at midnight. A double-precision number is
made of two sections: an integer part and a decimal side. The integral part is a natural
number with no decimal value, such as 8, 1450, or 32. For the TDateTime class, the
integral section represents the number of days that have elapsed since 12/30/1899.
On a double-precision number, such as 204.58, the decimal part starts with a period “.”
and is made of all digits on the right side of the period. For the TDateTime class, the
decimal part represents the number of seconds that have elapsed since midnight.
By default, the compiler refers to the Regional Settings of your computer to display the
time, separating it in hour, minute, second, and AM/PM. The default symbol to separate
the hour and the minute, or the minute and the second is “:”. To separate the seconds and
the AM/PM, the compiler leaves a one-character empty space between them.
The time in regular value is a floating number that ranges from 0 included to 1 excluded.
More precisely, the time is a value defined as follows:
To declare a time variable, use the TDateTime class and specify the name for the
variable. Here is an example:
TDateTime Mine;
If not assigned a valued, this variable is initialized at midnight or 12:00:00 AM. You can
display its value in an Edit control as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeValue;
Edit1->Text = TimeValue;
}
//---------------------------------------------------------------------------
You can initialize a time value with a double-precision number between 0.00000 and
0.99999. Here is an example:
TDateTime Value(0.2185);
You can also get the value from an intermediary action or request it from the user. This
allows you, if necessary, to convert any floating-point number to a time value, as follows:
You can also use an independent floating-point number to initialize a time variable. Here
is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTimeClick(TObject *Sender)
{
double Number = edtNumber->Text.ToDouble();
TDateTime TimeValue = Number;
edtTime->Text = TimeValue;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
Still using the default constructor, if you know the time you want to initialze a variable
with, you can provide it. To do that, declare an instance of the TDateTime constructor
and type the time value between the double-quotes of the parentheses. If the time is
known only for the hour(s) and the minute(s), you can initialize it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeValue("08:22");
Label3->Caption = TimeValue;
}
//---------------------------------------------------------------------------
When using this formula, the hour value must be between 0 and 23. Any other value
outside of this range will cause an error. The minute value must range from 0 to 59;
otherwise, an error would be thrown. If the hour portion has a value between 0 and 11:59,
the time is set in the morning with the AM in the AM/PM section. If the hour portion is
between 12 and 23, the time is set in the afternoon. When displaying it, the compiler, by
default, calculates and displays the 0 to 12 portion and then displays PM in the AM/PM
section.
You can also initialize a time value using the Hour:Minute:Second formula as a string.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeValue("20:22:52");
Label3->Caption = TimeValue;
}
//---------------------------------------------------------------------------
Once again, in the absence of an AM/PM section, the compiler would consider the hour
portion to evaluate whether the time occurs in the morning or in the afternoon. The value
of the seconds must be between 0 and 59; otherwise, an error will be thrown.
You can also initialize a time value by specifying the AM/PM portion as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
The AM and the PM can be in uppercase or lowercase. In otherwords the AM/PM portion
can be represented as AM, Am, aM, am, PM, Pm, pM, or pm. Only the characters A and
P (uppercase or lowercase) are accepted as the first character. Only the M or m characters
are accepted as the second character. Any other combination or other character will cause
an error.
If you know the values of the hour, the minute, the second, and the millisecond, you can
use them to initialize a time variable. To do this, you must supply the arguments in order
following the constructor:
The hour value must be between 0 and 23. The minutes must be between 0 and 59. The
Second argument must have a value between 0 and 59. Whenever the seconds are not
important to represent the time, provide their value as 0. The milliseconds must range
from 0 to 999. If you do not know the millisecond value, provide it as 0. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeValue(8, 20, 42, 605);
ShowMessage("The time considered is " + TimeValue);
}
//---------------------------------------------------------------------------
Since a double-precision number has a decimal section that represents the time of the
day, you can assign such a value to a TDateTime variable to initialize a time value. If the
integral part of the value is greater than 0, it would represents the number of days. If it is
0, only the time would be recognized as a fraction of the day. Using this, you can initia
The integral part is section y number
This function takes a string as argument. The string must be in a in a valid time format,
following the Regional Rettings of the Control Panel. For example, in the United States,
the components of a time are separated with a colon “:”. The typical formats of a time
are:
If the string contains an invalid date, the conversion would fail and the program would
throw an error. If the conversion is successful, the function returns a valid time. Here is
an example:
//---------------------------------------------------------------------------
void __fastcall TForm2::btnConvertClick(TObject *Sender)
{
TDateTime Value = StrToTime(edtSource->Text);
edtTarget->Text = Value;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeValue("22:32:58");
AnsiString Right = TimeValue;
Edit1->Text = Right;
}
//---------------------------------------------------------------------------
Therefore, to convert a time value to a string, you can simply assign the time to a string
variable. You can also explicity call the overloaded AnsiString as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime StartTime("9:05:00 AM");
AnsiString ToDisplay = StartTime.operator AnsiString();
Edit1->Text = ToDisplay;
}
//---------------------------------------------------------------------------
The TDateTime class is also equipped with a method that can be used to convert a time
value to a string when necessary. The syntax used is:
To convert a time value to a string, declare a TDateTime variable and call the
TimeString() method. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeValue("22:32:58");
AnsiString ToDisplay = TimeValue.TimeString();
Edit1->Text = ToDisplay;
}
//---------------------------------------------------------------------------
Alternatively, to convert a time value to a string, you can use the TimeToStr() function.
Its syntax is:
This function takes one argument, which is the time value that needs to be converted. If
the argument is not a valid time value, the conversion would fail and the program would
throw an error. If the conversion is successful, the function returns an AnsiString value.
Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
AnsiString Current = TimeToStr(Time());
edtTarget->Text = Current;
}
//---------------------------------------------------------------------------
To convert a time value to a double-precision number, simply cast the time value to a
double. In the following example, the current time is converted to double and displayed
in an edit box when the user clicks a button on a form:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeX = Time();
double Value = double(TimeX);
Edit1->Text = Value;
}
//---------------------------------------------------------------------------
You can use this function transparently as done in the previous example. You can also
call it explicitly call it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime TimeX("09:42:18 AM");
double Value = TimeX.operator double();
Edit1->Text = Value;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Caption = Time();
}
//---------------------------------------------------------------------------
This ability is independent of the format of the time; that is, it independent of the form of
initialization or source of the time value.
In the following example, the current time is stored in a TDateTime variable named
RightNow. A form is equipped with four Edit controls named edtTime edtHours,
edtMinutes, and edtSeconds. Although the mSec argument is required to decode a time
value, it was used only during the decoding operation. After calling the function, the
hour, the minute, and the second are retrieved and displayed in the corresponding edit
boxes:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDecodeClick(TObject *Sender)
{
TDateTime RightNow = Time();
edtTime->Text = RightNow;
edtHours->Text = Hours;
edtMinutes->Text = Minutes;
edtSeconds->Text = Seconds;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnExitClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
Besides the TDateTime::DecodeTime() method, the VCL provides a function that can be
used to decode a time value. Its syntax is:
This function takes four positive integers (unsigned short) that represent:
Example: the following form is equipped with five Edit controls named edtHours,
edtMinutes, edtSeconds, edtMilliseconds, and edtTime. When the user clicks the Encode
button named btnEncode, the OnClick event retrieves the of the hour, the minute, the
second, and the millisecond values from their respective edit boxes. The the compiler
creates a time from those valules and displays the result in the Time edit box:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnEncodeClick(TObject *Sender)
{
Word Hours, Minutes, Seconds, Milliseconds;
Hours = edtHours->Text.ToInt();
Minutes = edtMinutes->Text.ToInt();
Seconds = edtSeconds->Text.ToInt();
Milliseconds = edtMilliseconds->Text.ToInt();
The ReplaceTime() function takes two arguments. The second argument is the original
time that is used as the time reference. The first argument is the time value that needs to
be changed or replaced. The TimeSource argument must be a valid time variable or in a
recognizable format; otherwise, the function would fail and throw an error. The
TimeTarget argument can be an existing time value of a TDateTime variable. After the
function has executed, if successful, the time portions of both arguments would be the
same.
EXAMPLE
In the following example, two time values are retrieved from two edit boxes for
comparison. If both times are the same, a message displays accordingly on a panel:
//---------------------------------------------------------------------------
void __fastcall TForm1::Panel1Click(TObject *Sender)
{
TDateTime StartTime = StrToTime(edtStart->Text);
TDateTime EndTime = StrToTime(edtEnd->Text);
The equality comparison works on time values thanks the overloaded equality operator
on the TDateTime class:
The equality comparison works on all components of a time value. If either the hour, the
minute, the second, or the AM/PM is not the same the operation renders false. If you
want to compare just the hours, you should decode the time values and then perform the
comparison on the hours.
//---------------------------------------------------------------------------
void __fastcall TForm1::Panel1Click(TObject *Sender)
{
TDateTime StartTime = StrToTime(edtStart->Text);
TDateTime EndTime = StrToTime(edtEnd->Text);
The difference comparison works on all four entities of a time value. It examines the
hours, minutes, seconds, and AM/PM of the values provides on both sides of the
operator. If any of both similar components are different, the operation produces a true
result. This operation is based on the overloaded != operator whose syntax is:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCompareClick(TObject *Sender)
{
TDateTime Start = StrToTime(edtStart->Text);
TDateTime End = StrToTime(edtEnd->Text);
The “less than” comparison is based on its overloaded operator in the TDateTime class
using the following syntax:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCompareClick(TObject *Sender)
{
TDateTime Start = StrToTime(edtStart->Text);
TDateTime End = StrToTime(edtEnd->Text);
The operator that allows this comparison uses the following syntax:
//---------------------------------------------------------------------------
The “greater than” operator compare the hours, minutes, seconds, and AM/PM portions
of two dates and evaluates if the left date occurred after the right date; in this case, the
operator would produce a true Boolean value. This operation is based on its overloaded
operator from the TDateTime class. Its syntax is:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCompareClick(TObject *Sender)
{
TDateTime Start = StrToTime(edtStart->Text);
TDateTime End = StrToTime(edtEnd->Text);
The TDateTime class is equipped with the FormatString() function whose syntax is:
This function takes, as an argument, a string that specifies how the components of the
time value should display. The VCL provides an alternative function to apply the same
technique.; Its syntax is:
When calling the FormatDateTime() function, you must pass two arguments. The Time
argument represents a time value or a variable that holds a valid time value. The Format
argument is a string that specifies how the time of the Time argument should display.
To display the time using the default format, call the TDateTime::FormatString() method
and provide the Format argument as “c”. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime RightNow = Time();
RightNow.FormatString("c");
Edit1->Text = RightNow;
}
//---------------------------------------------------------------------------
hh:nn:ss AM/PM
To ignore a leading zero when an hour less than 10 displays, use only h for the hour
portion. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime RightNow = Time();
To display the leading zero, use the hh format for the hour portion. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime RightNow = Time();
The rule to display or not display the leading zero for the minutes is the same. To avoid
the leading zero, use only one n when displaying the time. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTimeClick(TObject *Sender)
{
TDateTime TimeX("08:05:52 AM");
These same rules apply for the seconds portions of the time display.
The AM/PM portion is case sensitive. This allows you display it in uppercase or in
lowercase. To display the AM/PM section in lowercase, type am/pm or ampm in the
AM/PM section. On the other hand, to display it in uppercase, type it as AM/PM or
AMPM. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTimeClick(TObject *Sender)
{
TDateTime TimeX("18:05:52");
This function takes a string as argument. The string must have a valid TDateTime format;
otherwise, the operation would faild. If everything works fine, after converting the string,
the function returns a valid TDateTime value.
In the following example, a form is created with a MaskEdit control named edtSource, an
Edit control named edtTarget, two Button controls named btnConvert and btnExit. The
EditMask of the MaskEdit control is configured as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
TDateTime Current = StrToDateTime(edtSource->Text);
edtTarget->Text = Current;
}
//---------------------------------------------------------------------------
This function takes, as argument, a valid TDateTime variable or value. If the argument is
not a valid date and time value, an error would result. After performing the conversion on
the date and time value, the function returns the value as a string.
In the following example, when the user clicks a button named btnConvert, the event uses
the Now() funtion to retrieve the current date and time then converts it to string and
displays the string in an Edit control named edtTarget:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnConvertClick(TObject *Sender)
{
AnsiString Current = DateTimeToStr(Now());
edtTarget->Text = Current;
}
//---------------------------------------------------------------------------
An alternative method to converting a date and time value to a string consists of using the
TDateTime::DateTimeString() method. Its syntax:
This function does not need an argument. To use it, declare a TDateTime date variable
and call the DateTimeString() method. Here is an example;
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TDateTime Current = Now();
AnsiString Right = Current.DateTimeString();
Edit1->Text = Right;
}
//---------------------------------------------------------------------------
Chapter 10:
Using C++ in VCL
Applications
int Age;
double Distance;
char FirstName[12];
INT MemberID;
BOOLEAN IsWorking;
Cardinal ItemLength;
Extended TotalPrice;
• A Win32 object
CHARFORMAT2 cfm;
HBITMAP hBitmap;
• A VCL object
TOpenDialog* FileOpener;
Tform *Locker;
//---------------------------------------------------------------------------
void __fastcall TForm1::btnComputeClick(TObject *Sender)
{
// Declare a variable for each grade needed
Double English, French, Geography, History, Sports;
//---------------------------------------------------------------------------
void __fastcall TForm1::btnExitClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
8. To test the form, on the main menu, click Run Run.
9. After viewing the dialog, click the Exit button to close it.
10. To use more variables, add two labels and two Edit controls to the form. Name
the Edit controls edtTotal and edtAverage respectively.
11. To use the new edit boxes, change the btnComputeClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnComputeClick(TObject *Sender)
{
// Declare a variable for each grade needed
Double English, French, Geography, History, Sports;
Double Total, Average;
// Display the total and the average in the appropriate edit boxes
edtTotal->Text = Total;
edtAverage->Text = Average;
}
//---------------------------------------------------------------------------
12. Test the form. Here is an example:
//---------------------------------------------------------------------------
Double GetMin(Double g[], int size);
Double GetMax(Double g[], int size);
void Ranges(Double g[], int& r1, int& r2, int& r3, int& r4, int& r5);
//---------------------------------------------------------------------------
If you call a function after it has been defined, you do not need to declare it in the top
section of the source file.
To define a function, implement its behavior as you see fit. For example, the following
function receives two integer arguments, use them to create a long integer that represents
an RGB color, converts the the result to a TColor enumerator, and returns the resulting
color:
return Clr;
2. Add two new labels to the form as on the above picture. Once again, the Edit
controls are named after their corresponding labels: edtHighest and edtLowest
3. To add your own functions that calculate the highest and lowest values, change
the source file as follows:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
Double __fastcall GetMin(Double g[], int size)
{
// Set the minimum as the first member of the array
Double Min = g[0];
//---------------------------------------------------------------------------
Double __fastcall GetMax(Double g[], int size)
{
// Set the maximum as the first member of the array
Double Max = g[0];
// Display the total and the average in the appropriate edit boxes
edtTotal->Text = edtTotal->Text.sprintf("%.2f", Total);
edtAverage->Text = edtAverage->Text.sprintf("%.2f", Average);
edtHighest->Text = edtHighest->Text.sprintf("%.2f", Highest);
edtLowest->Text = edtLowest->Text.sprintf("%.2f", Lowest);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::btnExitClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
4. Test the form.
5. To improve your application, enlarge the form and add the following labels and
Edit controls. The Edit controls will be named after their labels as follows:
edtBiology, edtTechnology, edtCompArchitecture, edtCompSciences,
edtMorale:
8. To add the grades of the new edit boxes, change the btnComputeClick event as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnComputeClick(TObject *Sender)
{
// Declare a variable for each grade needed
Double English, French, Geography, History, Sports,
Biology, Technology, CompArch, CompSciences, Morale;
Double Total, Average, Highest, Lowest;
English = edtEnglish->Text.ToDouble();
French = edtFrench->Text.ToDouble();
Geography = edtGeography->Text.ToDouble();
History = edtHistory->Text.ToDouble();
Sports = edtSports->Text.ToDouble();
Biology = edtBiology->Text.ToDouble();
Technology = edtTechnology->Text.ToDouble();
CompArch = edtCompArchitecture->Text.ToDouble();
CompSciences = edtCompSciences->Text.ToDouble();
Morale = edtMorale->Text.ToDouble();
// Display the total and the average in the appropriate edit boxes
edtTotal->Text = edtTotal->Text.sprintf("%.2f", Total);
edtAverage->Text = edtAverage->Text.sprintf("%.2f", Average);
edtHighest->Text = edtHighest->Text.sprintf("%.2f", Highest);
edtLowest->Text = edtLowest->Text.sprintf("%.2f", Lowest);
}
//---------------------------------------------------------------------------
9. Press F12 to display the form. Double-click the Reset button and implement it as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnResetClick(TObject *Sender)
{
edtEnglish->Text = AnsiString("0.00");
edtFrench->Text = AnsiString("0.00");
edtGeography->Text = AnsiString("0.00");
edtHistory->Text = AnsiString("0.00");
edtSports->Text = AnsiString("0.00");
edtBiology->Text = AnsiString("0.00");
edtTechnology->Text = AnsiString("0.00");
edtCompArchitecture->Text = AnsiString("0.00");
edtCompSciences->Text = AnsiString("0.00");
edtMorale->Text = AnsiString("0.00");
edtTotal->Text = AnsiString("0.00");
edtAverage->Text = AnsiString("0.00");
edtHighest->Text = AnsiString("0.00");
edtLowest->Text = AnsiString("0.00");
}
//---------------------------------------------------------------------------
11. After testing the edit boxes with some values between 0 and 100, click the Reset
button.
12. Click the Exit button to return to Bcb.
13. To further improve your application, we will find the number of grades that
range in some categories.
Add the following labels and Edit controls. Named after their labels, the Edit
controls are called edtedtRange90100, edtRange8089, edtRange7079,
edtRange6069, edtBelow60:
14. We need a function that would take the array of grades and compute the ranges
of its members. After the function has finished examining the array, it should
return the results of each range. One of the ways we can do this is to pass each
integer range as reference (we could also pass them as pointers); this allows a
function, even declared as void, to return multiple values. To create this
function, define it on top of the btnComputeClick event, as follows:
//---------------------------------------------------------------------------
void __fastcall Ranges(Double g[], int& r1, int& r2, int& r3, int& r4,
int& r5)
{
//---------------------------------------------------------------------------
void __fastcall TForm1::btnComputeClick(TObject *Sender)
{
// Declare a variable for each grade needed
Double English, French, Geography, History, Sports,
Biology, Technology, CompArch, CompSciences, Morale;
Double Total, Average, Highest, Lowest;
// Display the total and the average in the appropriate edit boxes
edtTotal->Text = edtTotal->Text.sprintf("%.2f", Total);
edtAverage->Text = edtAverage->Text.sprintf("%.2f", Average);
edtHighest->Text = edtHighest->Text.sprintf("%.2f", Highest);
edtLowest->Text = edtLowest->Text.sprintf("%.2f", Lowest);
edtRange90100->Text = Range1;
edtRange8089->Text = Range2;
edtRange7079->Text = Range3;
edtRange6069->Text = Range4;
edtBelow60->Text = Range5;
}
//---------------------------------------------------------------------------
16. To synchronize with resetting the grade values, change the btnResetClick event
as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnResetClick(TObject *Sender)
{
...
edtRange90100->Text = 0;
edtRange8089->Text = 0;
edtRange7079->Text = 0;
edtRange6069->Text = 0;
edtBelow60->Text = 0;
}
//---------------------------------------------------------------------------
17. Test the form. Here is an example:
18. To enhance the look of the form, add one bevel around the grades, another bevel
around the calculated boxes, and a bsRaised Style bevel around the buttons:
There are various ways you can create your own global variables and functions. To use a
function available to other functions or event, in the private or public sections of the unit
that will need it, declare the function:
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
WORD Salute();
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
If you add it to the private section, it will be accessible only to other functions or events
of the same unit. Otherwise, if you want the function to be accessible outside of its unit,
declare it in the public section:
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
WORD Salute();
public: // User declarations
Extended CalcMeasure();
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
Probably one of the most efficient ways of adding a function is by using the
ClassExplorer where you can right-click a class such as TForm and add a Method.
After declaring a function in the header file, you should define it in the source file. Once
it has been defined, it can be called by any function or event of the same unit.
If you declare a function as public, you can indirectly access it from another unit or form.
26. Make sure you delete the content of the Text field for each edit box
27. Click the OK button and press Delete to delete it.
28. Set the Caption property of the Cancel button to Close.
29. Add a button control with a caption of &Calculate and a name of btnCalculate
30. Set the Default property of the btnCalculate control to true.
31. Right-click in the middle of the dialog and click Tab Order.
32. Arrange the tab order as follows:
33. Click OK
34. To save the new form and unit, on the Standard toolbar, click the Save button.
35. Make sure Karyne is displaying in the Save In combo box. Type Change and
press Enter.
36. To add another one of C++ Builder’s dialog boxes, on the main menu, click File
New
37. On the Object Repository, click the Dialogs property page.
38. Click Standard Dialog (Horizontal)
39. Click OK.
40. To save the new dialog box, on the Standard toolbar, click the Save button.
41. Type FoodPrices and press Enter
Here is the design for the new dialog box:
42. Change the caption of the new dialog to Karyne’s Resto – Food Prices
43. Change the dimensions to Height = 288 and Width = 430
44. Change the name to frmFoodPrices
45. Besides the existing bevel, add another bevel control to the right side of the
form.
46. Change the Shape property to bsFrame
47. Place a label on the top line of the left bevel with a caption of Food Menu
48. Add another label to the top of the right bevel with a caption of Side Orders
49. Design the dialog box using the following tables:
50. To select everything on the form, on the main menu, click Edit Select All.
Notice that all controls on the form are selected.
51. To copy the selection to the clipboard, on the main menu, click Edit Copy.
52. To display the starting form, press Shift + F12.
53. On the View Form dialog box, click FoodOrders and click OK.
54. To paste the items and their prices, on the main menu, click Edit Paste. Press
Esc to deselect everything.
Here is the design we will apply to the Food Orders form
EdtPC6Price edtORPrice
true true
edtPC12Price
true edtMSPrice
true
edtHC6Price
true edtAPPrice
edtHC12Price true
true
edtDPPrice
edtSHC6Price true
true
edtSHC12Price edtSPrice
true true
edtFOF6Price edtOJPrice
true true
edtFOF12Price
true
edtC6Price
true
edtC12Price
true
edtCB6Price
true
edtCB12Price
true
edtTS6Price
true
edtTS12Price
true
58. Move the right bevel and all of its content to the right section of the form (since
the bevel is not a container, it cannot “carry” its controls; you will select each
manually). Enlarge the left bevel.
59. Add the # edit boxes using the following tables:
60. Add a panel to the bottom of the form. Set its BevelInner property to
bvLowered and its BevelOuter property to bvRaised
61. Inside of the panel, add the following controls
62. Right-click in the middle of the form, click Tab Order and arrange the sequence
of control navigation as follows:
63. Click OK
When the user has made changes to the prices using an appropriate dialog box, she will
click OK and the new prices will be replicated to the main form
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::btnExitClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
3. To declare a global variable, right-click the Class Explorer window and click
New Field…
4. Set the Field Name to PricePC6 and in the Add To Class combo box, select
TfrmFoodOrders. In the Type combo box, type d and then double-click the
down-pointing arrow to display double. Click the Private radio button.
private:
double PricePC6; // User declarations
12. To display the form, press F12.
13. To include the header file of the Food Prices form, on the main menu, click File
Include Unit Hdr…
14. On the Use Unit dialog box, click FoodPrices and click OK
15. On the form, double-click the Change Prices button and implement its OnClick
event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::btnChangePricesClick(TObject *Sender)
{
// Find out whether the user clicked OK
if( frmFoodPrices->ShowModal() == mrOk )
{
// Since the user clicked OK, transfer each price changed
// from the Food Prices dialog box to the Food Order form
edtPC6Price->Text = frmFoodPrices->edtPC6Price->Text;
edtPC12Price->Text = frmFoodPrices->edtPC12Price->Text;
edtHC6Price->Text = frmFoodPrices->edtHC6Price->Text;
edtHC12Price->Text = frmFoodPrices->edtHC12Price->Text;
edtSHC6Price->Text = frmFoodPrices->edtSHC6Price->Text;
edtSHC12Price->Text = frmFoodPrices->edtSHC12Price->Text;
edtFOF6Price->Text = frmFoodPrices->edtFOF6Price->Text;
edtFOF12Price->Text = frmFoodPrices->edtFOF12Price->Text;
edtC6Price->Text = frmFoodPrices->edtC6Price->Text;
edtC12Price->Text = frmFoodPrices->edtC12Price->Text;
edtCB6Price->Text = frmFoodPrices->edtCB6Price->Text;
edtCB12Price->Text = frmFoodPrices->edtCB12Price->Text;
edtCB6Price->Text = frmFoodPrices->edtCB6Price->Text;
edtCB12Price->Text = frmFoodPrices->edtCB12Price->Text;
edtTS6Price->Text = frmFoodPrices->edtTS6Price->Text;
edtTS12Price->Text = frmFoodPrices->edtTS12Price->Text;
edtFFPrice->Text = frmFoodPrices->edtFFPrice->Text;
edtORPrice->Text = frmFoodPrices->edtORPrice->Text;
edtMSPrice->Text = frmFoodPrices->edtMSPrice->Text;
edtAPPrice->Text = frmFoodPrices->edtAPPrice->Text;
edtDPPrice->Text = frmFoodPrices->edtDPPrice->Text;
edtOJPrice->Text = frmFoodPrices->edtOJPrice->Text;
}
}
//---------------------------------------------------------------------------
16. To actucal price of each item is calculated by multiplying the quantity set of the
item by the unit price. Since there are many items that perform the same
calculation, we will use a global function that takes the content of a quantity edit
box and the content of a unit price. After the calculation, the function will return
the total price of the particular item.
Right-click in the Class Explorer and click New Method…
17. Set the method name to CalcItemPrice
18. In the Add to Class combo box, select TfrmFoodOrders and the arguments as
AnsiString StrQty, AnsiString StrUnitPrice
19. In the Function Result combo box, type d and then double-click the down-
pointing arrow. The double data type should be selected. Otherwise, set the
Function Result to double. Click the __fastcall check box:
//---------------------------------------------------------------------------
double __fastcall TfrmFoodOrders::CalcItemPrice(AnsiString StrQty,
AnsiString StrUnitPrice)
{
int Qty;
double UnitPrice, Price;
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtPC6NbrChange(TObject *Sender)
{
AnsiString Quantity, UnitPrice;
Quantity = edtPC6Nbr->Text;
UnitPrice = edtPC6Price->Text;
}
//---------------------------------------------------------------------------
24. Once we have two strings that represent the quantity and the unit orice
respectively, we can pass them to the CalcItemPrice() function. We will use the
returned value to set the total price of this unit. Therefore, change the
edtPC6Nbr OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtPC6NbrChange(TObject *Sender)
{
AnsiString Quantity, UnitPrice;
Quantity = edtPC6Nbr->Text;
UnitPrice = edtPC6Price->Text;
25. We will use this same technique to find the total price of each item. Once we
have the prices, we can display the total price of the order in the Total edit box.
To display this total, we will use a global function that can add all of the total
prices and display the result in the Total.
If it is not expanded yet, click the + sign of the KaryneResto – Classes folder.
Right-click TfrmFoodOrders and click New Method…
26. Set the Method Name to DisplayTotal
27. Make sure the Add to Class combo box displays TfrmFoodOrders. Leaving the
Arguments empty, set the Function Result to void and click the __fastcall check
box. Click OK.
28. Implement the DisplayTotal() function as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::DisplayTotal()
{
double TotalOrder = PricePC6;
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtPC6NbrChange(TObject *Sender)
{
AnsiString Quantity, UnitPrice;
Quantity = edtPC6Nbr->Text;
UnitPrice = edtPC6Price->Text;
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtHC6NbrChange(TObject *Sender)
{
PriceHC6 = CalcItemPrice(edtHC6Nbr->Text, edtHC6Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtSHC6NbrChange(TObject *Sender)
{
PriceSHC6 = CalcItemPrice(edtSHC6Nbr->Text, edtSHC6Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtFOF6NbrChange(TObject *Sender)
{
PriceFOF6 = CalcItemPrice(edtFOF6Nbr->Text, edtFOF6Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtC6NbrChange(TObject *Sender)
{
PriceC6 = CalcItemPrice(edtC6Nbr->Text, edtC6Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtCB6NbrChange(TObject *Sender)
{
PriceCB6 = CalcItemPrice(edtCB6Nbr->Text, edtCB6Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtTS6NbrChange(TObject *Sender)
{
PriceTS6 = CalcItemPrice(edtTS6Nbr->Text, edtTS6Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtPC12NbrChange(TObject *Sender)
{
PricePC12 = CalcItemPrice(edtPC12Nbr->Text, edtPC12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtHC12NbrChange(TObject *Sender)
{
PriceHC12 = CalcItemPrice(edtHC12Nbr->Text, edtHC12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtSHC12NbrChange(TObject *Sender)
{
PriceSHC12 = CalcItemPrice(edtSHC12Nbr->Text, edtSHC12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtFOF12NbrChange(TObject *Sender)
{
PriceFOF12 = CalcItemPrice(edtFOF12Nbr->Text, edtFOF12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtC12NbrChange(TObject *Sender)
{
PriceC12 = CalcItemPrice(edtC12Nbr->Text, edtC12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtCB12NbrChange(TObject *Sender)
{
PriceCB12 = CalcItemPrice(edtCB12Nbr->Text, edtCB12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtTS12NbrChange(TObject *Sender)
{
PriceTS12 = CalcItemPrice(edtTS12Nbr->Text, edtTS12Price->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtFFNbrChange(TObject *Sender)
{
PriceFF = CalcItemPrice(edtFFNbr->Text, edtFFPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtORNbrChange(TObject *Sender)
{
PriceOR = CalcItemPrice(edtORNbr->Text, edtORPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtMSNbrChange(TObject *Sender)
{
PriceMS = CalcItemPrice(edtORNbr->Text, edtORPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtAPNbrChange(TObject *Sender)
{
PriceAP = CalcItemPrice(edtAPNbr->Text, edtAPPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtDPNbrChange(TObject *Sender)
{
PriceDP = CalcItemPrice(edtDPNbr->Text, edtDPPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtSNbrChange(TObject *Sender)
{
PriceS = CalcItemPrice(edtSNbr->Text, edtSPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::edtOJNbrChange(TObject *Sender)
{
PriceOJ = CalcItemPrice(edtOJNbr->Text, edtOJPrice->Text);
DisplayTotal();
}
//---------------------------------------------------------------------------
35. If the user decides to change the price of items, we had decided that this would
be performed on a different form. When the price of items has been changed and
the clerk clicks OK, since it is likely that an order processing was going on, we
need to immediately recalculate the total price. To do that, we will ask each item
to re-evaluate itself:
//---------------------------------------------------------------------------
void __fastcall TfrmFoodOrders::btnChangePricesClick(TObject *Sender)
{
// Find out whether the user clicked OK
if( frmFoodPrices->ShowModal() == mrOk )
{
...
}
edtPC6NbrChange(Sender);
edtHC6NbrChange(Sender);
edtHC6NbrChange(Sender);
edtSHC6NbrChange(Sender);
edtFOF6NbrChange(Sender);
edtC6NbrChange(Sender);
edtCB6NbrChange(Sender);
edtTS6NbrChange(Sender);
edtPC12NbrChange(Sender);
edtHC12NbrChange(Sender);
edtSHC12NbrChange(Sender);
edtFOF12NbrChange(Sender);
edtC12NbrChange(Sender);
edtCB12NbrChange(Sender);
edtTS12NbrChange(Sender);
edtFFNbrChange(Sender);
edtORNbrChange(Sender);
edtMSNbrChange(Sender);
edtAPNbrChange(Sender);
edtDPNbrChange(Sender);
edtSNbrChange(Sender);
edtSNbrChange(Sender);
edtOJNbrChange(Sender);
}
//---------------------------------------------------------------------------
36. To test the form, on the main menu, click Run Run
37. Change the quantities of different items and make sure that the calculation is
performed and the total order is displayed immediately.
38. After using the form, close it.
39. Display the Food Order form.
40. To include the header file of the Change form, on the main menu, click File
Include Unit Hdr…
41. On the Use Unit dialog box, the Change unit should be selected because it is the
only one. Otherwise, select Change and click OK.
42. Double-click the Get the Change button and implement its OnClick event as
follows:
//---------------------------------------------------------------------
void __fastcall TfrmChange::btnCalculateClick(TObject *Sender)
{
double TotalOrder, AmountTended, Difference;
46. On top of the current source file, include the math.h library:
//---------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
47. To test the application, on the main menu, click Run Run.
Chapter 11:
Progress Controls
The most important property of the UpDown property is the Associate property. It is
used to specify the control that would display the incrementing value of the control. To
associate a text control to the UpDown control, click the Associate field to display its
combo box. Click the arrow and select the desired control. You can also associate a
control programmatically using code such as:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
UpDown1->Associate = Edit1;
}
//---------------------------------------------------------------------------
The values that display in the associated edit box are short integer numbers. These
numbers range from a minimum controlled by the Min property to a maximum value
controlled by the Max property. By default, a freshly added UpDown control on a from
has its Min and Max set to 0 and 100 respectively. In reality, you can set the minimum
value of the control to –32768 and the maximum to 32767. These values are set using the
Min and Max fields of the Object Inspector. You can change these values
programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
UpDown1->Associate = Edit1;
UpDown1->Min = -224;
UpDown1->Max = -1;
}
//---------------------------------------------------------------------------
If you use numbers in the thousands, the edit control will display the values using the
comma to separate the thousands. This is because the UpDown control is configured, by
default to separate the thousands. You do not want this feature, change the value of the
Thousands property from true to false.
When using the spin button, the user clicks one of the arrows of the control to increase or
decrease the value. By default, the value increases or decreases by 1. If you want the
value to augment by more than 1, set an integer value using the Increment property. To
set the Increment value programmatically, you can use code as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
UpDown1->Associate = Edit1;
UpDown1->Max = 125;
UpDown1->Min = 10;
UpDown1->Increment = 5;
}
//---------------------------------------------------------------------------
When an UpDown control is accessed, the value it displays is usually set by its Position.
You can use this property to set which value the edit control would display when the
control comes up. It should be an integer between the Min and the Max. You can also set
it programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
UpDown1->Associate = Edit1;
UpDown1->Max = 125;
UpDown1->Min = 10;
UpDown1->Increment = 5;
UpDown1->Position = 55;
}
//---------------------------------------------------------------------------
The Position property also allows you to find out the value of the UpDown control at any
time. After setting the Increment value, when the user clicks the arrow buttons, the value
would increase accordingly. When the maximum value is reached, the control would use
the Wrap property to find out what to do. If the Wrap Boolean property is set to false
(the default, the increment would stop at the Max value even if the Max valus is not
divisible by the Increment. The same goes for the Min value. If the Wrap property is set
to true and if the user increases the value of the control, the incrementing would stop to
the last value divisible by the Increment but less than the Max; the same would apply
when decrementing the value of the control.
The UpDown control appears with two arrows pointing up and down, respectively. This
feature is control by the Orientation. An alternative is to point the arrows to left and
right. To do this, use the Orientation property to set arrow to your liking.
The UpDown control usually has its associated edit box on the left side. This is
controlled by the AlignButton property. Alternatively, you can ask it to have the Edit
control on is right side by setting the AlignButton property to udRight. At design time,
both controls still display as they are designed. If you change the AlignButton value, the
control would apply the value only at runtime.
One of the nicest features that make the spin button easy to use is that the user can change
its values by pressing the up and down arro key of the keyboard. This ability is by default
set to true from the Boolean ArrowKeys property. If you want to prevent the user from
using the keyboard to increase or decrease the value of the UpDown control, set the
ArrowKeys property to false.
5. On the Win32 tab, click the UpDown control and click on the right side of
the edit box on the form:
6. On the Object Inspector, make sure the AlignButton field displays udRight.
7. Click Associate and type e
8. Notice that the edtSpin name is selected.
9. Make sure the Increment field display 1, the Max field displays 100 and the Min
field displays 0.
10. To test the new control, press F9.
11. On the form, click the up pointing arrow; then click the down pointing arrow,
using the mouse.
12. Press the up and down arrow keys of the keyboard to change the values of the
spin button.
13. After playing with the spin button, close the form.
If cannot design a spin button, you can programmatically create one in a function or
event. To do this, declare an instance of a TUpDown object. You need to specify the
control that owns the spin button. This is usually a form but could also be any control
container. You will also have to specify the parent of this control. You can create it as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TUpDown *Counter = new TUpDown(this);
Counter->Parent = this;
}
//---------------------------------------------------------------------------
Unfortunately, an UpDown control standing alone means nothing; you will need a control
to associate it with. If you already have an Edit control, you can use it. Otherwise, you
may create one dynamically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TUpDown *Counter = new TUpDown(this);
Counter->Parent = this;
TEdit *Displayer = new TEdit(this);
Displayer->Parent = this;
}
//---------------------------------------------------------------------------
Equipped with these controls, you can set their positions and configure their properties. When setting their
dimensions and positions, set the edit box’ width according to the range of values you are planning to
display. If you plan to position the UpDown control to the right side of the edit box, set the UpDown Left
to the left alignment + width of the edit box. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
TUpDown *Counter = new TUpDown(this);
Counter->Parent = this;
TEdit *Displayer = new TEdit(this);
Displayer->Parent = this;
Displayer->Left = 16;
Displayer->Top = 16;
Displayer->Width = 32;
Counter->Left = Displayer->Left + Displayer->Width;
Counter->Top = Displayer->Top;
Counter->Min = 12;
Counter->Max = 248;
Counter->Increment = 2;
Counter->Position = 36;
Counter->Associate = Displayer;
}
//---------------------------------------------------------------------------
If you are planning to access the UpDown control from more than one event or function, create it globally
using the form’s header file.
arrows are represented using the TUDBtnType enumerator that has two values. The up
or right pointing arrow is recognized as btNext while the down or left pointing arrow is
referred to as btPrev. When the user clicks one of the arrows, you can write code to
perform an action depending on the button that was clicked. Using this OnClick event,
you do not have to associate the UpDown control with anedit box to display integers; you
can use the event to format the value or configure any other behavior you see fit. For
example, instead of displaying an integer, you can display a floating number, a string,
anything, that is tradionationally not allowed.
The arrows of the UpDown controlled are configured so that when the user clicks a
pointing arrow, the UpDown control fires the OnMouseDown event; the OnMouseUp
event is fired when the user releases the mouse.
When the user clicks one of the arrows of the UpDown control, the operating system is
notified just before this action occurs. This notification is done through the OnChanging
event. This allows you to perform a last minute configuration before the value or position
of the control changes. You can also use this event to deny changing the value of the
control.
The OnChangingEx event also fires just before the value of the UpDown control
changes. This time, you can set a new value for the control if the change is successful.
It is important that you always make sure that the user can use the up and down arrow
keys of the keyboard to increase or decrease the value of the Updown control. If he user
presses and holds the up array key, the UpDown control wold be incrementing its value
until either the user releases the key or the control reaches its maximum limit. Here is an
example of how to track the OnMouseUp keyboard event of the UpDown control:
21. The radio buttons are named rdo87, rdo89, and rdo92. Their corresponding Edit
controls are named edt87, edt89, and edt92 respectively. The button is named
btnClose and the UpDown button is named udnGallons. Make sure you add the
bevels. The Edit controls inside the right bevel are named edtUnitPrice,
edtGallons, and edtTotal
22. On the form, double-click the Close button and implement its OnClick event as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
23. Right-click in the Code Editor window and click Open Source/Header File. In
the private section of the Main.cpp file, declare a double variable named
UnitPrice:
private:
double UnitPrice; // User declarations
24. Display the form. Double-click the 87 radio button to access its OnClick event.
Double-click the other radio buttons. Implement the OnClick events as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::rdo87Click(TObject *Sender)
{
UnitPrice = edtPrice87->Text.ToDouble();
edtUnitPrice->Text = FloatToStr(UnitPrice);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::rdo89Click(TObject *Sender)
{
UnitPrice = edtPrice89->Text.ToDouble();
edtUnitPrice->Text = FloatToStr(UnitPrice);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::rdo92Click(TObject *Sender)
{
UnitPrice = edtPrice92->Text.ToDouble();
edtUnitPrice->Text = FloatToStr(UnitPrice);
}
//---------------------------------------------------------------------------
25. Run the program to test it. Make sure that when you click a radio button, its
price in the corresponding edit box is transferred to the Unit Price edit box.
Change the prices of each category and make sure the changed price display in
the Unit Price edit box when you click the radio buttons again. Close the form to
return to Bcb.
26. To save the project, on the main menu, click File Save All
27. On the form, click the UpDown to select it. On the Object Inspector, click the
Events tab.
28. Double-click the empty field on the right isde of OnClick and implement it as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::udnGallonsClick(TObject *Sender, TUDBtnType Button)
{
Double Total;
static int Gallons;
UnitPrice = edtUnitPrice->Text.ToDouble();
if( Button == btNext )
{
edtGallons->Text = Gallons++;
Total = (Gallons * UnitPrice) - UnitPrice;
edtTotal->Text = edtTotal->Text.sprintf("$ %.2f", Total);
}
else
{
edtGallons->Text = 0;
edtTotal->Text = "$ 0.00";
Gallons = 0;
}
}
//---------------------------------------------------------------------------
29. Save the project. Test it. Close it.
Two of the properties that differentiate the UpDown from the CSpinButton controls is
that the the CSpinButton allows you to add your own button indicators as bitmaps. To
specify which bitmap must point up on the control, click the ellipsis button on the
UpGlyph field of the Object Inspector. You can also specify a bitmap that would point
down using the DownGlyph property:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCSpinButton *LetMe = new TCSpinButton(Form1);
LetMe->Parent = Form1;
}
//---------------------------------------------------------------------------
private:
int Value; // User declarations
6. In the form’s constructor, intialize the value to 0:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Value = 0;
}
//---------------------------------------------------------------------------
7. On the form, click the SpinButton control to select it. On the Object Inspector,
click the Events tab.
8. Double-click the empty field on the right side of OnUpClick and implement the
event as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::CSpinButton1UpClick(TObject *Sender)
{
Edit1->Text = Value++;
}
//---------------------------------------------------------------------------
9. On the Object Inspector, double-click the field of the OnDownClick event and
implement it as follows:
//---------------------------------------------------------------------------
Without a doubt, the SpinEdit control is the easiest spin control of the three sets of
updown controls. There is hardly any configuration to do.
To add a SpinEdit to your application, from the Samples tab of the Component Palette,
click the CSpinEdit button and click in the desired location on the form.
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
CSpinEdit1->MinValue = -12;
CSpinEdit1->MaxValue = 228;
}
//---------------------------------------------------------------------------
By default, the values of a SpinEdit control increase by 1 and decrease by –1. If that
value is not appropriate for your application, you can change it using the Increment
property in the Object inspector.
When a SpinEdit control appears at startup, the control displays the value 0 even if its
MinValue is set to a value other than 0. To set the default position of the SpinEdit
control, use the Value property. You can control it at desing time or at runtime. If you set
the Value property to a value that is less than the MinValue, the value would be
automatically set to the minimum value. If you try to set it to a value greater than the
MaxValue in the Object Inspector, the Value would be reset to the MaxValue.
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCSpinEdit* Staple = new TCSpinEdit(this);
Staple->Parent = this;
}
//---------------------------------------------------------------------------
You must include the CSPIN.h header file to the form or unit that would be using the Spin Edit control
6. On follows:
To add a trackbar to a form, from Win32 tab of the Component Palette, double-click the
TrackBar button.
Trackbar Properties
The properties of a trackbar control how it displays and behaves. After placing a
TrackBar control on a form of other container, by default, its assumes a horizontal
direction. The direction of the trackbar is controlled by the TTrackBarOrientation
enumerator:
To change the direction of the control, on the Object Inspector, set the Orientation
property to the desired value. For example, to make it vertical, change the field from
trHorizontal to trVertical. To change this property at runtime, assign the desired value
to the property. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TrackBar1->Orientation = trVertical;
}
//---------------------------------------------------------------------------
The Min property controls the minimum positional value of the control while the Max
value controls the opposite. The user is allowed to slide only between these two values.
These two properties are set in Object Inspector using their respective fields. By default,
the minimum value is set to 0 and the maximum is 10. As integers, the lowest minimum
allowed is INT_MIN which is –2147483647. The maximum allowed value is INT_MAX
which is 2147483647. To change the minimum or maximum values programmatically,
assign the desired value to the appropriate proprety. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TrackBar1->Min = -1205;
TrackBar1->Max = -540;
}
//---------------------------------------------------------------------------
Always make sure that the minimum value is lower than the maximum. This safe
measure will allow you to better control the current value of the control. At designtime, if
you try inversing the values, C++ Builder would reset them. For example, if the Min field
is 12 and you try setting it to 48 when the Max field is 25, the Min field would be reset to
its original value 12. At runtime, if you try setting wrong values as follows,
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TrackBar1->Min = 55;
TrackBar1->Max = 12;
}
//---------------------------------------------------------------------------
The minimum would be set the previous minimum value the property had and the new
maximum value would be kept. If you do not know for sure which value would be greater
due to an intermediary action of the user, you can write a conditional statement that
would control the minimum and the maximum values.
When using the trackbar, the user can slide the thumb in the desired direction, thus
changing the value of the control. While it is moving, you can control the incrementing of
the thumb. By default, the thumb advances or regresses by 1 unit each time it is slided.
This unit is controlled by the Frequence property.
The thumb’s visual display appears as a small standing pentagon with two straight
borders. Its size is set using the ThumbLength property; the smaller the value, the
narrower the thumb. This ability is controlled by the ThumbLength property. The visual
apperance of the thumb is controlled by the SliderVisible property whose Boolean value
is by default set to true. Therefore, if you wish to hide the thumb, set its SliderVisible
property to false.
A trackbar is also equipped with small bars “|” that serve as indicators of the position
occupied by the slider. These bars are called ticks. By default, the tick marks are
positioned on the same side the slider is pointing. This conditional position of the ticks is
controlled by the value of TickMarks property set from the TTickMark enumerator:
By default, when you add a new TrackBar control to a form, it is horizontally oriented,
the slider points down, the tick marks are positioned under the sliding field. In this
setting, the TickMarks property is set to tmBottomRight. To place the tick marks above
the sliding field, change the value of the TickMarks property to tmTopLeft; this also
has the effect of reversing the direction of the slider. As a third option, you can have the
tick marks on both sides of the slider. To get this, set the TickMarks property to tmBoth.
With this value, the thumb becomes a small rectangle (changing from its pentagon
shape).
The sliding field of a trackbar is a rectangle with a with background. It stayed white even
as the user slides the thumb to change the control’s value.cause their
1. From the Win32 tab, click the TrackBar control and click on the form
under the existing control. That’s all it takes.
2. On the Object Inspector, change the Cursor field to crHandPoint.
3. Click Frequency and type 2
4. Click Max and type 20
5. Change the TickMarks to tmTopLeft
6. To test the program, press F9.
7. Slide the pointer of the track bar to the right and left, using the mouse.
8. While the trackbar has focus, use the left and right arrow keys on the keyboard
to change its positions.
9. Close the form
1. From the Standard tab of the component palette, add a label to the form and
under the track bar control.
2. On the form, double-click the TrackBar to access its OnChange event.
3. Implement it as follows:
The Progress Bar is created using the ProgressBar control from the Win32 tab.
7. On the form, double-click the spin button to access its OnClick event.
8. Implement it as follows:
11.6 ScrollBars
A scrollbar is a control that allows the user to navigate a document in two directions
along a control by clicking the mouse on the appropriate arrow. This control can assume
only one of two directions: horizontal or vertical. For its functionality, a scroll bar is
made of three parts:
1. a button arrow of each side of the control: Up or Down .
2. a horizontal or vertical bar
3. a scrolling region
To use a scrollbar control in your application, on the Standard tab of the Component
Palette, click the ScrollBar button and click on the form, then configure its properties.
To set this property programmatically, assign the desired value to this property. Here is
an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollBar1->Kind = sbVertical;
}
//---------------------------------------------------------------------------
When using a scroll bar, the user can navigate from one end of the control to the other
end. These are the control’s minimum and maximum values. For a horizontal scrollbar,
the minimum is the far left position that the bar can assume; for a vertical scrollbar, this
Note would be most bottom position. The maximum would be the opposite. These two values
The Min value must are controlled by the Min and Max properties. By default, a newly added scrollbar allows
always by less than the scrolling from 0 to 100. To change these values at design time, type an integer number
Max value. for each field in the Object Inspector. The lowest number the Min property can have is –
2147483648 and the highest number for Max would be 2147483647. To change any of
these properties programmatically, you can use code such as:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollBar1->Kind = sbVertical;
ScrollBar1->Min = -122;
ScrollBar1->Max = 240;
}
//---------------------------------------------------------------------------
The primary technique the user applies to a scrollbar is to click one of the arrows at the
ends of the control. As the bar slides insides of the control, it assumes an integer position
from Min to Max. At design time, you can use the Position property to set the position
that the scrollbar would assume when the form opens. If you set the Position to a value
less than the Min, the Object Inspector would restore it to the Min. If you set a Position
greater than the Max, the Object Insopector would assign it the Max value. To
programmatically set the position of the bar, assign the desired value, which must be
between Min and Max, to the Position property. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollBar1->Kind = sbVertical;
ScrollBar1->Min = -122;
ScrollBar1->Max = 240;
ScrollBar1->Position = 38;
}
//---------------------------------------------------------------------------
When the user clicks an arrow of a scrollbar, the bar slides one unit. This unit is called
SmallChange and is set to 1 by default. If you want the bar to slide more than one unit,
change the SmallChange property to an integer value between Min and Max. The bigger
the value, the faster the sliding would occur because the bar would jump by
SmallChange units. You can also set this value programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollBar1->Kind = sbVertical;
ScrollBar1->Min = -122;
ScrollBar1->Max = 240;
ScrollBar1->Position = 38;
ScrollBar1->SmallChange = 4;
}
//---------------------------------------------------------------------------
There are two main ways the user can scroll faster using scrollbars: by pressing either
page buttons or by clicking the scrolling region. The amount covered using this technique
is controlled by the LargeChange property. Once again, the user can scroll only between
Min and Max; this means you can set this value only to an integer from Min to Max. To
find the scrolling amount, the compiler would divide the actual scrolling range (the
difference between the Max and Min) by the LargeChange value. When the user clicks
in the scrolling region or presses the Page Up or Page Down keys, the bar would jump by
LargeChange up to the scrolling amount value. You can change the LargeChange
property programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollBar1->Kind = sbVertical;
ScrollBar1->Min = -122;
ScrollBar1->Max = 240;
ScrollBar1->Position = 38;
ScrollBar1->SmallChange = 4;
ScrollBar1->LargeChange = 20;
}
//---------------------------------------------------------------------------
The bar inside the scroll region has a size relative to the Min and Max value. By default,
it is square of the approximate size of the arrow buttons. This size of the bar is controlled
by the PageSize property. Approximately, this represents the percentage of the scrolling
range (the difference between the Max and Min). You can change this value at design
time in the Object Inspector, by an integer value between Min and Max. To change it
programmatically, assign the desired integer to the PageSize property. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ScrollBar1->Kind = sbVertical;
ScrollBar1->Min = -122;
ScrollBar1->Max = 240;
ScrollBar1->Position = 38;
ScrollBar1->SmallChange = 4;
ScrollBar1->LargeChange = 20;
ScrollBar1->PageSize = 85;
ScrollBar1->PageSize = 75;
}
//---------------------------------------------------------------------------
2. To add a scroll bar, on the Standard tab of the Component Palette, click the
ScrollBar control .
3. Click on the form.
4. Move the scroll bar to the top left section of the form.
5. While the scrollbar is still selected, on the Object Inspector, click the Max field
and type 150
6. To add another scrollbar, on the Component Palette, double-click the ScrollBar
control
7. While the second scroll bar is still selected, on the Object Inspector, click the
Kind field.
8. Click the arrow of the Kind field and selected sbVertical
9. Move the second scroll bar to the middle section of the form
10. Click the Max field and type 180
11. Click the Min field and type 20
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TScrollBar * Scroller = new TScrollBar(Form1);
Scroller->Parent = Form1;
}
//---------------------------------------------------------------------------
After declaring the variable, you can set its properties as desired. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TScrollBar * Scroller = new TScrollBar(Form1);
Scroller->Parent = Form1;
Scroller->Left = 24;
Scroller->Width = 228;
Scroller->Top = 35;
Scroller->Kind = sbVertical;
Scroller->Max = 1500;
Scroller->Position = 780;
Scroller->SmallChange = 5;
Scroller->LargeChange = 150;
Scroller->PageSize = 250;
}
//---------------------------------------------------------------------------
Another method of a the TScrollBar class is the SetParams(). It allows you to set the
Position, Min, and Max values using one function. Here is an example of using it;
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TScrollBar * Scroller = new TScrollBar(Form1);
Scroller->Parent = Form1;
Scroller->Left = 24;
Scroller->Width = 228;
Scroller->Top = 35;
Scroller->Kind = sbVertical;
// Scroller->Max = 1500;
// Scroller->Position = 780;
Scroller->SmallChange = 5;
Scroller->LargeChange = 150;
Scroller->PageSize = 250;
Scroller->SetParams(780, 0, 1500);
}
//---------------------------------------------------------------------------
Every time the user performs one of these actions, the position of the bar changes unless
it is already at one of the extremes. When the position of the bar has changed, a message
is sent to the operating system that the bar has changed its position. Using the OnChange
event of the scrollbar, you can tell the compiler what to do. Fundamentally you can find
out the new position and display it on a label. Here is an example:
The OnScroll event occurs when the user scrolls the bar. This event is appropriate if or
when you want to capture the specific action that caused the scrolling action. These
actions relate to the TScrollCode enumerator:
We will create a small application simply used to change the background color of a form.
There are three entities in this application that need to be synchronized as closely as
possible. When the form starts, we have made sure that the positions of the scroll bars,
the values in the edit boxes and the color of the Preview panel are synchronized. When
the user scrolls any of the scrollbars, we will change the color of the Preview panel and
allow the corresponding edit box to keep with the position of the its scrollbar. When the
user changes the value in an edit box, we will update the position of the corresponding
scrollbar and change the color of the Preview panel.
Chapter 12:
Selection Controls
12.1.1 Descriptions
Radio Buttons
Check Boxes
List Boxes
The GroupBox is the most universally known control as a group holder. It can “carry” or
hold any of the other controls.
The RadioGroup is more appropriate for a group of radio buttons because it is already
equipped to treat those radio buttons as one control holding only one name.
The panel control provides a very efficient means of holding other controls.
you add the radio buttons on this type of container, by default, they will be treated as a
group. You should refrain from positioning radio buttons on the form.
At design time, to create a group of radio buttons, first position a container on the form;
this could be a RadioGroup control. There are two main ways you can create a group of
radio buttons. If you are using a RadioGroup as the container, this control considers its
“children”, the radio buttons it hosts, as a list of strings. Therefore, you can type the label
of each radio button in the String List Editor. The radio buttons created as a list of
strings are not controls to their full extent, althouth this technique provides the fastest and
a very efficient method of creating a group of radio buttons. If you want each radio
button to behave like a full control, first position a GroupBox (the better choice) or a
panel controls on the form. To add each radio button, from the Standard tab of the
Component Palette, click the RadioButton anc click inside of the container.
Two properties are of particular importance to both you and the user: the label and the
state of the control. The label is text that specifies what a particular radio button is used
for. If you decide to use a RadioGroup control, after placing it on the form, on the Object
Inspector, click the Items field to reveal its ellipsis button . Click the ellipsis button to
call the String List Editor. To create each radio button, type a label and press Enter for
each
After creating the list, click OK. The container will take care of positioning the radio
buttons so they can fit inside the host. If you type too many or too long strings for the
host, resize the container. If you have a RadioGroup control on the form but could not or
forgot to create a list of radio buttons, you can do so programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
grpEmplStatus->Items->Add("Part-Time");
grpEmplStatus->Items->Add("Full-Time");
grpEmplStatus->Items->Add("Contractor");
grpEmplStatus->Items->Add("Consultant");
}
//---------------------------------------------------------------------------
If you are using a GroupBox or a panel controls to host the radio buttons, after adding it
to the form, on the Component Palette, click the RadioButton and click in the host. To
set the label of a radio button, on the Object Inspector, click Caption and type the desired
label. Repeat this for each radio button. If you want to change a radio button’s caption at
runtime, you can do so programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
rdoGender1->Caption = "&Man";
}
//---------------------------------------------------------------------------
The second of the most important properties of a radio button is its state: whether it is
selected or not. When the user clicks a radio button, it becomes exclusively selected. This
is seen by the dot inside its rounded box. When a radio button is selected, it is said to be
checked. By default, a newly created radio button is not checked. At design time, if you
created the radio buttons using a RadioGroup control, you can set which radio button is
selected by changing the integer value of the ItemIndex property. Since no radio button
is selected by default, its value is –1. The items in the string are counted starting at 0,
then 1, and so on. For example, to set the second radio button as checked, set the
ItemIndex property of the RadioGroup control as 1. This property can be changed only
after the list is created. Therefore, if you create the list programmatically, you can also
decide which radio button would be selected when the list shows up:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
grpEmplStatus->Items->Add("Part-Time");
grpEmplStatus->Items->Add("Full-Time");
grpEmplStatus->Items->Add("Contractor");
grpEmplStatus->Items->Add("Consultant");
grpEmplStatus->ItemIndex = 2;
}
//---------------------------------------------------------------------------
If you create the radio buttons using a GroupBox or a panel controls, you can set a radio
button using the Checked property. This same property allows you to decide which
button would be selected when the form opens. As a Boolean property, to set the
Checked state of a radio button, set this value to true. At runtime, to set a particular radio
button as checked, assign a true value to its name:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
rdoGender2->Checked = True;
}
//---------------------------------------------------------------------------
Once one button has been checked in a group, even if there was no selection in the
beginning, one radio button is always selected in the group. The user cannot deselect all
radio buttons. Only the developper can do this at runtime. By setting the Checked
property of a radio button to false, you can remove its selection.
In the same way you can deselect all radio buttons. If the radio buttons were created
using a RadioGroup control, assign a –1 value to its ItemIndex proerty:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
rdoGender2->Checked = False;
}
//---------------------------------------------------------------------------
Otherwise, you can assign a false value to the Checked property of each radio button.
When dessigning your radio buttons, to manage the space, you can distribute them on
more than one column. If the radio buttons were created using a RadioGroup control, on
the Object Inspector, change the (interger) value of the Columns property. You can also
do this at runtime:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
grpEmplStatus->Items->Add("Part-Time");
grpEmplStatus->Items->Add("Full-Time");
grpEmplStatus->Items->Add("Contractor");
grpEmplStatus->Items->Add("Consultant");
grpEmplStatus->ItemIndex = 2;
grpEmplStatus->Columns = 2;
}
//---------------------------------------------------------------------------
If you want to use various columns on a group of radio buttons created using a
GroupBox or a panel controls, you can visually position each radio button on the
container. Programmatically, you can also change the Left, and Top values of each
control as desired.
By default, a radio button is configured so that the label would be positioned on the right
side of the rounded box. This is controlled by the Alignment property. If you want the
label of the left side, set the radio button’s Alignment property according. The values are:
taRightJustify and taLeftJustify.
6. Type &Large
7. Click OK
8. Notice that a list of radio has been created.
9. On the Component Palette, click the Edit control and click on the form
10. Change the name of the Edit box to edtPizzaSize
11. Click and drag the Pizza Sizes to the top left section of the form.
12. Notice its dependent items move also.
13. Move the Pizza Price group. Notice that its children controls move also.
14. To save the project and create another, on the main menu, click File New…
15. On the New Items dialog, make sure Application is selected and click OK.
16. When asked to save your project, click Yes.
17. Locate the folder where the exercises are installed.
18. Click the Create New Folder button, type Exo Pizza1 and press Enter twice.
19. After making sure that the Exo Pizza1 folder displays in the Save In combo box,
click Save twice.
20. Start a new project with the default form.
21. Once Bcb is opened with a new form, on the Component Palette, click the Panel
control.
22. On the form, click and drag from the top left section to the middle center
section.
23. Click Caption and press Delete to delete the caption of the panel.
24. On the Component Palette, double-click the RadioButton control
25. Click Caption and type &Addition
26. Click Name and type rdoAddition
27. Move the new radio button to the top section of and inside the panel.
34. Add another panel with four labels captioned Number &1:, Number &2:, and
Result:
35. Add three Edit controls inside the panel and on the right side of the
corresponding labels. These edit boxes will be named edtNumber1,
edtNumber2, and edtResult
The fastest and most convenient way to dynamically create a group of radio buttons
consists of using a RadioGroup control. If you don’t have this control already, either by
adding it at design time or by creating anyhow, you can use the new operator to assign an
instance of the TRadioGroup to the owner of this control. The compiler needs to know
the owner that would have the responsibility of cleaning the RadioGroup once it is not
needed anymore. This time, the owner should be the form, unless the RadioGroup control
will be hosted by another container. Also, specify the parent of the control. If you will
need the radio buttons in just one function or event, you can create the RadioGroup
control in that function. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateGroupClick(TObject *Sender)
{
TRadioGroup* Group = new TRadioGroup(Form1);
Group->Parent = Form1;
}
//---------------------------------------------------------------------------
If you are planning to use the control in more than one location, declare a TRadioGroup
object in the private or public sections of the form or unit that would use it:
To create the list that represents the radio buttons, use the TStrings::Items property of the
RadioGroup control. You can do this in the function where you create the control locally:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateGroupClick(TObject *Sender)
{
TRadioGroup* Group = new TRadioGroup(Form1);
Group->Parent = Form1;
Group->Caption = "Membership";
Group->Items->Add("Senior");
Group->Items->Add("Adult");
Group->Items->Add("Tean");
Group->Items->Add("Child");
Group->Columns = 2;
Group->Left = 8;
Group->Top = 20;
}
//---------------------------------------------------------------------------
If the RadioGroup was created globally, use the appropriate function or event to initialize
it:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
grpMaritalStatus = new TRadioGroup(Form1);
grpMaritalStatus->Parent = Form1;
grpMaritalStatus->Items->Add("Single");
grpMaritalStatus->Items->Add("Married");
grpMaritalStatus->Items->Add("Divorced");
grpMaritalStatus->Items->Add("Widow");
grpMaritalStatus->Left = 220;
grpMaritalStatus->Top = 20;
grpMaritalStatus->Height = 100;
grpMaritalStatus->Width = 124;
grpMaritalStatus->Caption = "Marital Status";
}
//---------------------------------------------------------------------------
If you want to create each button as its own object, you will once have to have a
container, designed or dynamically created. The bad news is that you will have to create
each button individually.
On the other hand, after creating each radio button as a control, you can use its OnClick
event to configure its functionality.
else
edtPizzaPrice->Text = "$14.55";
}
3. To test the form, press F9.
4. Click different radio buttons and observe as the value in the edit box changes.
5. Close the form to return to Bcb.
6. To save the project, on the Standard toolbar, click Save All
7. Open the project of the Exo Pizza program.
8. If the form does not display, press F12.
Double-click the Addition radio button to access its OnClick event.
9. Implement it as follows:
17. In the same way, access the OnClick event for the rdoDivision control and
implement it as follows:
ListView
42. RadioGroup control . Operations then save Unit1 and the project in it.
A check box is a Windows control that allows the user to set or change the value of an
item as true or false. Although it can appear by itself, a check box usually comes in a
group with others, allowing the user to select as many choices as are available.
Depending on the application, a little square appears with a check box and a label.
The user makes his or her selection by clicking in the square which toggles a check mark
. Toggling means that if the square were empty , after clicking it, a check mark
would appear in it ; otherwise, the check mark would be removed. Some environments
offer a different kind of check mark: .
From the user’s standpoint, a check box is selected when its check mark is set; and the
item is not selected when its square is empty.
From the developer standpoint, a check mark has two (Boolean) values: true or false (or
TRUE or FALSE, or True or False). When a check mark is selected, its value is true;
otherwise, its value is false.
A check mark is a special button and can be programmed as a regular button. Therefore,
depending on the application’s needs, you can display or hide it, enable or disable it as
necessary; you can adjust the control’s behavior depending on other controls on the same
form, the same application, or external factors.
Check boxes provide “non-exclusive” choice, which means each check box can behave
as independent as needed with regard to the other check boxes of the same group.
Therefore, although not recommended, you can create check boxes anywhere on the
form. It is recommended that you include them in rectangular container so their
belonging to the same group will be obvious to the user. The group can be hosted by a
GroupdBox (recommended) or a Panel controls. You can also design the group in a Bevel
control but, since the bevel is not a container, you will not be able to perform some of
moving and toggling operations you get with the first suggested controls.
The most obvious property of the check box is its state as being checked or not. By
default, a check box is not checked (it is empty). At design time, you can make sure that a
check box appears checked or not by changing the Boolean value of the Checked
property in the Object Inspector. When you set this property, it would be updated
automatically on the form. You or the user can also control this property at runtime. To
change the Checked property programmatically, you could write:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
CheckBox1->Checked = True;
}
//---------------------------------------------------------------------------
When a check box is clicked, its Checked property has a value of true; otherwise, the
values is false. Since the Checked property is a Boolean value, you can toggle its state
based on an intermediary action from the program, the user, or the computer:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
CheckBox1->Checked = !CheckBox1->Checked;
}
//---------------------------------------------------------------------------
Probably the most important property of a check box is its caption, which is controlled by
the Caption property. This can easily be set at design or runtime. The position of the
caption is controlled by the Alignment property. By default, the check box caption is
aligned to the right side of the check box:
To change the caption alignment of a check box, use the Alignment property of the
Object Inspector. The values are taRightJustify for the right alignment and the
taLeftJustify.
Fundamentally, a check box can have only one of two states: checked or unchecked.
When a check box’ checked property is dependent of other controls or actions,
sometimes, you cannot categorically set it to Checked or not Checked. Imagine that, in a
certain company, for an employee to qualify for stock options, he or she must be have a
full-time status and must have been in the company for at least two years. If an
(important) employee fulfills one of these requirements bu not the other requirements,
you can gray out the Stock Options check box. since the control would not be completely
checked, you can show it as half checked:
This property is set using the AllowGrayed property. In the Object Inspector, change the
(Boolean) of the desired check box to true or false (the default). Programmatically, to set
this property, assign it a true value (because otherwise the false value is set by default).
At design time or when the user is interacting with your application, you can control the
display of a check box using one of three states. Unlike being checked or unchecked, like
the AllowGrayed property, you can set an intermediary that would help you and user
know that the control’s condition cannot be definitely decided. This is set using the State
property. This property, derived from the TCheckBoxState enumrator, allows you to set
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCheckBox* Checker = new TCheckBox(Form1);
Checker->Parent = Form1;
}
//---------------------------------------------------------------------------
If the check box will be hosted by a container other than the form, specify this as the parent:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TCheckBox* Checker = new TCheckBox(Form1);
Checker->Parent = GroupBox1;
}
//---------------------------------------------------------------------------
If you do not have or cannot get a container at designe time, you can also dynamically create one that
would host the dynamic check boxes. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TGroupBox* Group = new TGroupBox(Form1);
Group->Parent = Form1;
Group->Left = 16;
Group->Top = 32;
Group->Caption = "Preferred Sports";
To create this control globally, that is, to make it accessible by more than one function, method or event,
declare it in the private or public sections of the header file of the unit or object (control) that would “own”
it. We have seen various examples of doing this already.
4. To save the project, on the Standard toolbar, click the Save All button.
5. Double-click the Close button and implement its OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TPizza::btnCloseClick(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
6. We are going to write a function that will serve as the central point of the many
calculations involved. This function will take care of calculating the total and
displaying it in the Total edit box.
In the Class Explorer, if necessary, expand the Pizza – Classes
7. Right-click Tpizza and click New Method…
8. Set the name of the function as ShowTotal
10. Click OK
11. When designing the form, we placed an edit box on the right side of a radio
control. The radio control specifies the pizza that the customer wants. The edit
box shows the price based on the selected size. To start, when the user clicks a
radio button, we will convert the content of its equivalent edit box to a float to
validate the price.
Start implementing the ShowTotal() function as follows:
//---------------------------------------------------------------------------
void __fastcall TPizza::ShowTotal()
{
double PriceSize, TotalOrder;
if(rdoSmall->Checked == True)
PriceSize = StrToFloat(edtSmall->Text);
else if(rdoMedium->Checked == True)
PriceSize = StrToFloat(edtMedium->Text);
else if(rdoLarge->Checked == True)
PriceSize = StrToFloat(edtLarge->Text);
TotalOrder = PriceSize;
edtTotalOrder->Text = edtTotalOrder->Text.sprintf("%.2f",
TotalOrder);
}
//---------------------------------------------------------------------------
12. A radio button is like a regular button. It has an OnClick event that it inherits
from the TControl parent. Whenever the user clicks a certain radio button, we
need to let the ShowTotal() function know that a button has been clicked. This
allows the ShowTotal() function to recalculate the totalorder, thereby adding the
new price and subtracting the old one.
Display the form. Double click each radio button and implement each OnClick
event as follows:
//---------------------------------------------------------------------------
void __fastcall TPizza::rdoSmallClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::rdoMediumClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::rdoLargeClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
13. To test the program, on the main menu, click Run Run.
14. Test the functionality of the buttons (do not test the other controls). After
making sure that the right price displays in the Total edit box, click the Close
button to return to Bcb.
15. Save the project.
16. When the user clicks one of the check box, we need to get the price of the
corresponding topping, add it to the current total, and display the new total to the
Total edit box. If the user unchecks a check box, we should subtract its value
from the total automatically. Therefore, change the ShowTotal function as
follows:
//---------------------------------------------------------------------------
void __fastcall TPizza::ShowTotal()
{
double PriceSize, Pepperoni, Sausage,
ExtraCheese, Onions, Olives, TotalOrder;
if(rdoSmall->Checked == True)
PriceSize = StrToFloat(edtSmall->Text);
else if(rdoMedium->Checked == True)
PriceSize = StrToFloat(edtMedium->Text);
else if(rdoLarge->Checked == True)
PriceSize = StrToFloat(edtLarge->Text);
if(chkPepperoni->Checked == True)
Pepperoni = StrToFloat(edtPepperoni->Text);
else
Pepperoni = 0;
if(chkSausage->Checked == True)
Sausage = StrToFloat(edtSausage->Text);
else
Sausage = 0;
if(chkExtraCheese->Checked == True)
ExtraCheese = StrToFloat(edtExtraCheese->Text);
else
ExtraCheese = 0;
if(chkOnions->Checked == True)
Onions = StrToFloat(edtOnions->Text);
else
Onions = 0;
if(chkOlives->Checked == True)
Olives = StrToFloat(edtOlives->Text);
else
Olives = 0;
TotalOrder = PriceSize
+ Pepperoni + Sausage + ExtraCheese + Onions + Olives;
//---------------------------------------------------------------------------
void __fastcall TPizza::chkPepperoniClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::chkSausageClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::chkExtraCheeseClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::chkOnionsClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::chkOlivesClick(TObject *Sender)
{
ShowTotal();
}
//---------------------------------------------------------------------------
18. To test the program, run it. Test the check boxes and combine their selection
with the radio buttons to make sure that the order processing works.
19. Close the dialog box to return to Bcb.
20. Save the project.
21. To perform the total order, the compiler will retrieve the content of the total of
each item, because a customer can order more than one unit of an item; for
example the customer could want more than one piece of bread or many bottles
of root beer. The compiler will need only the total price of each unit.
Change the ShowTotal() function as follows:
//---------------------------------------------------------------------------
void __fastcall TPizza::ShowTotal()
{
double PriceSize, Pepperoni, Sausage,
ExtraCheese, Onions, Olives, BWings, Bread,
Pepsi, DietPepsi, Sprite, OJ, RootBeer, TotalOrder;
if(rdoSmall->Checked == True)
PriceSize = StrToFloat(edtSmall->Text);
else if(rdoMedium->Checked == True)
PriceSize = StrToFloat(edtMedium->Text);
else if(rdoLarge->Checked == True)
PriceSize = StrToFloat(edtLarge->Text);
if(chkPepperoni->Checked == True)
Pepperoni = StrToFloat(edtPepperoni->Text);
else
Pepperoni = 0;
if(chkSausage->Checked == True)
Sausage = StrToFloat(edtSausage->Text);
else
Sausage = 0;
if(chkExtraCheese->Checked == True)
ExtraCheese = StrToFloat(edtExtraCheese->Text);
else
ExtraCheese = 0;
if(chkOnions->Checked == True)
Onions = StrToFloat(edtOnions->Text);
else
Onions = 0;
if(chkOlives->Checked == True)
Olives = StrToFloat(edtOlives->Text);
else
Olives = 0;
BWings = StrToFloat(edtTotalBuffWings->Text);
Bread = StrToFloat(edtTotalBread->Text);
Pepsi = StrToFloat(edtTotalPepsi->Text);
DietPepsi = StrToFloat(edtTotalDietPepsi->Text);
Sprite = StrToFloat(edtTotalSprite->Text);
OJ = StrToFloat(edtTotalOJ->Text);
RootBeer = StrToFloat(edtTotalRootBeer->Text);
TotalOrder = PriceSize
+ Pepperoni + Sausage + ExtraCheese + Onions + Olives
+ BWings + Bread
+ Pepsi + DietPepsi + Sprite + OJ + RootBeer;
edtTotalOrder->Text = edtTotalOrder->Text.sprintf("%.2f", TotalOrder);
}
//---------------------------------------------------------------------------
22. (If you want to test the project, on the Debug toolbar, click the Run button. On
the form, type floating point numbers in the total edit boxes and continue testing
the order processing. When finished, close the form).
Save the application.
23. Although the compiler relies on the total of each unit, we need to allow the user
(clerk) to change the quantity ordered on a particular unit. For example, one
customer could want more than one bottle of pepsi and another customer might
want almost anything on the menu.
Every item on the right side of the order form has a quantity and a unit price.
After the user has typed the quantity desired for an item, we will convert such a
quantity to an interger. We could write this conversion for each item but since
many items need this conversion, we will write a function that can validate this
number and pass it back to the method or function that needs it. Since the
quantity that the user types is text that is an AnsiString object, the function will
take a string and return an integer.
In the class Explorer, right-click TPizza and click New Method.
24. Set the name of the function to EvaluateQuantity and its argument to
AnsiString Sqty
25. Set the Function Result as int and make it a __fastcall.
26. Implement the EvaluateQuantity() function as follows:
//---------------------------------------------------------------------------
int __fastcall TPizza::EvaluateQuantity(AnsiString SQty)
{
int Qty;
if(SQty == "")
{
Qty = 0;
}
else
Qty = StrToInt(SQty);
return Qty;
}
//---------------------------------------------------------------------------
27. Now that we can rely on a function to evaluate the quantity of each item, we will
send the content of each Qty edit box when necessary.
To get the real total of each unit, we will multiply the quantity by the unit price.
To get the unit price, we will convert the content of each unit Price from
AnsiString to a floating number. Because the user will not usually change the
price of an item, we will perform both conversions (the conversion of the Qty
string to an integer and the conversion of the unit Price string to float) when the
user changes the Qty value. After multiplying the quantity by the price to get the
total, we will call the ShowTotal() function to ask it to update its price.
On the form, double-click each Qty edit box to access its OnChange event.
Implement them as follows:
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtyBuffWingsChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtyBuffWings->Text);
Price = StrToFloat(edtBuffWings->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtyBreadChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtyBread->Text);
Price = StrToFloat(edtBread->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtyPepsiChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtyPepsi->Text);
Price = StrToFloat(edtPepsi->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtyDietPepsiChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtyDietPepsi->Text);
Price = StrToFloat(edtDietPepsi->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtySpriteChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtySprite->Text);
Price = StrToFloat(edtSprite->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtyOJChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtyOJ->Text);
Price = StrToFloat(edtOJ->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
void __fastcall TPizza::edtQtyRootBeerChange(TObject *Sender)
{
int Qty;
double Price, Total;
Qty = EvaluateQuantity(edtQtyRootBeer->Text);
Price = StrToFloat(edtRootBeer->Text);
ShowTotal();
}
//---------------------------------------------------------------------------
28. Save the project.
29. To test the program, on the Debug toolbar, click the Run button.
12.4 Reviews
12.4.1 Exercises
1. The Zoom dialog box of StarOffice is equipped with 8 radio buttons on the left
section under a label marked Zoom factor.
a. Although the radio buttons do not seem to be hosted by a group control, they
still provide mutual exclusiveness, which means only one radio button can be
checked at a time.
Implement this behavior by making sure that there is no physical border around
the radio buttons.
b. To set a value that is not part of the obvious values. The user must click the
Variable then either start clicking the arrow buttons of the spin control or simply
type an integer value in the spin button. The user can type anything before
clicking OK. If the user types a number between 20 and 400, that value applies
and the dialog box recognizes it. If the user types a floating number between 20
and 400, such as 72.15, the dialog box sets the value to either the floor or the
ceiling, depending on the value that is closer. If the user types any number that
is not in a valid decimal format, the dialog box closes as if the user have clicked
Cancel.
Create a form equipped with a button and an Edit control. Allow the user to type
a valid decimal number in the Edit control.
When the user clicks the button, the Zoom dialog box as on the picture above
would display. Make it so that the radio button whose value is closer to the value
of the Edit box would be selected. After using the Zoom dialog box, if the user
clicks OK, implement the behavior described above and display the valid
returned value in the Edit box. If the returned value is not value, keep the value
that was in the Edit box.
2. A
To create a list box, click the ListBox control from the Standard tab of the Component
Palette and click on the form. Once the list box is positioned on a container, you can
move it by clicking and dragging the control. You can also resize it using any of the
techniques we learned to add, position, move, and resize controls on a component. If the
list will cover many items, design it so its height can display 8 items at a time; otherwise,
for a list of 8 or less items, use only the necessary height that would accommodate all of
the items.
After creating the list, click OK. To test the control, you can press F9.
To programmatically add the items to a list box, use the TStrings::Add() method. If the
list were empty, the new items would be added to the list. If the list already contained one
or more items, the new items would be added, by default, to the end of the existing
one(s). Here is an example of creating a list of items or adding new ones to a list:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
ListBox1->Items->Add("Chad");
ListBox1->Items->Add("Equatorial Guinea");
ListBox1->Items->Add("Egypt");
ListBox1->Items->Add("Madagascar");
}
//---------------------------------------------------------------------------
As mentioned already, the user mostly interacts with a list box by selecting an item. At
any time you can find out whether a particular item has been selected. This is done using
the TCustomListBox::Selected Boolean property.
When the Items of a list box appear in alphabetical order, the list is said to be sorted. By
default, the items of a list box are not sorted. To arrange the list to ascending order, set
the Sorted property’s value to true. As a Boolean data type, you can set the sorting
feature programmatically as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ListBox1->Sorted = True;
}
//---------------------------------------------------------------------------
If you create an unsorted list, then at one time get it sorted (for example, you can give the
user the ability to sort the list, by clicking a button), the list would be sorted. If an item is
added to the sorted list, the compiler would automatically insert to the right position
following the order. If at another time you allow the user to “unsort” the list, the list
would keep its current order. If another item is added when the list is not sorted, the item
would be positioned at the end of the list. If you want the list to have its original state,
you would have to reset it through code.
If you change the Color property of the ListBox control, its whole background would
appear with that color. If you want each item to have its own color, you would have to
change the style of the list and properly configure it.
When you create a list of items, they appear in one range of columns. If the number of
items exceeds the height, a scrollbar would appear on the control. One alternative you can
use is to span the list on more than one column. This is set using the Columns property.
By default, the Columns value is set to 0, which means the items appear in one column.
If you position the control on a form whose DockSite property is set to true with the the
control has a DragKind property dkDock and the DragMode property set to
dmAutomatic, the user will be able to move the control and position it anywhere inside
the form.
By deafault, the user can select only one item in the list. This is controlled by both the
ExtendedSelect and the MultiSelect properties. If you want the user to be able to select
more than one item, you should set the MultiSelect property to true sinc the
ExtendedSelect property would already be set to true. After the user has selected more
than one item, you can use the TCustomList::SelCount to find out the number of items
that the user would have selected.
The list boxes are designed in three types of style. The default is the lbStandard in
which case each item in the list is an AnsiString object. On the other hand, if you want
each item of the list to display a graphic or a color, you must set the style to an owner
draw. The lbOwnerDrawFixed allows you to set a desired height by each item of the
list. This height is controlled through the ItemHeight property. You can set a different
height for each item if your set the list style to lbOwnerDrawVariable.
The ItemIndex is a property that identifies which item is selected in a list box. This is a
property of highly particular interest. If you try performing an operation thatn requires
that an item be selected and no item is selected, the program would throw an error (it
would crash). The items in a list box are counted from 0, then 1, etc. The first item, at
position 0, can be identified as ListBox1->ItemIndex = 0. If no item is selected in the list,
the TCustomListBox::ItemIndex has a value of –1;
The items of a list box are AnsiString objects created from the TStrings class. This allows
you to use the properties of the TStrings class.
//---------------------------------------------------------------------------
void __fastcall TForm1::CreateTheList()
{
TListBox* Liste = new TListBox(this);
Liste->Parent = Form1;
}
//---------------------------------------------------------------------------
If the list box will be positioned on another type of container, such as a panel called
Panel1, you can create it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::CreateTheList()
{
TListBox* Liste = new TListBox(this);
Liste->Parent = Panel1;
}
//---------------------------------------------------------------------------
If you create the list box in a function, a method, or an event, the list will exist only inside
Note of that function: you cannot manipulate it from another function, method, or event. If you
When creating a want the control to be accessed by many functions declare a TListBox object in the
control dynamically in header file of the form where the control will be hosted.. Here is an example:
the header file, You
should declare it in the
public or the private //---------------------------------------------------------------------------
sections of the header #ifndef Unit1H
file. If you declare it in #define Unit1H
the published section,
//---------------------------------------------------------------------------
you would get an
annoying warning #include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private: // User declarations
TListBox *Listing;
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
After declaring the control, you should initialize it in the form’s contructor. This allows
you to specify the contrainer that will host the control:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Listing = new TListBox(Form1);
Listing->Parent = Form1;
Listing->Left = 120;
Listing->Top = 80;
}
//---------------------------------------------------------------------------
When an application terminates, Borland C++ Builder takes care of destroying all of the
objects that are part of the application. If the objects were created at design time, they are
owned by the form. Since the form is owned by the application, the application would
destroy the form including its hosted controls. If a control was placed on another
container such as a panel, the panel is owned by the form and the form by the application.
The destruction would still be smooth when the application executes. If you dynamically
create a control, you must specify the owner of the control; otherwise the program would
not compile. Since you will have specified the owner or container of the control, when
the application exits, the compiler would destroy the form and its control, which would
include the control you dynamically created. Therefore, you do not have to worry about
the state of the dynamic controls when your application exits. This does not mean that
your application would never produce a memory leak, but it would be highly unlikely.
If you want to explicitly destroy your dynamically created object, use its destructor. The
best place to destroy a global object is to use the delete operator on the OnDestroy event
of the form:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
delete Listing;
Listing = NULL;
}
//---------------------------------------------------------------------------
If the list box was dynamically created inside of a function, you cannot access it outside
of that function. If it were declared in the header file, you can use any appropriate
method, event, or function to fill the list or to manipulate the control. For example, you
can fill out the Listing control we declared earlier as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Listing->Items->Add("C++ Builder");
Listing->Items->Add("Delphi");
Listing->Items->Add("JBuilder");
Listing->Items->Add("Kylix");
}
//---------------------------------------------------------------------------
Since the items of a list box are derived from the TStrings class, you can use this class’
methods to perform the desired operations on the control. The strings in a list box are
counted starting at 0, then 1, and so on.
To add an item at the end of the list, you can write code such as:
To insert an item in the 2nd position you can write code such as:
If the list contains less than 4 items, the TStrings::Delete() method would ignore the
operation. If you have an Edit control called edtCountry, you can let the user add its
content to the list box when he or she double-clicks the edit box. The code could look as
follows:
If the user is filling out a list box while typing additional items in an Edit control, the best
and fastest way to add a new item is when the user presses Enter after typing the item. To
implement this behavior, you should find out what key the user pressed. If the user
presses Enter when the edit box has focus, you should make sure the edit box contains a
string. The code could appear like this:
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1KeyPress(TObject *Sender, char &Key)
{
if( Key == 13 ) // If the user presses the Enter key
{
if(Edit1->Text != "") // If Edit1 contains something
{
lstCountries->Items->Add(Edit1->Text); // Add the content of Edit1 to ListBox1
Edit1->Text = ""; // Reset Edit1 and make it empty
}
else // Since Edit1 is empty, display a message
Panel1->Caption = "There is nothing to add";
}
}
//---------------------------------------------------------------------------
The TCustomListBox::Clear() method is used to clear the control of its whole content:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
lstCountries->Clear();
}
//---------------------------------------------------------------------------
1. From the Standard of a list box, double-click Add Lesotho and implement it as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
lstCountries->ItemIndex = 6;
}
//---------------------------------------------------------------------------
When performing your operations, sometimes you will want to find out if a particular
item is selected. You can do this using the ordinal position of the item. For example, to
find out if the 3rd item is selected, you can write:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button7Click(TObject *Sender)
{
if( lstCountries->ItemIndex == 2)
Panel1->Caption = "The third item is selected";
}
//---------------------------------------------------------------------------
If an item is selected, you can allow the user to perform an operation on it. If a string
(that is, any string) is not selected, most operations would fail and the program would
crash. Therefore, usually you should make sure an item is selected. An item is selected
when the value of the TCustomListBox::ItemIndex is not –1. Operations include
displaying the selected item of the list box to an edit box:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
// First find out whether an item is selected
if(lstCountries->ItemIndex != -1) // Put the selected item in the edit
Edit1->Text = lstCountries->Items->Strings[lstCountries->ItemIndex];
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
lstCountries->Items->Insert(lstCountries->ItemIndex, Edit1->Text);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::Button6Click(TObject *Sender)
{
lstCountries->Items->Insert(lstCountries->ItemIndex + 1, Edit1->Text);
}
//---------------------------------------------------------------------------
Many times during your design, you will allow users to add or delete items to or from a
list box. One way you will do this is to create a list of items originating from another list;
this allows you to control the items the user can select from a list before continuing with
the issue at hand. Borland C++ Builder ships with a dialog box completely configured to
handle this transaction.
To allow two list boxes to exchange data, you provide the appropriate buttons. If only
one list will be used as the source, provide one button that could allow the user to select
an item. It is also a good idea to allow the user to select and add all items at once. Also
important is the ability for the user to remove mistakenly selected items. Over all, these
kinds of list boxes handle their transactions through the use of four buttons: two are used
to exchange one item at a time from one list to another, two to exchange all items from
one list to another.
1. To start a new project, on the Standard toolbar, click the New button
2. Make sure the Application icon is selected and click OK
3. To add Borland C++ Builder’s built-in list box dialog, on the Standard toolbar,
click the New button .
4. In the Object Repository, click the Forms property sheet.
6. Click OK.
7. To remove the starting form, press F12 to display the Code Editor.
8. Click the Unit1.cpp to select it.
9. Right-click the Unit1.cpp tab and click Close Page
10. When asked whether you want to save Unit1, click No.
11. To test the application, press F9.
12. Use the existing transfer buttons to exchange items between both list boxes.
13. Close the form using its Windows Close button.
14. On the form, click the Source List label.
15. On the Object Inspector, click Caption and type Cities to locate on a map:
16. Click Destination List and type Cities Selected:
17. To remove the items in the list, click the left list to select it.
18. On the Object Inspector, click the ellipsis button of the Items field.
19. Delete all items in the String List Editor dialog box and click OK.
20. To create our own list, double-click an unoccupied area of the form and
implement the OnCreate event as follows:
SrcList->Items->Add("Shangai");
SrcList->Items->Add("Melbourne");
SrcList->Items->Add("Kenitra");
SrcList->Items->Add("London");
SrcList->Items->Add("Valencia");
SrcList->Items->Add("Rio de Oro");
SrcList->Items->Add("Santiago");
SrcList->Items->Add("Dublin");
SrcList->Items->Add("Bamako");
SrcList->Items->Add("New Delhi");
SrcList->Items->Add("Tokyo");
SrcList->Items->Add("Alexandria");
SrcList->Items->Add("Boston");
SrcList->Items->Add("Quebec");
SrcList->Items->Add("Dar-Es-Salam");
SrcList->Items->Add("Munich");
}
21. Display the form.
22. Click the Cancel button and press Delete.
23. Also delete the Help button.
24. Double-click the OK button and implement its OnClick event as follows:
Like a radio button, a combo box allows the user to select one item from a group. Unlike
radio buttons, a combo box saves space by using just as much room as an edit control.
Like a list box, a combo box displays a list of items to the user. Unlike a list box, there is
a version of a combo box that retracts once the user has made a selection; this is useful
when space saving is particularly important.
Just like every control of your application, the name is the most important property of the
control, for you and the compiler. This name allows you and the compiler to refer to the
control. By default, the first combo box you add to your form at design time is called
ComBox1, the second would be ComboBox2, etc. To change the name of the control,
click the Name field, type a new name and press Enter (or click somewhere else).
Probably the first this the user sees on a combo box is the text it displays. Although the
text of an item is an AnsiString, the items are composed from the TStrings class. To
create this list, when the control is selected on the form, on the Object Inspector, click the
Items field to reveal an ellipsis button. Click the ellipsis button to display the String List
Editor. Type each string and press Enter:
Once you click OK, the control would be filled with the new items. You can also fill out
the control using the methods of the TStrings class. For example, to create a list of items,
you could write:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFillTheListClick(TObject *Sender)
{
cbxColors->Items->Add("Old Blue");
cbxColors->Items->Add("Light Blue");
cbxColors->Items->Add("Salmon");
cbxColors->Items->Add("Dark Violet");
}
//---------------------------------------------------------------------------
By default, the items you add to the combo box will appear in the order they are supplied.
For example the TStrings::Add() method would add the new string at the end of the list.
If you want the list of items to be sorted, you can change the value of the Sorted property
in the Object Inspector from false (the default) to true. To sort a list programmatically,
you can write:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSortTheListClick(TObject *Sender)
{
cbxColors->Sorted = True;
}
//---------------------------------------------------------------------------
You can unsort the list by changing the value of the Sorted property.
There are three styles of combo boxes, although all allow the user to make only one
selection. These styles are controlled by the TComboBoxStyle enumerator and the Style
property of the Object Inspector. A combo box can be configured to allow the user to add
items to the list. In this case, if the user does not find the desired item in the list, he or she
can type a new one values. To provide this ability, set the Style to csDropDown. If you
set the Style to csDropDownList, the user cannot enter a new item in the list but can still
select one from the control. A combo box with the csSimple Style permanently displays
a combination of an edit box and a list box. The user can scroll in the list box and select
an item; after the selection, the list would still display the list. The other two styles,
csOwnerDrawFixed and csOwnerDrawVariable, are typically used to display varying
objects such as pictures or colors }.
If the combo box has a style other than csSimple, there is typically a fixed number of
items that display when the user click the control’s arrow. You can control the number of
items that displays using the DropDownCount property. By default, this is set to 8. If the
list contains a number of items less than the DropdownCount integer value, all of the
items would display fine. If the list contains more than the DropDownCount number of
items, when the user clicks the arro, a scroll box would appear. The control would display
DropDownCount number of items; to reveal more, the user would have to scroll in the
list.
The text that displays on a non-drawn combo box is an AnsiString object. If you want the
combo box to display a certain string, use the Text property. At design time, you can set
this only if the control’s Style is csDropDown or csSimple. At run time, you can set the
text that would display in the combo box at startup using the ItemIndex property. This
property represents the ordinal integer item of the combo box. The items are counted
from 0, then 1, and si on. The ItemIndex of each item is set depending on the value ot
the Sorted property. If the list is not sorted, the first item entered in the list has an
ItemIndex value of 0. If the list gets sorted, the first item in ascending order has an
ItemIndex property set at 0. You can therefore use this property to control what item to
display in the list:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
cbxColors->ItemIndex = 0;
}
//---------------------------------------------------------------------------
You can also use the ItemIndex property to find out what item is selected at a given time.
11. Click the Items field and click its ellipsis button . Type 00:00 AM and press
Enter. Type 00:30 AM and press Enter. Type the hourly numbers to complete
the list with the following values: 00:00 AM, 00:30 AM, 01:00 AM, 01:30 AM,
02:00 AM, 02:30 AM, 03:00 AM, 03:30 AM, 04:00 AM, 04:30 AM, 05:00 AM, 05:30 AM,
06:00 AM, 06:30 AM, 07:00 AM, 07:30 AM, 08:00 AM, 08:30 AM, 09:00 AM, 09:30 AM,
10:00 AM, 10:30 AM, 11:00 AM, 11:30 AM, 12:00 PM, 12:30 PM, 01:00 PM, 01:30 PM,
02:00 PM, 02:30 PM, 03:00 PM, 03:30 PM, 04:00 PM, 04:30 PM, 05:00 PM, 05:30 PM,
06:00 PM, 06:30 PM, 07:00 PM, 07:30 PM, 08:00 PM, 08:30 PM, 09:00 PM, 09:30 PM,
10:00 PM, 10:30 PM, 11:00 PM, 11:30 PM
23. On the right side of the right Time Out, add a label with a caption as Total
24. Under the Total label, add an Edit control that has a Text property as 8.00
25. On the form, click one of the combo boxes. Press and hold Shift. Click each of
the other combo boxes and the edit box under the Total label. Release Shift
26. On the main menu, click Edit Copy
27. Click an empty area on the panel to select it.
28. On the menu, click Edit Paste
29. While the new pasted controls are still selected, move the selection under the
other similar controls:
30. On the panel, select all the combo boxes and the edit boxes under the Total
label. Copy the selection. Click an empty area on the panel. Paste the selection.
Move the selected controls down:
31. On the panel, select all the combo boxes of the top three rows and the top three
edit boxes under the Total label. Copy the selection. Click on the panel. Paste
the selection. Move the selected controls to create seven rows as follows:
32. To continue with the design of the form, add six labels under Monday. Set their
captions to Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday
respectively.
33. Add a label captioned Total Weekly Hours: and add an Edit control to the right
as in the following picture. Set the Text property of the new Edit control to
40.00
34. Set the names of the ComboBox and Edit controls as in the following table:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateComboBoxClick(TObject *Sender)
{
TComboBox *CarMake = new TComboBox(this);
CarMake->Parent = this;
}
//---------------------------------------------------------------------------
If you want the object to be accessible from more than one function or event, declare an
instance of a TComboBox control in the public or private sections of the object, unit or
form that would use it:
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TButton *btnCreateComboBox;
void __fastcall btnCreateComboBoxClick(TObject *Sender);
private: // User declarations
TComboBox *CarModel;
public: // User declarations
In the source file, use the new operator to specify the control owner of the object. If you
want the control created when the form starts, you can do this in the form’s constructor:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
CarModel = new TComboBox(this);
CarModel->Parent = this;
}
//---------------------------------------------------------------------------
After creating the object, you can manipulate its properties the change the defaults. If you
create a local list, you will manipulate it in the same function or event:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCreateComboBoxClick(TObject *Sender)
{
TComboBox *CarMake = new TComboBox(this);
CarMake->Parent = this;
CarMake->Left = 32;
CarMake->Top = 16;
CarMake->Items->Add("Ford");
CarMake->Items->Add("Renault");
CarMake->Items->Add("Fiat");
CarMake->Items->Add("Honda");
}
//---------------------------------------------------------------------------
If the object were created globally, you can access it anywhere to manipulate it:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
CarModel = new TComboBox(this);
CarModel->Parent = this;
CarModel->Left = 200;
CarModel->Top = 16;
CarModel->Items->Add("Elantra");
CarModel->Items->Add("LeBaron");
CarModel->Items->Add("Corolla");
CarModel->Text = "Corolla";
}
//---------------------------------------------------------------------------
a combo box are from other controls or actions that are not programmatically directly
related to a combo box. It is usually possible to fill out the list of a combo box at design
time; that is, if you know the list of items that will be used. Otherwise, you will use
another event or function to provide the items of the list. For example, the OnCreate
event of a form is a common place to fill out a list, especially if you want the list to owns
its items the first time it appears to the user. If you create a combo box named cbxSports
but do not provide its items at design time, you can use the OnCreate event of the hosting
form to fill it up as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
cbxMajor->Items->Add("Accounting");
cbxMajor->Items->Add("Medical Assistant");
cbxMajor->Items->Add("Fire Science");
cbxMajor->Items->Add("Computer Sciences");
cbxMajor->Items->Add("Business Administration");
cbxMajor->Items->Add("Hospitality Management");
cbxMajor->Items->Add("Criminal Justice");
cbxMajor->Items->Add("Computer Technician");
cbxMajor->Items->Add("Cartography");
cbxMajor->Items->Add("Music");
cbxMajor->ItemIndex = 3;
}
//---------------------------------------------------------------------------
The most regular operation a user performs on a combo box is to select an item from the
list. This happens when the user clicks the arrow to expand the list and then clicks one
item. Once the user clicks one of the items, the list disappears and the combo box
becomes a regular edit box, unless the style of the combo box is csSimple. Using this
event, you can find out what item the user would have selected and act accordingly. For
example, you can transfer the selected item to another control such as an edit box. Here is
an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxMajorClick(TObject *Sender)
{
edtMajor->Text = cbxMajor->Items->Strings[cbxMajor->ItemIndex].c_str();
}
//---------------------------------------------------------------------------
Note The OnChange event occurs when the user changes the event that was displaying in the
The ListBox control does edit box of the combo box. Also this event occurs also in response to the user making a
not have an OnChange event selection, it is more appropriate if you allow the user to edit an item of the list or if you
because the user cannot edit allow the user to add items to the list by typing directly in the edit box. Like the Edit
an item in the list. This is
because a list box does not control, the OnChange event occurs immediately as the user types anything in the edit
have an edit portion. box portion of the combo box. The OnClick event cannot respond to these events. You
can use the OnChange event to deal with the user trying to modify the item on the edit
box. You can also use it to respond to other actions associated with the user making a
selection. For example, you can simply display the list the number of items in the list:
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxMajorChange(TObject *Sender)
{
edtCount->Text = IntToStr(cbxMajor->Items->Count);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
// These are the starting times set on each combobox.
// The ItemIndex property is used to set the combobox' selection
cbxMondayIn1->ItemIndex = 18;
cbxMondayOut1->ItemIndex = 24;
cbxMondayIn2->ItemIndex = 24;
cbxMondayOut2->ItemIndex = 34;
cbxTuesdayIn1->ItemIndex = 18;
cbxTuesdayOut1->ItemIndex = 24;
cbxTuesdayIn2->ItemIndex = 24;
cbxTuesdayOut2->ItemIndex = 34;
cbxWednesdayIn1->ItemIndex = 18;
cbxWednesdayOut1->ItemIndex = 24;
cbxWednesdayIn2->ItemIndex = 24;
cbxWednesdayOut2->ItemIndex = 34;
cbxThursdayIn1->ItemIndex = 18;
cbxThursdayOut1->ItemIndex = 24;
cbxThursdayIn2->ItemIndex = 24;
cbxThursdayOut2->ItemIndex = 34;
cbxFridayIn1->ItemIndex = 18;
cbxFridayOut1->ItemIndex = 24;
cbxFridayIn2->ItemIndex = 24;
cbxFridayOut2->ItemIndex = 34;
cbxSaturdayIn1->ItemIndex = 24;
cbxSaturdayOut1->ItemIndex = 24;
cbxSaturdayIn2->ItemIndex = 24;
cbxSaturdayOut2->ItemIndex = 24;
cbxSundayIn1->ItemIndex = 24;
cbxSundayOut1->ItemIndex = 24;
cbxSundayIn2->ItemIndex = 24;
cbxSundayOut2->ItemIndex = 24;
}
//---------------------------------------------------------------------------
3. To test the new combo boxes, on the main menu, click Run Run
4. The value of each time in or time out is recognized by three parts: the hour, the
minute, and the AM portions. We need a function that can receive these three
parts, decode them and return a time value in decimal format.
Right-click in the Class Explorer and click New Method…
5. Set the Method Name to CalcTime and in the Add To Class combo box, select
TForm1. In the Arguments edit box, type
AnsiString h, AnsiString m, AnsiString AMPM
6. Set the function Result to double and click the __fastcall check box and click
OK.
7. Implement the CalcTime() function as follows:
//---------------------------------------------------------------------------
double __fastcall TForm1::CalcTime(AnsiString h, AnsiString m, AnsiString AMPM)
{
double HourFraction; // This should be an integer, but so what?
double MinuteFraction;
10. Click OK
11. Implement the new function as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::EvaluateTheTime()
{
double MondayShift1, MondayShift2;
double TuesdayShift1, TuesdayShift2;
double WednesdayShift1, WednesdayShift2;
double ThursdayShift1, ThursdayShift2;
double FridayShift1, FridayShift2;
double SaturdayShift1, SaturdayShift2;
double SundayShift1, SundayShift2;
double Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday;
double TotalHours;
//---------------------------------------------------------------------------
// The TComboBox::OnClick() event is used (instead of the OnChange
// because it occurs AFTER the selection has been made on a combobox.
void __fastcall TForm1::cbxMondayIn1Click(TObject *Sender)
{
// Using the TComboBox::ItemIndex property to find out
// what is the current selection of each combobox
// that is involved when this combobox' selection has changed
int In1Selection = cbxMondayIn1->ItemIndex;
int Out1Selection = cbxMondayOut1->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
14. Following the same algorithm, implement the OnClick event of all the other
combo boxes as as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxMondayOut1Click(TObject *Sender)
{
int In1Selection = cbxMondayIn1->ItemIndex;
int Out1Selection = cbxMondayOut1->ItemIndex;
int In2Selection = cbxMondayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxMondayIn2Click(TObject *Sender)
{
int In2Selection = cbxMondayIn2->ItemIndex;
int Out1Selection = cbxMondayOut1->ItemIndex;
int Out2Selection = cbxMondayOut2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxMondayOut2Click(TObject *Sender)
{
int Out2Selection = cbxMondayOut2->ItemIndex;
int In2Selection = cbxMondayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxTuesdayIn1Click(TObject *Sender)
{
int In1Selection = cbxTuesdayIn1->ItemIndex;
int Out1Selection = cbxTuesdayOut1->ItemIndex;
if( Out1Selection < In1Selection )
cbxTuesdayIn1->ItemIndex = 18;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxTuesdayOut1Click(TObject *Sender)
{
int In1Selection = cbxTuesdayIn1->ItemIndex;
int Out1Selection = cbxTuesdayOut1->ItemIndex;
int In2Selection = cbxTuesdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxTuesdayIn2Click(TObject *Sender)
{
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxTuesdayOut2Click(TObject *Sender)
{
int Out2Selection = cbxTuesdayOut2->ItemIndex;
int In2Selection = cbxTuesdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxWednesdayIn1Click(TObject *Sender)
{
int In1Selection = cbxWednesdayIn1->ItemIndex;
int Out1Selection = cbxWednesdayOut1->ItemIndex;
if( Out1Selection < In1Selection )
cbxWednesdayIn1->ItemIndex = 18;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxWednesdayOut1Click(TObject *Sender)
{
int In1Selection = cbxWednesdayIn1->ItemIndex;
int Out1Selection = cbxWednesdayOut1->ItemIndex;
int In2Selection = cbxWednesdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxWednesdayIn2Click(TObject *Sender)
{
int In2Selection = cbxWednesdayIn2->ItemIndex;
int Out1Selection = cbxWednesdayOut1->ItemIndex;
int Out2Selection = cbxWednesdayOut2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxWednesdayOut2Click(TObject *Sender)
{
int Out2Selection = cbxWednesdayOut2->ItemIndex;
int In2Selection = cbxWednesdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxThursdayIn1Click(TObject *Sender)
{
int In1Selection = cbxThursdayIn1->ItemIndex;
int Out1Selection = cbxThursdayOut1->ItemIndex;
if( Out1Selection < In1Selection )
cbxThursdayIn1->ItemIndex = 18;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxThursdayOut1Click(TObject *Sender)
{
int In1Selection = cbxThursdayIn1->ItemIndex;
int Out1Selection = cbxThursdayOut1->ItemIndex;
int In2Selection = cbxThursdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxThursdayIn2Click(TObject *Sender)
{
int In2Selection = cbxThursdayIn2->ItemIndex;
int Out1Selection = cbxThursdayOut1->ItemIndex;
int Out2Selection = cbxThursdayOut2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxThursdayOut2Click(TObject *Sender)
{
int Out2Selection = cbxThursdayOut2->ItemIndex;
int In2Selection = cbxThursdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxFridayIn1Click(TObject *Sender)
{
int In1Selection = cbxFridayIn1->ItemIndex;
int Out1Selection = cbxFridayOut1->ItemIndex;
if( Out1Selection < In1Selection )
cbxFridayIn1->ItemIndex = 18;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxFridayOut1Click(TObject *Sender)
{
int In1Selection = cbxFridayIn1->ItemIndex;
int Out1Selection = cbxFridayOut1->ItemIndex;
int In2Selection = cbxFridayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxFridayIn2Click(TObject *Sender)
{
int In2Selection = cbxFridayIn2->ItemIndex;
int Out1Selection = cbxFridayOut1->ItemIndex;
int Out2Selection = cbxFridayOut2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxFridayOut2Click(TObject *Sender)
{
int Out2Selection = cbxFridayOut2->ItemIndex;
int In2Selection = cbxFridayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSaturdayIn1Click(TObject *Sender)
{
int In1Selection = cbxSaturdayIn1->ItemIndex;
int Out1Selection = cbxSaturdayOut1->ItemIndex;
if( Out1Selection < In1Selection )
cbxSaturdayIn1->ItemIndex = 18;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSaturdayOut1Click(TObject *Sender)
{
int In1Selection = cbxSaturdayIn1->ItemIndex;
int Out1Selection = cbxSaturdayOut1->ItemIndex;
int In2Selection = cbxSaturdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSaturdayIn2Click(TObject *Sender)
{
int In2Selection = cbxSaturdayIn2->ItemIndex;
int Out1Selection = cbxSaturdayOut1->ItemIndex;
int Out2Selection = cbxSaturdayOut2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSaturdayOut2Click(TObject *Sender)
{
int Out2Selection = cbxSaturdayOut2->ItemIndex;
int In2Selection = cbxSaturdayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSundayIn1Click(TObject *Sender)
{
int In1Selection = cbxSundayIn1->ItemIndex;
int Out1Selection = cbxSundayOut1->ItemIndex;
if( Out1Selection < In1Selection )
cbxSundayIn1->ItemIndex = 24;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSundayOut1Click(TObject *Sender)
{
int In1Selection = cbxSundayIn1->ItemIndex;
int Out1Selection = cbxSundayOut1->ItemIndex;
int In2Selection = cbxSundayIn2->ItemIndex;
cbxSundayOut1->ItemIndex = 24;
if( Out1Selection > In2Selection )
cbxSundayOut1->ItemIndex = In2Selection;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSundayIn2Click(TObject *Sender)
{
int In2Selection = cbxSundayIn2->ItemIndex;
int Out1Selection = cbxSundayOut1->ItemIndex;
int Out2Selection = cbxSundayOut2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxSundayOut2Click(TObject *Sender)
{
int Out2Selection = cbxSundayOut2->ItemIndex;
int In2Selection = cbxSundayIn2->ItemIndex;
EvaluateTheTime();
}
//---------------------------------------------------------------------------
15. Add a Button control to the right side of the Countries combo box and under the
Count label.
16. To test the new setting, press F9
Chapter 14:
Managing Views
The starting item of the tree is called the Root and illustrates the beginning of the tree.
Each item, including the root, that belongs to the tree is referred to as a node.
In the following charts, the arrow means, “has the following child or children”.
Root Parent
A treeview is not limited to a one-to-one correspondence. Not only can an item have
more than one dependency, but also a child can make the tree stop at any category.
Categories of a treeview are organized by levels of organization. The most used trees
have one parent called the root; then under the root start the dependents.
Root
391 © FunctionX, Inc.
Borland C++ Builder Lists
World
Continent Asia
The children of a parent are recognized by their belonging to the same level but can have different
behaviors; for example, while one child might have another child (or other children), an item on the same
level does not necessarily abide by a set rule. Everything usually depends on the tree designer.
Root World
State ME PA
To create a tree view, use the TreeView control from the Win32 tab. After placing the
control on the form, create its children using the Items property. To include pictures on
your tree, use an ImageList control.
7. While the treeview control is still selected, on the Object Inspector, click the
Items field and click its ellipsis button
8. On the TreeView Items Editor dialog box, click the New Item button
9. Type World and press Enter
10. Type Universe
11. On the dialog box, click Universe and click Delete
12. Click World and click the New Subitem button.
13. Type America and press Enter
14. Type Africana and press Enter
15. Type Europe and press Enter
16. Click Africana and using the Text edit box, edit it to display Africa and press
Enter
17. Type Asia
18. Click America and click New Subitem
19. Type Chile and press Enter.
20. Type Canada
21. Click Asia and click New Subitem
22. Type Thailand and press Enter
23. Type Afghanistan
28. Click the other + signs to expand the tree items and click the – signs
33. On the Form1->ImageList1 ImageList dialog box, click the Add button.
34. Locate the folder where the exercises are located and display the Bitmaps folder.
35. Click World1 and click Open
36. Click Add again. This time, click Bell1 and click Open.
37. Repeat the same process to add Plus, Face1, Losange1, and Band:
Image Selected
Item – Text
Index Index
World 0 1
America / Africa/ Europe / Asia 2 3
Chile / Canada / Thailand / Afghanistan 4 5
47. Click OK
48. To test the treeview, press F9
49. Click the various + to expand and click items to select them. Notice the change
of graphics.
50. After using the form, close it.
C++ Builder provides three classes equipped with various properties and functions to
deal with a treeview. The basic class that manages the treeview control is the TTreeView.
This class controls the visual settings such as background color, borders, borders,
dimensions, etc. Each node is managed by the TTreeNode class. The class is used as a
descriptor of the control. For example, it can be used to find out what node is selected,
whether the node is expanded or collapsed, whether a node has children. The
TTreeNodes class is used to manage a treeview; it combines vaious operations such as
creating the treeview, adding, inseting or deleting nodes, or updating the list of items.
To create a treeview, position a TreeView control on the form (although you can still
create it completely with code). Once the control is placed, you can customize its window
settings derived from the TControl class. The nodes are usually created from the
OnCreate event of the host form.
TreeView1->Items->AddChild(America, "Panama");
TreeView1->Items->AddChild(America, "Colombia");
To use images on a treeview, first include an ImageList control to the form. Using the
Form ImageList dialog box, add the desired images to the list of images. Note the
position of each image in the list; you will need to know the position of each image.
To associate an image to a node, first declare a TTreeNode object and set or assign it a
position. The TTreeNode object needs to know the position of the node for almost any
operation that node will be involved in. The most important property related to an image
is the ImageIndex; this is the position of the image on the list created previously. The
other image you might be interested in is the Selected Index; this informs the TreeNode
object about the position of the image the node will display when selected.
1. To add some pictures to the treeview, from the Win32 tab, double-click the
ImageList to add it to the form.
2. Change the name of the ImageList to imgTree
3. On the form, double-click the ImageList icon
4. Click Add.
5. From the Bitmaps16 folder, include the following pictures: World1, Plus,
Losange1, Bell, Face, and Whole.
6. Click OK
7. On the form, click the listview.
8. On the Object Inspector, set the Images field to imgTree.
9. To assign the images to the appropriate nodes, change the listing of the event as
follows:
TreeView1->Items->Add(NULL, "World");
// Assign a position to the node
World = TreeView1->Items->Item[NULL];
// Set the image states for the node
World->ImageIndex = 0;
World->ImageIndex = 1;
Asia->ImageIndex = 2;
Asia->SelectedIndex = 3;
TreeView1->Items->AddChild(Asia, "Bangladesh");
Country = TreeView1->Items->Item[12];
Country->ImageIndex = 4;
Country->SelectedIndex = 5;
}
10. To test the treeview, press F9.
A list view consists of using one of four views to display a list of items. The list is
typically equipped with icons that allow the user to verify what view is displaying. There
are four views used to display items:
Large Icons: The view displays a list of items using icons with a 32x32 pixels size of
icons. This is the preferred view when the main idea consists of giving a grand overview
of the items
Small Icons: Like the other two views, it uses 16x16 pixel icons to display a simplified
list of the items. Once more, no detail is provided about the items of this list. The list is
organized in disparate columns with some on top of others. If the list is supposed to be
sorted, the alphabetical arrangement is organized from left to right.
List: This list, using small icons, is also organized in columns; this time, the columns are
arranged so that the first column gets filled before starting the second. If the list is sorted,
the sorting is arranged in a top-down manner.
Details: This view displays arranged columns of items and provides as many details as
the list developer had arranged it.
C++ Builder provides a means of creating a list without much concern with coding, as
long as you need just one view to display the list.
To create a listview, use the ListView control from the Win32 tab. If you plan to display
a list without columns, you can create the list in a major one-step process. If the list will
display or need a column, its creation will involve a major two-step process. Once the
listview control is placed on the form, create its items using the Items field. The columns
are created using the Columns field.
42. Click OK
43. On the form, click the listview.
44. On the Object Inspector, set the SmallImages property to imgSmall
45. Change the ViewStyle to vsReport.
46. To test the listview, press F9.
47. After viewing the listview, close the form.
48. On the Component Palette, click the Standard tab.
49. Add four buttons to the form positioned under the list box.
50. Change their captions to &Large Icons, &Small Icons, &List, and &Details
respectively:
51. Double-click the Large Icons button to access its OnClick event.
52. Double-click the other buttons and implement their events as follows:
Creating a listview fom code provides the same flexibility as a listview created at design-
time, minus the ability to visualize live the list being created. To create a listview, place a
ListView control on the form.
The columns and the items of the list are created separately. A column is created using
the TListColumn class. This allows you to add and format columns. An item of the list is
created using the TListItem class.
TListColumn *ListCol;
TListItem *ListIt;
ListCol = ListView1->Columns->Add();
ListCol->Caption = "Country";
ListCol->Width = 95;
ListCol = ListView1->Columns->Add();
ListCol->Caption = "Area (Km2)";
ListCol->Width = 70;
ListCol->Alignment = taRightJustify;
ListCol = ListView1->Columns->Add();
ListCol->Caption = "Population (M)";
ListCol->Width = 90;
ListCol->Alignment = taRightJustify;
ListCol = ListView1->Columns->Add();
ListCol->Caption = "Budget";
ListCol->Width = 50;
ListCol->Alignment = taRightJustify;
ListCol = ListView1->Columns->Add();
ListCol->Caption = "Capital";
ListCol->Width = 85;
ListCol = ListView1->Columns->Add();
ListCol->Caption = "@";
ListCol->Width = 30;
ListIt = ListView1->Items->Add();
ListIt->Caption = "Belgium";
ListIt->SubItems->Add("30,510");
ListIt->SubItems->Add("10,241,506");
ListIt->SubItems->Add("116.5B");
ListIt->SubItems->Add("Gaborone");
ListIt->SubItems->Add("BC");
ListIt = ListView1->Items->Add();
ListIt->Caption = "Colombia";
ListIt->SubItems->Add("1,138,910");
ListIt->SubItems->Add("39,685,655");
ListIt->SubItems->Add("22B");
ListIt->SubItems->Add("Bogota");
ListIt->SubItems->Add("CO");
ListIt = ListView1->Items->Add();
ListIt->Caption = "Botswana";
ListIt->SubItems->Add("600,370");
ListIt->SubItems->Add("1,576,470");
ListIt->SubItems->Add("1.6B");
ListIt->SubItems->Add("Gaborone");
ListIt->SubItems->Add("BC");
ListIt = ListView1->Items->Add();
ListIt->Caption = "Danemark";
ListIt->SubItems->Add("43,094");
ListIt->SubItems->Add("5,336,394");
ListIt->SubItems->Add("59.7B");
ListIt->SubItems->Add("Copenhagen");
ListIt->SubItems->Add("DA");
ListIt = ListView1->Items->Add();
ListIt->Caption = "Bangladesh";
ListIt->SubItems->Add("144,000");
ListIt->SubItems->Add("129,194,224");
ListIt->SubItems->Add("4.3B");
ListIt->SubItems->Add("Dhaka");
ListIt->SubItems->Add("BG");
ListIt = ListView1->Items->Add();
ListIt->Caption = "Benin";
ListIt->SubItems->Add("112,620");
ListIt->SubItems->Add("6,395,919");
ListIt->SubItems->Add("299M");
ListIt->SubItems->Add("Cotonou");
ListIt->SubItems->Add("BN");
ListView1->ViewStyle = vsReport;
}
14. To test the form, press F9.
15. Since there is a line in the midddle of the form, try to drag the line left and right
to resize the form’s sections.
16. After viewing the form, close it.
17. Press F12 to display the form. To add images, from the Win32 tab, double-click
the ImageList control.
18. Double-click the ImageList icon on the form.
19. Click Add and add the following images (click No to All if you receive a
warning message): Belgium, Columbia, Botswana, Danemark, Bangladesh, and
Benin
20. Open the FormCreate event again.
21. After the TListItem line, add the following:
ListView1->LargeImages = ImageList1;
ListView1->SmallImages = ImageList1;
22. After the first ListIt->Caption line, add the following:
ListIt->Caption = "Belgium";
ListIt->ImageIndex = 0;
23. In the same way, assign an image to each item list:
ListIt->Caption = "Colombia";
ListIt->ImageIndex = 1;
ListIt->Caption = "Botswana";
ListIt->ImageIndex = 2;
ListIt->Caption = "Danemark";
ListIt->ImageIndex = 3;
ListIt->Caption = "Bangladesh";
ListIt->ImageIndex = 4;
ListIt->Caption = "Benin";
ListIt->ImageIndex = 5;
24. To test the form, press F9.
25. After using the form, close it.
A splitter is a bar that divides a window area in two sections. These sections are referred
to as panes or frames.. The splitter bar is used to create independent sections holding
various controls. The splitter can divide the sections horizontally or vertically, depending
on how you create it Among other things, the design and implementation allows to
display related data.
To create a splitter bar, click the Splitter control from the Additional tab of the
Component Palette. The Splitter must be added to a control that has the Align property
set to a value other than alNone. If the splitter is embedded to a control that has the alLeft
or alRight Align property, it will create two vertical ssections. If the Align of a control is
set to alTop or alBottom when receiving the splitter, this creates two horizontal sections.
By using a combination of panels and other controls, you can divide the window in as
many sections as necessary and in any way.
1. Display the form. Click the TreeView control on the left side of the form to
select it. Make sure its Align property is set to alLeft.
2. From the Additional tab of the Component Palette, click the Splitter control.
3. Click the treeview on the left side of the form. Notice that the splitter aligns
vertically with the treeview.
4. That’s it. To test the form, press F9.
5. Drag the splitting line in the middle of the form to resize the sections.
6. After using the form, close it.
The SpeedButton control provides the ability to create click buttons that behave either
like check boxes or radio buttons. As a check boxes, you can create a group of speed
buttons so that, out of the group, the selected one will display and keep a clicked state. To
implement a radio button effect, you can create speed buttons in a group so that only one
in the group would display a clicked state when chosen. Speed Buttons can also display
as regular buttons. In fact, a speed button’s behavior is configured as that of a regular
button. The design of the speed button provides the most different aspect of the control.
To create a speed button, use the SpeedButton control from the Additional tab. The best
way to implement the behavior of a group of speed buttons is to place then on a toolbar or
a panel control
1. Make sure the Additional tab is still displaying. Click the SpeedButton control
and click on the panel above the ListView control
Click here
9. Click one of the speedbuttons, press Shift and click each one of the other
speedbuttons
10. Set their Flat property to True. Set their GroupIndex to 1
11. Click anywhere on the form to deselect.
12. Double-click the LargeIcons button to access its OnClick event:
13. Double-click the other buttons and implement the OnClick events as follows:
15.1 Lists
A string, as we have studied and used a few of theem, is a group of characters. A list is a
suite of items of the same category. By default, a list is made of a single type of items
easily identified, but an advanced list is made of objects that are of the same type
although each object can be made of its sub-objects.
A simple list
whose items
are text-based
A list could also be structured as a tree made of words or groups of words. An example is
the list of fonts in WordPerfect 2002:
A Tree View
as a list
A list can also combine graphics and text. The Area dialog box of StarOffice features
such a list:
A list that
combines
graphics
and text.
A list does not have to be made of items uniformly aligned. For example, the list of
colors of MS Excel’s Format Cells dialog box is made of square boxes representing
colors:
A list does not necessarily display its items all at once. For example, the items of a
listview are usually configured to change their display mode. Such is the case for the
right pane of Windows Explorer. Another category of list of this kind is implemented for
a multiple-choice question exam or text where only one question as a member of the list
of questions would display:
Strings are used everywhere and for various circumstances. To start, you should be
familiar with what is available in the VCL before creating your own lists.
A popular type of list is available on database applications. These lists allow the user to
select items from one list to create a new one. An example is the Form Expert from Corel
Paradox:
When creating a list, you will decide how you would like users to interact with that part
of your application, how they can interact with the list, what can do and what they should
be prevented from doing. The less interaction users have with a list, the least difficult it is
to create. Depending on your intentions, you will need to provide just as much usefulness
as possible to the user. Although lists can appear difficult to create and implement, user
will not care how much work you put into; you will still need to be at least enough
creative.
Many controls use lists as their main components. Such controls are list views, combo
boxes, rich texts, tree views, list boxes, color fields, radio button groups, text memos,
checked list boxes, etc. There are various classes C++ Builder provides to create such
lists.
The TStrings class is used to provides most of the list-based controls with the properties
and methods they need for their functionality. Because of this, such controls are equipped
to take advantage of all (or most) properties of this class. Such controls need to be filled
out with their main items, usually strings.
Since the TStrings class does not lead to a specific Windows control, the control that
needs it has to call it. Put it in reverse order, the TStrings class is declared in each class
that needs to create a list based on a TStrings class. For this reason, it is free to be named
anyway a class wants it. For example, in the TMemo class, the TStrings variable is
declared as Lines whereas it is called Items in the TListBox and the TComboBox
classes.
To implement a list based on the TStrings class from any of these objects, call the
TStrings property which in turn would give access to its properties and methods.
The primary operation you as the programmer will perform on a new list is to fill it with
the items the user can use. At design time, this is usually easy to do because most list-
based controls provide a dialog box used to create an initial list (this is Rapid Application
Development in its truest form). If you have to programmatically create the list,
depending on the control, you would be interested to know not only whether the item was
added to the list but also what position the item is occupying in the list. To create such a
list, call the TStrings::Add() method. Its syntax is:
This function takes one argument as an AnsiString object and add it to the end of the
target list. If the list is empty, the Add() method would intiate the list with the new item.
The Source argument could be a locally defined string. For example, the following would
add the Borland C++ Builder is Fun!!! string to a Memo control when the user clicks
Button1:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->Lines->Add("Borland C++ Builder is fun!!!");
}
//---------------------------------------------------------------------------
You can also use a string held by another control. In this case you would call the control
field that holds the string. For example, the following would add the content of the Edit1
edit box, or the Text property of the Edit control, to a Memo control when the user clicks
Button1:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->Lines->Add(Edit1->Text);
}
//---------------------------------------------------------------------------
You could also use the name of a string variable to add its value to a TStrings variable:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String Address = "4812 Lockwood Drive #D12";
Memo1->Lines->Add(Address);
}
//---------------------------------------------------------------------------
If the addition of the Source string to the TStrings variable was successful, Add() returns
the position where the Source string was added. The position is zero-based. If Source was
set as the first item of the list, its position would be 0. If it were added as the 2nd item of
the list, it would assume position 1, etc. If you need to, you can find out the position the
argument is occupying after being added. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
String Address = "4812 Lockwood Drive #D12";
int Success = Memo1->Lines->Add(Address);
If you are not interested in the position that Source occupied once it was added, you can
use use the Append() method. Its syntax is:
For a text-based control such as Memo or Rich Edit, the only thing you want to know is
whether the item was added to the sequence. This makes the Append() method useful.
This method also takes one argument as the AnsiString object to be added. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->Lines->Append("The magazine is on the table");
}
//---------------------------------------------------------------------------
2. To save the project, on the Standard toolbar, click the Save All button
3. By clicking the Create new Folder button, create a new folder called List Filler
and display it in the Save combo box
4. Save the unit as Main and the project as ListFiller
5. Change the form’s caption to Travel Plans
6. Add a label on the top left section of the form. Set the caption to
Select a Continent:
7. Add a ComboBox control under the exisiting label. Change its name to
cbxCountries
8. To create a list of continents, double-click in the middle of the form to access its
OnCreate event.
9. Implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
cbxContinents->Items->Append("Asia");
cbxContinents->Items->Append("Europe");
cbxContinents->Items->Append("America");
cbxContinents->Text = "Asia";
}
//---------------------------------------------------------------------------
10. To test the project, on the main menu, click Run Run
11. Test the combobox by selecting different items. Close the form
12. If the form is not displaying, press F12. Add a label under the combo box with a
caption of Select a Country:
13. Add a listbox under the new label. Change its name to lstCountries
14. To fill out the new control, we will do this depending on the item selected on the
top combobox. Therefore, double-click the Select A Continent combox to
access its OnChange event.
15. Set the default list for the Countries combo box in the OnCreate event of the
form to synchronize with the default selection of the Continent combobox. Then
implement the OnChange event of the Countries combobox as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
cbxContinents->Items->Append("Asia");
cbxContinents->Items->Append("Europe");
cbxContinents->Items->Append("America");
cbxContinents->Text = "Asia";
lstCountries->Items->Append("Sri Lanka");
lstCountries->Items->Append("Indonesia");
lstCountries->Items->Append("Yemen");
lstCountries->Items->Append("Iraq");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cbxContinentsChange(TObject *Sender)
{
if(cbxContinents->Text == "Asia")
{
lstCountries->Clear();
lstCountries->Items->Append("Sri Lanka");
lstCountries->Items->Append("Indonesia");
lstCountries->Items->Append("Yemen");
lstCountries->Items->Append("Iraq");
}
else if(cbxContinents->Text == "Europe")
{
lstCountries->Clear();
lstCountries->Items->Clear();
lstCountries->Items->Append("Sweden");
lstCountries->Items->Append("Greece");
lstCountries->Items->Append("Portugal");
lstCountries->Items->Append("Spain");
}
else
lstCountries->Clear();
}
//---------------------------------------------------------------------------
16. To test the project, on the Debug toolbar, click the Run button
17. On the Select A Continent combobox, select different continents and make sure
the list of countries changes accordingly. After testing the combobox, close the
form.
This function needs two pieces of information. The Index argument specifies the intended
position to insert the item. The positions are zero-based. If you want to add the new item
on top of the list, set the Index to 0, for the second place, set the Index to 1, etc. The
string to be added is the Source argument. In the following example, the Easy Listening
string is added to the 3rd position on a list:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ListBox1->Items->Insert(2, "Easy Listening");
}
//---------------------------------------------------------------------------
The Index value applies whether the list is sorted or not. If you would like to add a new
string to a sorted list and insert it to the right alphabetical sequence, use the Add() or the
Append() methods.
Besides adding, appending, or inserting, you can delete an item from a list. This is
performed using the Delete() method whose syntax is:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDeleteClick(TObject *Sender)
{
cbxNetwork->Items->Delete(2);
}
//---------------------------------------------------------------------------
To (effectively) use the Delete() method, you should supply the position of the item you
want to delete. Sometimes such a position would be invalid. The best thing to do is to
first inquire whether the item you want to delete exists in the list. For this and many other
reasons, you can ask the compiler to check the existence of a certain item in a list. This
operation is performed using the IndexOf() method. Its syntax is:
To use this function, provide the string you are looking for. This string is an AnsiString
object. If the string exists in the list, the IndexOf() method returns its position in the list.
The following event is used to examine the items of a combo box looking for a Printer
string:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnFindClick(TObject *Sender)
{
cbxNetwork->Items->IndexOf("Printer");
}
//---------------------------------------------------------------------------
If the IndexOf() method finds that the Source string exists in the target list, it returns the
position of Source. You can then use this information as you see fit. For example you can
insert a new string on top of the found string. Here is example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnInsertClick(TObject *Sender)
{
int Found = cbxNetwork->Items->IndexOf("Printer");
if( Found )
cbxNetwork->Items->Insert(Found, "Digital Camera");
}
//---------------------------------------------------------------------------
You could also look for Source in a target list and delete it if it exists. Here is an
example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnDeleteClick(TObject *Sender)
{
int Found = cbxNetwork->Items->IndexOf("Printer");
if( Found )
cbxNetwork->Items->Delete(Found);
}
//---------------------------------------------------------------------------
Another type of operation you will perform in a list is to retrieve the text of a particular
string in the group; this usually happens when you want to transfer an item to another
control or display a message about the item. The Strings property allows you to get an
item based on its position in the list. This property is an array that represents the items of
the list. To locate a string, use the square brackets to specify its position. Because the list
is zero-based, the first item is 0 and would be represented by Strings[0], the second is 1
and would be called with Strings[1], etc. For the following example, when the user clicks
the list box, regarless of the item selected, a label on the form would retrieve the third
item of the list:
//---------------------------------------------------------------------------
void __fastcall TForm1::ListBox1Click(TObject *Sender)
{
Label1->Caption = ListBox1->Items->Strings[2];
}
//---------------------------------------------------------------------------
One of the most effective ways to use the Strings property is to find out the item that the
user would have selected in a list and act accordingly. In the following example, when
the user selects a radio button from a RadioGtroup control, the caption of the button
selected displays on a label:
//---------------------------------------------------------------------------
void __fastcall TForm1::RadioGroup1Click(TObject *Sender)
{
One of the most regular reasons for this operation is to make sure that a string is not
duplicately added to a list that already has the Source argument. In the following
example, when the user types a string in an edit box and clicks soemewhere else (that is,
when the Edit control looses focus), the compiler checks to see if the string in the edit
box already exists in the list. If the list of the combo box does not have the string in the
edit box, then this string is added to the list:
//---------------------------------------------------------------------------
void __fastcall TForm1::edtLaptopExit(TObject *Sender)
{
String Laptop = edtLaptop->Text;
int Exists = cbxNetwork->Items->IndexOf(Laptop);
if( Exists == -1 )
cbxNetwork->Items->Append(Laptop);
}
//---------------------------------------------------------------------------
Some operating system configuration files contain lines with the = symbol as part of a
string. There is no strict rule on what those files are or what they do. The person who
creates such a file also decides what the file is used for and when. For example, a music
program would use such a file to configure the keyboard keys as related to the associated
software. A communication program could use another type of those files as a list or table
of ports. Programmers have to deal with those files for various reasons. Some of those
files have strings made of three parts: Left=Right. The value called Right has to be
assigned to the value on the left. Sometimes the Left value is called a Key; sometimes it
is called a Name. The value on the right of equal is also called a Value. Therefore, a
string on this file would have the form Name=Value. Some of these files have the .INI
extension but can perfectly have any extension the programmer wanted.
Depending on how the file is structured, the programmers have to find a certain key or
name in the list. The TStrings class is equipped with a function that helps with this
operation. The method is the IndexOfName() and its syntax is:
This method takes an AnsiString object as argument. The compiler scans the list looking
for a string that has the form Name=Value. If the left part of a string matches the Name
argument, the IndexOfName() method returns the first position where such a string was
found. The following dialog box is equipped with an edit box and a memo. To add a new
key to the list of keys in the memo, the user types the key in the edit box and clicks the
Add Key button (the Edit control is named edtNewKey, the Memo control is named
mmoConfigure, the button is named is btnAddKey, the bottom Edit control is named
edtFound):
//---------------------------------------------------------------------------
void __fastcall TForm1::btnAddKeyClick(TObject *Sender)
{
String NewKey = edtNewKey->Text;
if(LookFor == -1)
mmoConfigure->Lines->Append(NewKey);
else
edtFound->Text = LookFor;
}
//---------------------------------------------------------------------------
When the user clicks the Add Key button, the Name part, which is the string on the left of
the = symbol of the edit box, is checked for each string in the memo. If no name matches
the Name part of the edit box, the new key is added to the memo. If that Name part is
already in the list, the bottom edit box displays the position of the first string that contains
Name.
Probably the best way to do this, “Live”, is to retrieve the Name part from the string that
the user has typed in the top edit box. The following commented code would accomplish
that:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnAddKeyClick(TObject *Sender)
{
// Get the content of the edit box
String NewKey = edtNewKey->Text;
// Find the position of the first occurence in the edit box
int EqualPos = NewKey.AnsiPos("=");
// Create a string from the beginning to the first occurence of =
String NamePart = NewKey.Delete(EqualPos, NewKey.Length());
// Find out if the Name part of the key is already in the list
int LookFor = mmoConfigure->Lines->IndexOfName(NamePart);
Again, depending on how the list is structured, you can ask the compiler to retrieve the
name part of a string provided its position. This operation is performed using the Names
property. This property is an array of the strings of this type of file. When needed, you
can ask the compiler to give you the name part of a certain line. For example, to retrieve
the name part of the 5th line, you could write Names[4]. If the item at that position does
not have = as part of the string, the compiler would consider that the line is not a valid
IndexOfName string and would void it. In the following example, the 2nd line of
mmoConfigure is examined. If that line is a valid IndexOfName, its Name part displays
in the Found At edit box:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnGetNameClick(TObject *Sender)
{
edtFound->Text = mmoConfigure->Lines->Names[1];
}
//---------------------------------------------------------------------------
By constrast, to retrieve the Value part of an IndexOfName string, use the Values
property. This also is an array of the valid = strings of the list. It uses the following
syntax:
This time, you must (or should) provide the string you are looking for as if it were the
position of the string. This string, which is an AnsiString object, should be the Name part
of a string you are looking for. The compiler would scan the list of strings looking for
valid IndexOfName strings. If it finds a string that encloses an = symbol, then the
compiler would check its Name part. If this Name matches the NamePart of the Values
property, then it would return the Value. This is useful if you want to know whether a
certain key has already been defined in the file. Here is an example:
Note //---------------------------------------------------------------------------
When providing the
void __fastcall TForm1::btnGetValueClick(TObject *Sender)
NamePart as the string
to look for, make sure {
you do not include = as edtFound->Text = mmoConfigure->Lines->Values["Directory"];
part of the string }
//---------------------------------------------------------------------------
Another usefulness of items of a list is to switch their positions as related to each other.
The primary method used to swap items is the Move method. Its syntax is:
This function takes two strings. The first string is considered for its position. When
executing, the function moves the first item from the CurrentPos position to the position
specified by NewPos. The following event would move the 2nd item of a CheckListBox
control to the 5th position:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnMoveClick(TObject *Sender)
{
CheckListBox1->Items->Move(1, 4);
}
//---------------------------------------------------------------------------
After the move, the item at CurrentPos is moved to NewPos. If the item is not move just
one position, all of the items whose positions are between CurrentPos and NewPos are
affected. If the item moved up, the items that were above it would be moved down. The
opposite occurs if the item has move down.
While the Move() method is used to move an item from one position to another, the
Exchange() method is used to switch two items. Its syntax is:
The compiler takes the item at Index1, moves it to Index2, takes the item at that was at
Index2 and moves it to Index one. In the following example, the items at the 4th and the
1st positions are switched:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnExchangeClick(TObject *Sender)
{
CheckListBox1->Items->Exchange(3, 0);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::lstCountriesClick(TObject *Sender)
{
// When a new country is selected, empty the list of cities
lstCities->Clear();
if(Selected == "Portugal")
{
lstCities->Clear();
lstCities->Items->Append("Braga");
lstCities->Items->Append("Coimbra");
lstCities->Items->Append("Viana do Castelo");
lstCities->Items->Append("Aveiro");
}
else if(Selected == "Indonesia")
{
lstCities->Clear();
lstCities->Items->Append("Makassar");
lstCities->Items->Append("Ambon");
lstCities->Items->Append("Kupang");
lstCities->Items->Append("Jakarta");
lstCities->Items->Append("Surabaya");
}
else if(Selected == "Sweden")
{
lstCities->Clear();
lstCities->Items->Append("Upsala");
lstCities->Items->Append("Kalmar");
lstCities->Items->Append("Sundsvall");
lstCities->Items->Append("Tärnaby");
lstCities->Items->Append("Kiruna");
lstCities->Items->Append("Göteborg");
}
else
lstCities->Clear();
}
//---------------------------------------------------------------------------
3. To test the project, on the Debug button, click the Run button.
4. Save your project
This function takes an AnsiString object as argument, which is the FileName. If you want
to open a file whose path you know, you can provide this path as the argument. Here is an
example that fills out a Memo control of a form with the content of a text file:
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Memo1->Lines->LoadFromFile("C:\\Windows\\WINHELP.INI");
}
//---------------------------------------------------------------------------
If you provide the path of a file but the file does not exist, when the user clicks the
button, the application would throw an uncomfortable error. The best alternative is to let
the user select a file using an appropriate dialog box such the Open dialog box. In this
case, the FileName argument would be matched to the content of the dialog box.
Following this code, a Memo control named Memo1 would be filled with the content of a
file opened from an OpenDialog1 and a Button1 controls placed on the form:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnOpenFileClick(TObject *Sender)
{
if(OpenDialog1->Execute())
Memo1->Lines->LoadFromFile(OpenDialog1->FileName);
}
//---------------------------------------------------------------------------
On the other hand, the TStrings class is also equipped with a special method that can be
used to save a file from a Memo or a RichEdit controls. Its syntax is:
This method takes an AnsiString object as the argument, called FileName. This argument
specifies the default name of the file being saved by the user. Here is an example;
//---------------------------------------------------------------------------
void __fastcall TForm1::btnSaveClick(TObject *Sender)
{
if(SaveDialog1->Execute())
Memo1->Lines->SaveToFile(SaveDialog1->FileName);
}
//---------------------------------------------------------------------------
Besides the Memo and RichEdit controls, you can also fill out a list of a control from the
strings of another list. This is mainly performed using the AddStrings() method whose
syntax is:
The argument provided to this string must be a valid string object. Therefore, you should
make sure that the list originates from another list-based control or from another valid
source. The Strings argument could come from a known control. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTransferFileClick(TObject *Sender)
{
Memo2->Lines->AddStrings(Memo1->Lines);
}
//---------------------------------------------------------------------------
Since the TStrings class is a descendent of the TPersistent class, you can also use the
Assign() method. Its syntax is:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTransferFileClick(TObject *Sender)
{
Memo2->Lines->Assign(Memo1->Lines);
}
//---------------------------------------------------------------------------
At any time you can find out how many items compose a list using the Count property.
Not only this property provides an integral count of the members of the list but you can
also use it when scanning the list using a for loop. The fundamental way of using the
Count property is to get the number of items of a list. In the following example, when the
user clicks the Count button, the number of strings in the RadioGroup1 control displays
in the Count edit box:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCountClick(TObject *Sender)
{
edtCount->Text = RadioGroup1->Items->Count;
}
//---------------------------------------------------------------------------
An alternative is to use the Capacity property which fundamentally also provides the
number of items of a list. Its main role is to deal with memory allocation especially when
writing a component that uses a list of items.
If you have two lists and want to compare them, use the Equals() method whose syntax
is:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnCompareListsClick(TObject *Sender)
{
if( !ListBox1->Items->Equals(ListBox2->Items) )
ShowMessage("Both lists are not the same\n"
"You should synchronize them before exiting");
}
//---------------------------------------------------------------------------
The items of a TStrings list are usually text based although they can also be of different
kinds of objects. When the items are made of strings, sometimes you will need to convert
them to a single text. Such is the case when transferring the items of a listbox or a combo
box to a text document or a rich text file. To convert a TStrings list of strings to text, you
should translate the list to a C-based string of objects. This can be done using the
GetText() method whose syntax is:
When this method is called by a TStrings variable, it returns a null-terminated string that
represents all of the items of the text.
To assign a C-based string to a TStrings list of strings, use the SetText() method. Its
syntax is:
You can use these two methods to perform the same transfer or transaction we used to
pass a list of strings from one list to another. Here is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnGetTextClick(TObject *Sender)
{
char *WholeList = Memo1->Lines->GetText();
Memo3->Lines->SetText(WholeList);
}
//---------------------------------------------------------------------------
Even if the controls are different kind, you can use the same transaction. For example, the
following event transfers the content of a listbox to a memo.:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTransToLBXClick(TObject *Sender)
{
char *WholeList = ListBox1->Items->GetText();
Memo3->Lines->SetText(WholeList);
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm2::btnTransferClick(TObject *Sender)
{
Memo1->Lines->Add(ListBox1->Items->Text);
Edit1->Text = ListBox1->Items->Text;
Label1->Caption = ListBox1->Items->Text;
}
//---------------------------------------------------------------------------
As you can see, this transfer is not properly interpreted by the Edit control because this
control does not have a multiple line capability while the WordWrap property helps to
manage the Label control.
Another technique used to most effectively transfer a list from strictly list-based control,
such as a listbox, a combobox or a RadioGroup control to a text based such as a memo or
a RichText control is to use the CommaText property. When called to use this property,
the compiler would scan the list of items. If an item is a one-word string, the compiler
would write a comma “,” on its right and start adding the next item. If the item is a string
made of more than one word, to delimit it, the compiler would enclose it with double-
quotes. This is done until the last string.
In the following example, when the user clicks the Transfer button, the list of items from
the listbox is transferred to both a memo and an edit box using the CommaText property:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnTransferClick(TObject *Sender)
{
Memo1->Lines->Add(ListBox1->Items->CommaText);
Edit1->Text = ListBox1->Items->CommaText;
}
//---------------------------------------------------------------------------
If you decide to dismiss a whole list, use the Clear() method. Its syntax is:
Unlike the Delete() method, the Clear function completely empties the list of items. Here
is an example:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnEmptyTheListClick(TObject *Sender)
{
Memo1->Lines->Clear();
}
//---------------------------------------------------------------------------
The TStringList is derived from the TStrings class and adds new properties and
methods for operations not possible on its parent. This is because the TStrings class can
only fill out a list. It cannot independently manage the items of its own list; it relies on
the control that uses it.
One of the strengths of the TStringList class is that, unlike the TStrings class, it is not
associated with any control, not even a control that creates a list. Therefore, you are in
charge of using it as you see fit. This also allows a TStringList object to accommodate
almost any control that uses a list. It also provides the primary means of exchanging
items among controls of almost various kinds.
To dynamically create a list, you must declare an instance of a TStringList class using
the new operator. If you are planning to use the list inside of only one function or event,
you can initiate the object as follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::CreateAlist()
{
TStringList *Categories = new TStringList;
}
//---------------------------------------------------------------------------
Such a list cannot be accessed outside of the event or function in which you created it. If
you want the list to be available to more than one event or function, create it globally.
This could be done on top of the source file. Here is an example:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TStringList *Categories = new TStringList;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
This time, the list would be available to any event or function of the same source file.
Other objects, events, or fundtions that are part other units (for example if you call this
form from another form) other than this one cannot access the list. The alternative,
sometimes the best one, is to declare the list variable in the header file of the primary unit
that would manipulate or use it. This is done in the private, public or protected sections
of the unit. If only one unit will use this list, declare the variable in the private section.
By contrast, if more than one unit will need it, then declare it in the public section. This
time, since you cannot initialize a variable in a class, only declare a pointer to a
TStringList class. Here is an example:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
private:
TStringList * Categories; // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
After declaring such a variable, you should initialize it in a function or event that would
be called prior to any other event or function using the list. Although this can be done in
the OnCreate() event of a form, probably the safest place to initialize the list is the
constructor of the form. You will use the new operator to initialize the variable. Here is
an example:
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Categories = new TStringList;
}
//---------------------------------------------------------------------------
Once you have created the list locally or globally, you can call any of its properties or
methods to manipulate it.
Like a TStrings list, the primary means of filling out a TStringList list is by using either
the Add() or the Append() method. The Append() method is only inherited. The syntax
of the TStringList::Add() method is:
Once again, each item is added to the list as an AnsiString object. If the addition is
successful, the method returns the position occupied by the Source argument in the list. If
the list was empty, Source would occupy the first position, which is 0 because the list is
zero-based. If the list already had at least one item, the Source argument would be added
to the end of the existing items.
3. To save the project, on the Standard toolbar, click the Save All button
4. Create a new folder called DateAndTime
5. Save the unit as Main
6. Save the project as DateTimeDlg
7. Change the caption of the form to Date and Time and set its BorderStyle
property to bsDialog
8. Change the name of the form to DateAndTime
9. Set the Height property of the form to approximately 266 and its Width to 306
10. Add a Bevel control to the form. Set its Height to approximately 217 and set its
Width to approximately 201
11. Add another Bevel control inside the first one. Set its Style to bsRaised
12. Add a label inside the interior bevel and set its caption to Available Formats:
13. Add a ListBox control under the label but completely inside the interior bevel.
Change the name of the listbox to lstFormats
14. Add a button to the top right section of the form. Set its name to btnOK and its
Default property to true. Change its Caption to OK
15. Add another button under the OK buton. Change its name to btnCancel and set
its Cancel property to true. Change its Caption to Cancel
16. Because the date and time values must be set by the computer at the exact time
the user needs a date or time value for a document, the list of dates and times of
our dialog must be created dynamically.
Double-click an unoccupied area on the form tro access its OnCreate event..
17. Implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TDateAndTime::FormCreate(TObject *Sender)
{
TDateTime TodayDate = Date();
TDateTime RightNow = Time();
DateList->Add(TodayDate);
ShortDateFormat = "m/d/yy";
DateList->Add(TodayDate);
ShortDateFormat = "m/dd/yy";
DateList->Add(TodayDate);
ShortDateFormat = "m/dd/yyyy";
DateList->Add(TodayDate);
ShortDateFormat = "yy/m/dd";
DateList->Add(TodayDate);
DateSeparator = '-';
ShortDateFormat = "yyyy/m/dd";
DateList->Add(TodayDate);
ShortDateFormat = "dd/mmm/yy";
DateList->Add(TodayDate);
LongDateFormat = "dddd";
DateSeparator = ',';
ShortDateFormat = "dddd/ mmmm dd/ yyyy";
DateList->Add(TodayDate);
ShortDateFormat = "mmmm dd/ yyyy";
DateList->Add(TodayDate);
ShortDateFormat = "dddd/ dd mmmm/ yyyy";
DateList->Add(TodayDate);
ShortDateFormat = "dd mmmm/ yyyy";
DateList->Add(TodayDate);
ShortTimeFormat = "h:n:s";
DateList->Add(RightNow);
ShortTimeFormat = "hh:nn:ss";
DateList->Add(RightNow);
LongTimeFormat = "HH:nn:ss";
DateList->Add(RightNow);
lstFormats->Items->AddStrings(DateList);
delete DateList;
DateList = NULL;
}
//---------------------------------------------------------------------------
18. Save your project.
19. To test the dialog box, on the Debug toolbar, click the Run button
The TStrings and the TStringList classes tend to exchange information fairly easily. It is
likely that you will have to use the TStringList class whenever you need a dynamic list.
Then use the TStrings to actually fill a list on a control.
6. To create a list of continents, add a GroupBox control to the top left section of
the form. Change its caption to Continents
7. Add six RadioButton controls named rdoAfrica, rdoAmerica, rdoPacific,
rdoAsia, rdoEurope, and rdoNowhere as follows:
8. Set each radio buttons caption by removing rdo from its name
9. Save the project and test the functionality of the radio buttons by running the
project. Return to Bcb
10. To add our first list control, add a ListBox control under the GroupBox control.
11. Change its name to lstCountries
12. To create five lists variables, on the Class Explorer, expand the Classes folder.
Double-click TfrmMain to access its header file.
//---------------------------------------------------------------------------
#ifndef MainH
#define MainH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TfrmMain : public TForm
{
__published: // IDE-managed Components
TGroupBox *GroupBox1;
TRadioButton *rdoAfrica;
TRadioButton *rdoAmerica;
TRadioButton *rdoAsia;
TRadioButton *rdoEurope;
TRadioButton *rdoPacific;
TRadioButton *rdoNowhere;
TListBox *lstCountries;
private: // User declarations
public:
TStringList* Africa;
TStringList* America;
TStringList* Asia;
TStringList* Europe;
TStringList* Pacific; // User declarations
__fastcall TfrmMain(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TfrmMain *frmMain;
//---------------------------------------------------------------------------
#endif
14. On the Code Editor, click the Main.cpp tab. In the form’s constructor, initialize
the variables as follows:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TfrmMain *frmMain;
//---------------------------------------------------------------------------
__fastcall TfrmMain::TfrmMain(TComponent* Owner)
: TForm(Owner)
{
Africa = new TStringList;
America = new TStringList;
Asia = new TStringList;
Europe = new TStringList;
Pacific = new TStringList;
}
//---------------------------------------------------------------------------
15. Press F12 to access the form. Double-click an empty area on the form to access
its OnCreate event. Implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::FormCreate(TObject *Sender)
{
// Create a list of countries for each continent
Africa->Add("Cameroon");
Africa->Add("Lybia");
Africa->Add("Senegal");
Africa->Add("Botswana");
Africa->Add("Morocco");
America->Add("Argentina");
America->Add("Haiti");
America->Add("USA");
America->Add("Uruguay");
Asia->Add("Thailand");
Asia->Add("Sri Lanka");
Asia->Add("Iraq");
Asia->Add("Japan");
Asia->Add("Bangla Desh");
Europe->Add("Denmark");
Europe->Add("Italy");
Europe->Add("Greece");
Pacific->Add("New Zealand");
Pacific->Add("Australia");
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoAfricaClick(TObject *Sender)
{
lstCountries->Items->AddStrings(Africa);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoAmericaClick(TObject *Sender)
{
lstCountries->Items->AddStrings(America);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoPacificClick(TObject *Sender)
{
lstCountries->Items->AddStrings(Pacific);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoAsiaClick(TObject *Sender)
{
lstCountries->Items->AddStrings(Asia);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoEuropeClick(TObject *Sender)
{
lstCountries->Items->AddStrings(Europe);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
18. Save your project.
19. To test the project, on the main menu, click Run Run.
20. Click various radio buttons and verify that the list of countries changes
everytime a new continent is selected. Actually, we have a small problem. When
a continent is selected, we need to display only the countries that are part of that
continent. Close the form to return to Bcb
21. In the Code Editor, add the highlighted line on top of the OnClick event for each
radio button:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoAfricaClick(TObject *Sender)
{
// When a new continent is selected, empty the list of countries
// to make sure that countries are not mixed
lstCountries->Clear();
lstCountries->Items->AddStrings(Africa);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
22. On the form, double-click the Nowhere radio button to access its OnClick event
and implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoNowhereClick(TObject *Sender)
{
lstCountries->Clear();
}
//---------------------------------------------------------------------------
23. Save your project.
24. Test the project. This time, each radio button controls its list of countries. Close
the form.
25. Now we need to display the countries associated with each continent.
Add a label on the right side of the GroupBox. Set its caption to Cities
26. Add ListBox control to the form. Change its name to lstCities
27. To fill out the list of cities, we will rely on the country that was selected in the
Countries listbox.
On the form, double-click the Countries listbox to access its OnClick event.
Implement it as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::lstCountriesClick(TObject *Sender)
{
// Since a new country has been selected, empty the list of cities
lstCities->Clear();
lstCities->Items->Add("Atlanta");
lstCities->Items->Add("Boston");
lstCities->Items->Add("Miami");
lstCities->Items->Add("San Diego");
lstCities->Items->Add("Chicago");
}
else if(Selected == "Haiti")
{
lstCities->Items->Add("Port-de-Paix");
lstCities->Items->Add("Les Cayes");
lstCities->Items->Add("Jérémie");
lstCities->Items->Add("Port-Au-Prince");
lstCities->Items->Add("Jacmel");
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::FormActivate(TObject *Sender)
{
// Behave as if the Countries list had been clicked
lstCountriesClick(Sender);
}
//---------------------------------------------------------------------------
31. Test the program again. This time, the cities of the country selected always
display in the Cities listbox. Click different countries.
32. Close the form and return to Bcb.
33. Now, we will allow the user to select cities from the Cities listbox and create a
list of cities to visit.
Add a new label to the right side of the Cities label. Set its caption to Selected
34. Add a new ListBox control under the Selected: label. Change its name to
lstSelected
35. Fundamentally, the user can use a button to select a city and put it in a new list.
If the list is empty, the item will be the first in the list. If the list already contains
a city, the new city will be added to the end of the existing one(s). To make our
application more useful, we will let the user decide whether to add the new item
on top or under a selected item already in the list.
Add a new button between the right listboxes. Change its name to
btnAddAbove and set its Caption to >
36. Double-click the new button and implement its OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnAddAboveClick(TObject *Sender)
{
// Since a city was selected, get its string (its name)
AnsiString NewCity =
lstCities->Items->Strings[lstCities->ItemIndex];
39. Test the program. Select different continents, different countries, and different
cities. Also, click the button just added. Observe that, although the button can
create a list of cities effectively, the problem is that it duplicates them. The
application we are creating allows the user to select cities to travel. There is no
reason a city should be added twice: we need to prevent a city from being added
if it exists in the Selected list already.
40. Close the form and return to Bcb.
41. To check whether a city exists already in the Selected list, we will call the
TStrings::IndexOf() by providing the name of the city we are looking for. If
IndexOf() does not find the string, then we will add it.
Change the OnClick event of the AddAbove button as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnAddAboveClick(TObject *Sender)
{
// Since a city was selected, get its string (its name)
AnsiString NewCity =
lstCities->Items->Strings[lstCities->ItemIndex].c_str();
// find out whether the new string already exists in the Selected list
// If if does, we will not add it
if(lstSelected->Items->IndexOf(NewCity) == -1)
{
// add the new item to the end of the list
lstSelected->Items->Add(NewCity);
}
}
//---------------------------------------------------------------------------
42. Test the project again. After making sure that no city gets duplicated in the
Selected list, close the form and return to Bcb.
43. By the way, we had decided to let the user add a city above another city in the
Selected list. This allows the user to prioritize the places to travel. In order to
control this order, the user should first select a city. Using the AddAbove button,
we will insert the new city above the selected one, of course provided the new
city is not already in the Selected list.
Change the OnClick event of the AddAbove button as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnAddAboveClick(TObject *Sender)
{
// Find out if a city is selected in the Cities list
if(lstCities->ItemIndex != -1)
{
// Since a city was selected, get its string (its name)
AnsiString NewCity =
lstCities->Items->Strings[lstCities->ItemIndex].c_str();
// find out whether the new string already exists in the Selected list
// If if does, we will not add it
if(lstSelected->Items->IndexOf(NewCity) == -1)
{
// Now find out if a city was chosen in the Selected list,
if(lstSelected->ItemIndex != -1)
{
// then, allow the user to insert the new item
// on top of the selected one
lstSelected->Items->Insert(lstSelected->ItemIndex, NewCity);
// Select the newly added city
lstSelected->ItemIndex = lstSelected->ItemIndex - 1;
}
else // Since no city was selected, add the new one at the end
{
// add the new item to the end of the list
lstSelected->Items->Add(NewCity);
}
}
}
}
//---------------------------------------------------------------------------
44. Test the project to make sure it works fine. Test that the user can select an
already added city in the Selected list and then insert a city above it. Close the
form to Bcb.
45. Save your project.
46. In the same way, we will allow the user to insert a city under a selected one in
the Selected listbox.
Add a new button under the AddAbove button. Change its name to
btnAddBelow and set its caption to _
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnAddBelowClick(TObject *Sender)
{
if(lstCities->ItemIndex != -1) // find out if a city is selected
{
// Since a city was selected, get its string (its name)
AnsiString NewCity =
lstCities->Items->Strings[lstCities->ItemIndex].c_str();
// find out whether the new string already exists in the Selected list
// If if does, we will not add it
if(lstSelected->Items->IndexOf(NewCity) == -1)
{
if(lstSelected->ItemIndex != -1)
{
// If a city was chosen in the Selected list,
// allow the user to insert the new item on top of the selected one
lstSelected->Items->Insert(lstSelected->ItemIndex + 1, NewCity);
// Select the newly added city
lstSelected->ItemIndex = lstSelected->ItemIndex + 1;
}
else
{
// add the new item to the end of the list
lstSelected->Items->Add(NewCity);
}
}
}
}
//---------------------------------------------------------------------------
48. Since we have allowed the user to add one item at a time, if the user wants to
visit all cities of a certain country, we will let the user select all cities and add
them to the Selected list.
Add a new button under the AddBelow button. Change its name to btnSelectAll
and its caption to >>
49. When the user decides to add all cities to the Selected listbox, although we can
just call the TStrings::AddStrings() method to perform this job, it is possible that
the Selected listbox already contains a certain city the user wants to add. For
example, if a user selects a city X from a country A, then selects another city
from country B, and then comes back to country A, since country A would
display all of its cities, the user would have selected city A already. Once again,
we need to prevent a certain city from being added twice to the Selected list.
Double-click the new button and implement its OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnSelectAllClick(TObject *Sender)
{
// We need to prevent the same city from being added twice
// to the Selected list.
// Initiate a scanning of all items of the Cities list
for(int i = 0; i < lstCities->Items->Count; i++)
{
// Give the name City to each item of the Cities list
AnsiString City = lstCities->Items->Strings[i].c_str();
// Find out if the Selected list is empty
if(lstSelected->Items->Count == 0) // then fill it with the cities
lstSelected->Items->AddStrings(lstCities->Items);
else // Since there is at least one item in the Selected list,
{
// Initiate the process of scanning each item of the Selected list
for(int j = 0; j < lstSelected->Items->Count; j++)
{
// If an item of the Cities list is not in the Selected list,
if(lstSelected->Items->IndexOf(City) == -1 )
{
// then add it to the Selected list, ignoring any match
lstSelected->Items->Add(City);
}
}
}
}
a function that the needed controls can call to check what they want.
On the Class Explorer, right-click the TfrmMain class and click New Method…
52. Set the name to ControlTheLists and make sure the Class Name is TfrmMain.
Set the Function Result to void and click the __fastcall check box. Click OK.
53. Implement the function as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::ControlTheLists()
{
// When a new continent is selected, empty the list of countries
// to make sure that countries are not mixed
lstCountries->Clear();
// Since a new item country has been selected, empty the list of cities
lstCities->Clear();
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoAfricaClick(TObject *Sender)
{
ControlTheLists();
lstCountries->Items->AddStrings(Africa);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoAmericaClick(TObject *Sender)
{
ControlTheLists();
lstCountries->Items->AddStrings(America);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
void __fastcall TfrmMain::rdoPacificClick(TObject *Sender)
{
ControlTheLists();
lstCountries->Items->AddStrings(Pacific);
lstCountries->ItemIndex = 0;
}
//---------------------------------------------------------------------------
// When the user clicks this button, both the Countries and the Cities
// lists are emptied. Therefore, we don't need the AddBelow button
btnAddBelow->Enabled = False;
}
//---------------------------------------------------------------------------
55. At this time, the buttons have been disabled, we need to find out when and
where they should be enabled and disabled.
At the bottom of the OnCreate event of the form, add the following commented
code:
btnSelectAll->Enabled = False;
}
}
//---------------------------------------------------------------------------
57. On the form, double-click the Selected list to access its OnClick event.
Implement it as follows (the comments have been added to explain why):
//---------------------------------------------------------------------------
void __fastcall TfrmMain::lstSelectedClick(TObject *Sender)
{
// Apparently the user has made a selection in the Selected list
// Maybe the user did not select anything. Well, find out
if(lstSelected->ItemIndex != -1)
{
// Since the user made a selection,
// change the caption of the AddAbove button
btnAddAbove->Caption = "^";
// Enable the AddBelow button
btnAddBelow->Enabled = True;
}
}
//---------------------------------------------------------------------------
58. Save your project and test it. Make sure you can add cities. Also make sure that
the selection button are enabled and disabled when necessary. Close the form
59. just as we had allowed the user to add cities to the Selected list, we need to let
the user removed the unneeded cities to create a better list.
Add a new button under the SelectAll button. Change its name to btnRemove
and its caption to R
60. In order to remove a city, the user must have selected one. Therefore, this would
be the first condition to check. Then, since a selected item will have been
removed, we need to select another, just in case the user would like to remove
more than one.
Double-click the R button to access its OnClick event and implement it as
follows:
//---------------------------------------------------------------------------
void __fastcall TForm1::btnRemoveClick(TObject *Sender)
{
// Get the position of the currently selected item
int Selected = lstSelected->ItemIndex;
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnRemoveAllClick(TObject *Sender)
{
// Remove everything from the Selected list
lstSelected->Clear();
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnAddAboveClick(TObject *Sender)
{
btnRemove->Enabled = True;
btnRemoveAll->Enabled = True;
}
//---------------------------------------------------------------------------
66. We know that the user keeps removing items one by one using the R button,
after all items have been removed, we do not need the R-A button. Therefore,
we can disable it as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnMoveUpClick(TObject *Sender)
{
// Just in case the MoveDown button was disabled, if the selected item
// is not at the bottom of the list, then enable the MoveDown button
if(CurItem < lstSelected->Items->Count)
btnMoveDown->Enabled = True;
}
//---------------------------------------------------------------------------
73. Access the form and double-click the MoveDown button. Implement its
OnClick event as follows:
//---------------------------------------------------------------------------
void __fastcall TfrmMain::btnMoveDownClick(TObject *Sender)
{
// Get the position of the currently selected item
int CurItem = lstSelected->ItemIndex;
if(CurItem == HowMany - 1)
{
btnMoveDown->Enabled = False;
lstSelected->ItemIndex = HowMany;
}
else
{
// Swap the selected item to tye one above it
lstSelected->Items->Move(CurItem, CurItem + 1);
// Follow the item that was selected
lstSelected->ItemIndex = CurItem + 1;
}
}
//---------------------------------------------------------------------------
74. Again, we need to decide when and where these buttons should be enabled or
not. Remember that when the user has selected all cities and added them to the
Selected list, a city should be selected. Therefore, it becomes time to enable the
move buttons.
At the bottom of the OnClick event of the SelectAll button, add the following:
15.5 Reviews
15.5.1 Exercises
1. The Table Wizard in Microsoft Access provides two lists of sample tables. Each list is
accessed through a radio button: Business or Personal:
a. To create a new table, the user selects items from the Sample Fields to add them to
the Fields In My New Table list box. If an item gets selected twice, instead of
denying the addition of a duplicate item, the new item is add with an incrementing
integer value. That way, the user can select Address many times and display
Address, Address1, Address2, and so on. Implement such a behavior.
b. If the user selects the same item from the Sample Fields more than once the items are
have the same incrementing name, such as FirstName, FirstName1, FirstName2, and
so on. The Table Wizard provides a Rename Field… button that allows the user to
select a field, that is any field, click this button to call a dialog box to rename the
field. When the dialog box displays, the field that was selected to rename already
fills the edit box on the dialog:
If the user clicks Cancel, nothing would happen and the Rename Field dialog box
would be closed. If the user clicks OK, the new name from the Rename Field would
replace the name that was selected for renaming except... If the name that the user
typed already exists in the Fields In My New Table listbox, a message box would let
the user know:
After the user clicks OK, the Rename Field dialog box display again (with the new
string that the user had typed).
Implement this behavior.
c. To select a field from the Sample Fields, the user can click the > button or double-
click a field in the Sample Fields. Either action adds the selected field to the right
list.
To deselect a field, the user can click the < button or double-click the unwanted field
in the Fields In My New Table.
Implement this behavior.
Index
Button1Click .................................................... 54
A Buttons
Abbreviation .................................................... 11 New Form ................................................... 26
access key ........................................................ 15 Run .............................................................. 79
ActiveX............................................................ 18 C
add ................................................................. 121
alClient........................................................... 408 c_str() ............................................................. 117
Align ................................................................ 35 C++ Builder ................................................... 143
alLeft.............................................................. 410 C++ Builder 5 ................................................. 14
alNone.............................................................. 81 Cancel .............................................................. 66
alphabetical .................................................... 118 categories ......................................................... 27
AnsiCompare ................................................. 126 Classes
AnsiCompare()............................................... 125 AnsiString ................................................. 112
AnsiExtractQuotedStr .................................... 132 TBevel......................................................... 79
AnsiLastChar()............................................... 130 TButton ...................................................... 76
AnsiLowerCase.............................................. 120 TForm.......................................................... 60
AnsiQuotedStr ............................................... 131 TLabel ........................................................ 91
AnsiSameCaption()........................................ 128 TScrollingWinControl................................. 62
AnsiString ........................................................ 87 TSizeConstraits ........................................... 45
AnsiCompare .................................... 125, 126 TUpDown.................................................. 307
Declaring an .............................................. 112 clBlue ............................................................... 44
Delete ........................................................ 130 Click................................................................. 10
LowerCase ................................................ 120 Close .......................................................... 14, 42
Methods Close All .......................................................... 15
AnsiCompareIC ..................................... 126 Code Editor ...................................................... 52
AnsiCompareStr() .................................. 126 combination ................................................... 287
AnsiLastChar ......................................... 130 Command Button ............................................. 66
Pos.......................................................... 133 commitment ..................................................... 28
SubString ............................................... 132 CompareStr().................................................. 126
UpperCase................................................. 120 comparison..................................................... 126
Appending...................................................... 122 compiler ........................................................... 54
AppendStr() ................................................... 122 Component Palette ............................... 18, 25, 66
application........................................................ 25 Additional............................................ 77, 410
application icon................................................ 14 Standard .............................................. 78, 406
Tabs
B Standard ................................................... 27
Bcb............................................................. 11, 50 Win32................................................ 305, 394
behavior ........................................................... 29 computer .......................................................... 25
bevel................................................................. 77 container........................................................... 25
biMaximize .............................................. 42, 287 controls............................................................. 25
Boolean ............................................................ 69 Controls
BorderIcons.................................................... 287 ActionList.................................................... 31
Borland .......................................................... 143 Bevel ........................................................... 78
C++ ............................................................. 25 BorderIcons ................................................. 42
C++ Builder ................................................ 26 Button.................................................... 27, 66
bsDialog........................................................... 43 ColorDialog................................................. 28
bsSizeable ........................................................ 42 Edit ........................................................ 27, 93
btNext ............................................................ 309 Form ............................................................ 26
BeginDrag................................................ 83 U
TCustomEdit .................................................. 95
TfrmMain......................................................... 53 unit ................................................................. 287
this ................................................................... 58 Unit1 ................................................................ 26
title bar ............................................................. 14 UpperCase() ................................................... 119
TLabel user................................................................... 49
Methods
TLabel ..................................................... 91 V
TListColumn.................................................. 408 VCL ............................................................... 131
TListItem ....................................................... 408 VertScrollBar ................................................... 78
tool tip.............................................................. 17 Views
toolbars ............................................................ 16 design .......................................................... 25
Toolbars visual design..................................................... 25
buttons......................................................... 17 vsReport ................................................. 404, 406
list................................................................ 17
Standard ................................................ 25, 26 W
View............................................................ 26
treeview.......................................................... 393 Width ............................................................. 394
TReplaceFlags ............................................... 134 Win32....................................................... 18, 394
TSizeConstraints.............................................. 45 Win95............................................................... 13
TTreeNode..................................................... 400 Windows .................................................. 25, 144
TTreeNodes ................................................... 400 Code Editor ........................................... 52, 70
TWinControl.................................................... 76 wsNormal......................................................... 43
SetFocus................................................... 76