Home

Introduction to Forms

 

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.

After creating the form's resource, you must let the application know that you have a form. To do this, you must call the CreateForm() method of the TApplication class. Its syntax is:

void __fastcall CreateForm(System::TMetaClass* InstanceClass,
			   void *Reference);

The name of the form is passed as a pointer as the second argument. Because the form is being added to the application, giving the application access to it for further operations and processing, the CreateForm() method requires that the class that controls the form be specified. This is normally done by calling the __classid() operator. Once you have specified the form to the application, you must also specify the name of the source file that holds the implementation of the form.

 

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:

TForm Inheritance

Like every other control, the form is equipped with a constructor that allows you to dynamically create it.

Practical LearningPractical Learning: Creating an Application

  1. To start C++Builder, click Start -> (All) Programs -> Embarcadero RAD Studio 2010 -> C++Builder 2010
  2. On the main menu, click File -> New -> Other... 
  3. On the New Items dialog box, click Console Application
     
    New Items
  4. Click OK
  5. In the New Console Application dialog box, accept the C++ radio button and the Use VCL check box.
    Clear the check mark on the Console Application check box
     
  6. Click OK
  7. In the file, before the return 0; line, type Application->Initialize();
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include <windows.h>
    #pragma hdrstop
    
    #include <tchar.h>
    //---------------------------------------------------------------------------
    
    #pragma argsused
    WINAPI WinMain(HINSTANCE hInstance,
    	       HINSTANCE hPrevInstance,
    	       LPSTR lpCmdLine,
    	       int nCmdShow)
    {
    	Application->Initialize();
    	return 0;
    }
    //---------------------------------------------------------------------------

Form Dynamic Creation

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);
}
//---------------------------------------------------------------------------

Customizing a Dynamic Form

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;
	}
}
//---------------------------------------------------------------------------

Introduction to Windows Messages

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).

Practical LearningPractical Learning: Adding a Form to an Application

  1. To add a form to the application, on the main menu, click File -> New -> Form - C++Builder
  2. Note the name of the form as Form1.
    Press F12 to access the Code Editor window
  3. Click the File.cpp tab to access its file and change the content of the file as follows:
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #include <windows.h>
    #pragma hdrstop
    
    #include <tchar.h>
    USEFORM("Unit1.cpp", Form1);
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
    	       LPSTR lpCmdLine, int nCmdShow)
    {
    	Application->Initialize();  
    	Application->CreateForm(__classid(TForm1), &Form1); 
    	Application->Run();
    
    	return 0;
    }
    //---------------------------------------------------------------------------
  4. To test the application, press F9
     
  5. Close it and return to your programming environment

Design and Run Times

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.

Characteristics of Forms

 

Introduction

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:

  • On the main menu, you can click File -> New -> Form - C++Builder
  • On the main menu, you can click File -> New -> Other. Then, in the left list, click C++Builder Files. In the right list, click Form and click OK
  • On the Standard toolbar, you can click the New Items button to display the New Items dialog box from where you would select the Form icon

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 System Icon

The top section of a form or a dialog box is called a title bar:

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:

Load Picture

After selecting the icon and clicking Open, the icon would be made available in the Picture Editor dialog box:

Picture Editor

After clicking OK, the new icon would be used as the system icon of the form:

Title Bar

The System Menu

The icon used on the title bar possesses a menu called the system menu. This menu displays if the user clicks the icon:

System Menu

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.

The Caption

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;
}
//---------------------------------------------------------------------------

The System Buttons

In the right section of the title bar, there are three system buttons that allow minimizing ( or or ), maximizing ( or or ), restoring ( or or ) or closing ( or or ) the form as a window. The presence, absence, or appearance of the system buttons is controlled by the BorderIcons property. To control this property, you can click its + button to expand it to display its four possible values: biSystemMenu, biMinimize, biMaximimize, and biHelp:

Border Icons

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:

biSystemMenu = false

Notice that there is no system button

Border Icons
Border Icons biSystemMenu = true

biMinimize = false

biMaximize = true

Notice that the Minimize button is disabled

biSystemMenu = true

biMinimize = true

biMaximize = false

Notice that the Maximize button is disabled

Border Icons
Border Icons biSystemMenu = true

biMinimize = true

biMaximize = true

Both the Minimize and Maximize buttons are enabled

biSystemMenu = true

biMinimize = false

biMaximize = false

Notice that only the system Close button is available

Border Icons
The biHelp property works only if the form is a dialog box. It does not bear any role on the title bar of a regular form.

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

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:

Position

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:

Position

If you use this technique, the Position property is set to poDesigned.

The Borders

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:

Border Style

The BorderStyle property is an enumeration and you can choose one of its values needed for your form.

By default, a form is designed to be resizable using the bsSizeable value. In this case the user can change its width and its height by dragging one of its borders or corners.

Border Style
Border Style

If you set the BorderStyle property to bsDialog, the user will not be able to resize the dialog. This is the default and the mostly used characteristics for a dialog window. You should always use it if you want the window to be a dialog box.

If you set the BorderStyle property to bsDialog and have a Help file you want to use on the dialog box, you can set the biHelp of the BorderIcons property to true. This would display a What's This button on the title bar.

Border Style
Border Style

A BorderStyle set with bsSingle looks like one set with the bsSizeable. The difference is that the user cannot resize it.

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.

Border Style

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.

A Form whose BorderStyle is set to bsNone has neither a title bar nor borders.

Border Style

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;
}
//---------------------------------------------------------------------------

The Window State of a Form 

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 Body of a Form

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:

Client Area

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.

The Transparency of a Form

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.

The Active Control of a Form

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;
}
//---------------------------------------------------------------------------
 
 
 
 

Previous Copyright © 2010-2011 FunctionX, Inc. Next