Forms Fundamentals
|
Introduction to Form Creation
|
The primary window and the most frequent object you
will use in your applications is the form. If you start a raw application
from a file that implements the _WinMain() function, after creating
an application, the next step you probably take is to create a form.
Because C++Builder provides a rapid application development (RAD)
environment, a form is created in two steps. First you must provide its
resource. This is done by visually adding a form available from clicking
the New Form button on the Standard toolbar or by clicking File -> New ->
Form - C++Builder on the main menu.
|
This is done by calling the USEFORM macro. Its
syntax is:
USEFORM(FileName, FormName)
This macro takes two arguments. The first is a string
that specifies the source file. The second specifies the name of the form
as it appears in the project.
The form in implemented by the TForm class
which itself is derived from TCustomForm. TCustomForm is
derived from the TScrollingWinControl class, which is based on the
TWinControl class:
Like every other control, the form is equipped with a
constructor that allows you to dynamically create it.
Besides designing a form visually, sometimes this will
not be possible. You may have to create the form dynamically. To create a
form dynamically, declare a pointer to a TForm class. If you want
to quickly use a form in a function or an event, you can create it easily.
There are two options you have.
If you want to create a duplicate of the form you
already have, you can use it as the base class and simply create an
instance of the form using the new operator. When dynamically creating a
form, you must specify the object or form that "owns" the form. If you are
creating a duplicate of the form, set the owner as the current form or the
this pointer. The owner is provided to the constructor. For example, to
create a duplicate form using a form's OnDblClick event, you can
implement the event as follows:
//--------------------------------------------------------------------------- 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, every time you do anything on the
form, the duplicate produces the same action. Therefore, the second option
consists of creating a fresh form. Here is an example:
//--------------------------------------------------------------------------- void __fastcall TForm1::FormDblClick(TObject *Sender) { TForm* Former = new TForm(this); } //---------------------------------------------------------------------------
The biggest problem with a locally created form is
that it is available only in the event or the function in which it is
created. If you try to access it outside, you would receive an error. If
you want a form to be available to more than one event or function, you
must create it in a header file of an existing form. 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);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
After declaring the form, 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. Here
is an example:
//---------------------------------------------------------------------------
#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);
}
//---------------------------------------------------------------------------
Whatever technique you use to create your form, you
can set its properties using code. The most basic thing you should do is
to display it. This is done using the TForm::Show() method. If the
form was created locally, you must display it in the function or event
where it was created:
//--------------------------------------------------------------------------- void __fastcall TForm1::FormDblClick(TObject *Sender) { TForm* Former = new TForm(this); Former->Show(); } //---------------------------------------------------------------------------
After creating and using a form, you should make sure
the memory allocated to it is regained. The 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 memory 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; } //---------------------------------------------------------------------------
Imagine you dynamically declare an object, such as a
form, as follows:
//--------------------------------------------------------------------------- class TForm1 : public TForm { ... private: // User declarations TForm* Fake; public: // User declarations __fastcall TForm1(TComponent* Owner); }; //---------------------------------------------------------------------------
We have seen that you can initialize it in the
constructor of the form that owns your object:
//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { Comet = new TForm(Form1); } //---------------------------------------------------------------------------
Once the dynamic object has been initialized you can
display it any time you choose. For example, you can do this when the user
double-clicks in the primary form:
//--------------------------------------------------------------------------- void __fastcall TForm1::FormDblClick(TObject *Sender) { Comet->Show(); } //---------------------------------------------------------------------------
Over all, the C++Builder compiler takes care of
deleting the dynamic object when the form that owns it is closed. If you
want to make sure that your dynamic object is destroyed, you can use the
delete operator as seen above. In reality, since you can use your judgment
to decide when the object would be displayed, when the form that owns it
is closed, before deleting the dynamic object, you can first find out if
the object was really created. This can be performed with a simple if
statement.
The best place to destroy a dynamically created object
that a form owns is when the form is destroyed. When a form is being
closed, it fires the OnDestroy event. This is the favorite place to
perform any housecleaning necessary and related to the form. Based on
this, you can destroy the above Fake object as follows:
//--------------------------------------------------------------------------- void __fastcall TForm1::FormDestroy(TObject *Sender) { if( Fake ) { delete Fake; Fake = NULL; } } //---------------------------------------------------------------------------
As an application receives messages, it processes them
and acts appropriately. For example, the application can be made aware
that the user wants to close it. To process such messages, the
TApplication class uses a method called Run(). Its syntax is:
void __fastcall Run(void);
Therefore, an application should (must) call this
method to process its assignments. If Run() is not called, the
application will compile and execute fine but because it cannot process
messages, it will not display anything (displaying something on the screen
is a message by itself and must be processed).
To create your applications, there are two settings
you will be using. If a control is displaying on the screen and you are
designing it, this is referred to as Design Time. This means that you have
the ability to manipulate the control. You can visually set the control's
appearance, its location, its size, and other necessary or available
characteristics. The design view is usually the most used and the easiest
because you can glance at a control, have a realistic display of the
control and configure its properties. The visual design is the technique
that allows you to visually add a control and manipulate its display. This
is the most common, the most regularly used, and the easiest technique.
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.
|
The form is the primary object of a VCL application. It
is a rectangular window whose main purpose is to carry, host, or hold other
controls to allow the user to interact with the computer. Although there are
various types of parent containers we will use, the form is the most
commonly and regularly used.
If you start a new project from the VCL Forms
Application, it creates a starting form and initializes the application. You
can use such as form as you see fit. If you need additional forms:
Another technique you can use is to create a form
programmatically. To do this, declare a pointer to the TForm class
using the new operator.
The top section of a form or a dialog box is called a
title bar:
On the left side of the form's title bar, there is an
icon. By default, C++Builder uses an icon shipped with the studio. If you
want to use your own icon, you can specify it using the Icon
property. To do this, on the Object Inspector, you can either double-click
the (None) value of the Icon field or click the ellipsis
button of the field. This would open the Picture Editor dialog box. From it,
you can click Load, which would open the Load Picture dialog box. From that
dialog box, locate an icon:
After selecting the icon and clicking Open, the icon
would be made available in the Picture Editor dialog box:
After clicking OK, the new icon would be used as the
system icon of the form:
The icon used on the title bar possesses a menu called
the system menu. This menu displays if the user clicks the icon:
The system menu of the icon's title bar allows the user
to perform the common actions of a regular Windows form. If you do not want
to display the icon and its menu, refer to the section on the BorderIcons
below.
On the right side of the system icon, there is the title
bar. It displays a word or a group of words known as the title or caption of
the form. By default, the title bar displays the name of the form. To
customize the text displayed on the title bar, change the text of the
Caption property.
At design time, you can only set the caption as text in
the Object Inspector. The caption can be any type of string. At run time,
you can control and programmatically display anything on the caption of the
form. It can consist of an expression or the result of a calculation. 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; } //---------------------------------------------------------------------------
In the right section of the title bar, there are three
system buttons that allow minimizing (
The BorderIcons property is a (Pascal-style) set,
which means it can use one or more values in any allowed combination. Each
member of the set can have a true or false value. If you set the
biSystemMenu property to true, regardless of the values of the other
fields of the BorderIcons property, the form would have neither the
system icon (which also makes the system menu unavailable) nor the system
buttons. If a form does not have a system close button, you should make sure
the user has a way to close the form:
Using a combination of the biSystemMenu, the
biMinimize and the biMaximimize properties, you can control the
availability of the system buttons:
You can also programmatically control the system
buttons. Since the BorderIcons property is a set, you must use the
overloaded extractor operators. To remove or set a property to false, use
the >> operator. To include or set a property to true, use the << operator.
For example, to set the biSystemMenu property to false, you can use
code such as:
biSystemMenu = false
is equivalent to:
//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { BorderIcons = TBorderIcons() >> biSystemMenu; } //---------------------------------------------------------------------------
biSystemMenu = true
biMinimize = false biMaximize = true is equivalent to: //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { BorderIcons = TBorderIcons() << biSystemMenu >> biMinimize << biMaximize; } //---------------------------------------------------------------------------
biSystemMenu = true
biMinimize = true biMaximize = false is equivalent to: //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { BorderIcons = TBorderIcons() << biSystemMenu << biMinimize >> biMaximize; } //---------------------------------------------------------------------------
biSystemMenu = true
biMinimize = false biMaximize = false
is equivalent to:
//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { BorderIcons = TBorderIcons() << biSystemMenu >> biMinimize >> biMaximize; } //---------------------------------------------------------------------------
If you do not explicitly define the values of the
BorderIcons, by default, the form would be equipped with all (three)
system buttons.
The position of a form is location it gets when the form
displays to the user. By default, the Microsoft Windows operating system is
configured to assign a location to a new form that displays to the user. In
most cases, this may depend on the type of form and its role in the
application. Fortunately, both the Win32 library and the VCL allow you to
specify where a form should primarily display.
To assist you with the deault location of a form, the
TCustomForm class is equipped with a property named
Position and is of type TPosition:
__property Forms::TPosition Position = {read=FPosition,write=SetPosition};
TPosition is an enumeration with
various values. To visually control the default location of a form, access
the Object Inspector for the form. In the Object Inspector, click Position
then click the arrow of its field:
The operating system has a default location for
applications. If you want to let it decide, select poDefaultPosOnly,
which is the default option anyway. After you have created and designed a
form, when it displays, the operating system respects the size you
specified. If you select the poDefaultSizeOnly option for the
Position propertty, the operating system would use its own default
size and apply it to the form. If you select the the poDefault
option, the operating system would decide about the form's position and
size.
If you want the form to be positioned in the middle of
the screen, select the poDesktopCenter option. The poScreenCenter
option has the same effect if the user has only one monitor. This time, if
the user has two monitors, the operating system will try to position the
form on the monitor set as the default.
If your application is using more than one form, to make
the form(s) other than the first to be positioned in the center of the first
form, select the poMainFormCenter option. If you are using
more than one form, if you create another form and you specified its Owner
argument, to have this other form appear in the middle of its owner, set its
Position as poOwnerFormCenter.
During design, you can manually set the location of a
form. To do this, click the form to select it. In the lower-right corner of
the Code Editor, drag the small rectangle inside the box to a position of
your choice:
If you use this technique, the Position property is set
to poDesigned.
One of the most visual aspects of an object's appearance
is its border. A border is a line that sets the visual limits of an object.
Most objects, including a form, have four borders: left, top, right, and
bottom. In VCL applications, the borders of a form are controlled by a
property called BorderStyle. This is also the main property that
specifies whether you are creating a regular form or a dialog box.
To control the appearance of the borders of your form,
on the Object Inspector, if you click BorderStyle, you would see that
it is a combo box property:
The BorderStyle property is an enumeration and
you can choose one of its values needed for your form.
A floating window is a form used to let the user move it
around while she is working on the main form or dialog. This form is usually
modeless, which means the user does not have to close it to continue
working. If you want to create a floating modeless window, you should set
the form's BorderStyle to bsSizeToolWin. The window has a
short title bar and it can be resized.
Like the sizable tool window, a form with
bsToolWindow has a short title bar and is also a prime candidate for a
floating window. Unlike the form with bsSizeToolWin, the user cannot
resize a bsToolWindow form.
To change a property programmatically, assign one of the
above values to the BorderStyle variable. Here is an example that
would transform the form in a dialog box:
//--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { BorderStyle = bsDialog; } //---------------------------------------------------------------------------
When a form appears as it was designed, it is said to be
"normal". C++Builder allows you to have the form minimized or maximized when
the application is launched. This ability is controlled by the
WindowState property. The default value of this property is wsNormal,
which means the form would appear in a normal fashion. If you want the form
to be minimized or maximized at startup, in the Object Inspector, select the
desired value for the WindowState property.
To control the window's state programmatically, simply
assign the wsMaximized or the wsMinimized value to the
WindowState property. Here is an example:
//--------------------------------------------------------------------------- void __fastcall TForm1::FormCreate(TObject *Sender) { WindowState = wsMaximized; } //---------------------------------------------------------------------------
If you want to check the state of a window before taking
action, simply use a conditional statement to compare its WindowState
property with the wsNormal, the wsMaximized, or the
wsMinimized values. Here is an example:
//--------------------------------------------------------------------------- void __fastcall TForm1::Panel1Click(TObject *Sender) { if( WindowState == wsNormal ) WindowState = wsMaximized; else if( WindowState == wsMaximized ) WindowState = wsMinimized; else WindowState = wsMaximized; } //---------------------------------------------------------------------------
The area that a form makes available to its control is
its body. As the main container of Windows controls, a form provides some
particular properties to the controls it hosts. The client area of a form is
represented by the ClientRect property. This property can be used to
get the dimensions of the body of the form. Like the TControl::ClientRect
property, the TForm::ClientRect property provides the width and the
eight of the client area, omitting the location (left and top) which is set
to the client origin (0, 0) located on the top-left corner of the body of
the form. Alternatively, to get the width of the client area of the form,
you can call the ClientWidth property. To get the height of the
client area, use the ClientHeight. The client aspects can be
illustrated as follows:
Overall, you will hardly be concerned with the
dimensions of the client area, unless you want to draw or render an image.
If you do not have a particular reason, let C++Builder take care of the
client area.
An object is referred to as transparent when you can see
through it. If you are developing for Microsofot Windows 2000 or later,
running on a Pentium processor or equivalent, you can make your form
transparent. To support this, the TCustomForm class is
equipped with a Boolean property named AlphaBlend:
__property bool AlphaBlend = {read=FAlphaBlend,write=SetAlphaBlend};
To specify that you want your form to be transparent,
set the AlphaBlend Boolean property to True from its default False
value. After setting this property is set to true, you can specify how much
transparency. To assist you with this, the TCustomForm class is equipped
with a property named AlphaBlendValue:
__property unsigned char AlphaBlendValue = {read=FAlphaBlendValue, write=SetAlphaBlendValue};
To specify how much transparency to apply, assign a
value that is a BYTE integer between 0 and 255. At 0, you would not see the
form at all. The only presence of the form would be on the taskbar. At 255,
the form would appear as if the property were not applied.
When a form is hosting many controls, it is a good idea
to set the control that has focus when the form opens. This is done using
the form’s ActiveControl property:
__property Controls::TWinControl * ActiveControl = { read=FActiveControl, write=SetActiveControl };
By default, as we know about tab ordering, the order of
controls on a form is directed by the order of adding them to the container.
Even if a control was added last, and regardless of tab ordering, you can
set a certain control to have focus when the form launches.
To set the ActiveControl at design time, give
focus to the form. In the Object Inspector, click the ActiveControl
field and select a control from the list. To programmatically set the active
control, call the TForm::ActiveControl property (actually, the
ActiveControl property belongs to the TCustomForm class). Here is
an example:
//--------------------------------------------------------------------------- void __fastcall TForm1::SetTheActiveControl() { ActiveControl = btnSubmit; } //--------------------------------------------------------------------------- |
No comments:
Post a Comment