Home

Edit Text-Based Controls

 

Edit Boxes

 

Introduction

An edit box is a Windows control used to get or display text for the userís interaction. At its most regular use, an edit box serves as a place to fill out and provide information. Such a use is common on employment applications, login dialog boxes, etc.

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 positioned to the left or the top side of the edit box. From the programmerís point of view, an edit box is a placeholder used for various things. For example, you can show or hide it as you see fit. You can also use it only to display text without allowing the user to change it.

To create an edit box, once again, Borland C++ Builder provides a lot of choices. The most fundamental edit box is designed with the Edit control Edit of the Standard section of the Tool Palette.

Edit Box Characteristics

The most important aspect of an edit box is its text, whether it is displaying or requesting it. This is the Text property. When you add an edit control, C++ Builder initializes it with the name of the control; this would be Edit1 for the first edit box, Edit2 for the second, etc. If you want the control to display some text when the form launches, type the text in the Text property field in the Object Inspector. Otherwise, if you want the edit box to be empty when it comes up for the first time, delete the content of the Text field.

By default, a newly created edit box is used to both display and receive text from the user. If you want to user to read text without being able to change it, set the ReadOnly Boolean property to true. Its default value is false.

As mentioned already, an edit box should be accompanied by a label that indicates what it is used for. To support this relationship, the Label control provides various properties. An accelerator character is a symbol of the label that provides easy access to its edit box. On the label, such a character is underlined. An example would be First Name. The idea is that, if the user presses Alt key in combination with the labelís underlined characters, the edit box it accompanies would receive focus.

To create an accelerator key, choose one of the labelís characters and precede it with an ampersand character when setting its caption. An example would be &First Name. If you want a label to display the accelerator character instead of a plain ampersand, set the labelís ShowAccelChar property to true. If you set it to true but need to display an ampersand, type two & characters where the ampersand would be shown.

The ShowAccelChar property of a label is only used to indicate that the label will display an accelerator character and the & symbol typed on the label creates that accelerator character. To indicate which edit box would receive focus when the accelerator character of the label is invoked; the label control provides the FocusControl property. To use this property, select the label on the container. Then, on the Object Inspector, click the FocusControl field to display its combo box. From there, you can select one of the existing controls. The control, such as an edit box, must be able to receive focus.

The CharCase property of an edit box control allows the content of an Edit control to apply a character case of your choice. The CharCase property is controlled by the TEditCharCase enumerator defined as follows:

enum TEditCharCase { ecNormal, ecUpperCase, ecLowerCase };

By default, it is set to ecNormal, which respects whatever character case is typed in an edit box. Otherwise, you can set it to ecUpperCase or ecLowerCase to set the edit boxí characters to uppercase or lowercase respectively.

Text typed in an edit box appears with its corresponding characters unless you changed the effect of the CharCase property from ecNormal. This allows the user to see and be able to read the characters of an edit. If you prefer to make them un-readable, you can use the PasswordChar property. Although this property is a char type of data, changing it actually accomplishes two things. Its default value is #0, which means that the characters typed in it will be rendered in their alphabetic corresponding and readable characters. If you change it, for example to *, any character typed in it would be un-readable and be replaced by the value of this property. You can use any alphabetic character or digit to represent the characters that would be typed but you must provide only one character. Alternatively, you can specify an ASCII character instead. To do this, type # followed by the number representing the ASCII character. For example, #98 would display b for each character.

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.

One of the actions the user may be asked to perform on an edit box is to type text in it. If the control already contains text, the user can read it. Another common action the user performs is to select text contained in the control. The user must have the option to select only part of the text or its whole content. To do this, the user can click and hold the mouse on one end of the selection and drag to the desired end. This allows for partial selection. The area where the user start dragging during selection is represented by the SelStart property. When the user ends the selections, the length of the text selected is represented by the SelLength property. The portion of text selected is represented by the SelText property, which is an AnsiString type. These properties allow you either to programmatically select text or to get information about text that the user would have selected in the edit box.

Practical Learning Practical Learning: Designing Edit Boxes

  1. Open the Geometry project created in Lesson 19
  2. By selecting the Label and Edit controls from the Standard section of the Tool Palette, design each page as follows:
     
    Control Name Caption/Text Glyph
    Label   Side:  
    Edit edtSquareSide 0.00  
    BitBtn btnCalcSquare Calculate Square
    Label   Perimeter:  
    Edit edtSquarePerimeter 0.00  
    Label   Area:  
    Edit edtSquareArea 0.00  
    Label   Length:  
    Edit edtRectLength 0.00  
    Label   Height  
    Edit edtRectHeight Height:  
    BitBtn btnCalcRectangle Calculate Rectangle
    Label   Perimeter  
    Edit edtRectPerimeter 0.00  
    Label   Area:  
    Edit edtRectArea 0.00  
    Control Name Caption/Text Glyph
    Label   Radius:  
    Edit edtCircleRadius 0.00  
    BitBtn btnCalcCircle Calculate Circle
    Label   Circumference:  
    Edit edtCircleCircumf 0.00  
    Label   Area:  
    Edit edtCircleArea 0.00  
    Label   radius:  
    Edit edtEllipseSRadius 0.00  
    Label   Radius:  
    Edit edtEllipseLRadius 0.00  
    BitBtn btnCalcEllipse Calculate Ellipse
    Label   Circumference:  
    Edit edtEllipseCircumf 0.00  
    Label   Area:  
    Edit edtEllipseArea 0.00  
    Control Name Caption/Text Glyph
    Label   Side:  
    Edit edtCubeSide 0.00  
    BitBtn btnCalcCube Calculate Cube
    Label   Area:  
    Edit edtCubeArea 0.00  
    Label   Volume:  
    Edit edtCubeVolume 0.00  
    Label   Base:  
    Edit edtBoxBase 0.00  
    Label   Height:  
    Edit edtBoxHeight 0.00  
    Label   Width:  
    Edit edtBoxWidth 0.00  
    BitBtn btnCalcBox Calculate Box
    Label   Area:  
    Edit edtBoxArea 0.00  
    Label   Volume:  
    Edit edtBoxVolume 0.00  
  3. Save your project

The Edit Control and its Functionality

The edit control is based on the TEdit class whose immediate parent is TCustomEdit. Like every VCL class, it has a constructor and a destructor. The constructor can be used to dynamically create an edit control. The TEdit class provides other methods derived from the controlís parent or from ancestor classes.

We saw earlier the properties related to the selection of text from an edit control performed either by you or by a user. Alternatively, the user may want to select the whole content of the control. To programmatically select the whole text of an edit control, call the SelectAll() method. Its syntax is:

void __fastcall SelectAll();

The contents of an edit box can be empty or contain some text. If you want it empty, use the Clear() method. This would delete the whole contents of the control:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnClearClick(TObject *Sender)
{
	Edit1->Clear();
}
//---------------------------------------------------------------------------

If the user or another control or action had selected text on the edit control, 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)
{
	Edit1->ClearSelection();
}
//---------------------------------------------------------------------------

Practical Learning Practical Learning: Using Edit Boxes

  1. Display the Quadrilateral tab and double-click the top Calculate button
  2. Implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::btnCalcSquareClick(TObject *Sender)
    {
        double side, perimeter, area;
    
        try {
            side = this->edtSquareSide->Text.ToDouble();
            perimeter = side * 4;
            area = side * side;
    
            this->edtSquarePerimeter->Text = FloatToStr(perimeter);
            this->edtSquareArea->Text = FloatToStr(area);
        }
        catch(EConvertError *err)
        {
            ShowMessage("The value you provided is an invalid number.");
            this->edtSquareSide->Text = "0.00";
            this->edtSquarePerimeter->Text = "0.00";
            this->edtSquareArea->Text = "0.00";
        }
    }
    //---------------------------------------------------------------------------
  3. Return to the Quadrilateral property page and double-click the bottom Calculate button
  4. Implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::btnCalcRectangleClick(TObject *Sender)
    {
        double length, height, perimeter, area;
    
        try {
            length = this->edtRectLength->Text.ToDouble();
            height = this->edtRectHeight->Text.ToDouble();
            perimeter = (length + height) * 2;
            area = length * height;
    
            this->edtRectPerimeter->Text = FloatToStr(perimeter);
            this->edtRectArea->Text = FloatToStr(area);
        }
        catch(EConvertError *err)
        {
            ShowMessage("Incorrect value(s). Please try again."); 
            this->edtRectPerimeter->Text = "0.00";
            this->edtRectArea->Text      = "0.00";
        }
    }
    //---------------------------------------------------------------------------
  5. Return to the form and click the Circular tab
  6. Double-click the top Calculate button and implement its event as follows:
     
    const double myPI = 3.14159;
    //---------------------------------------------------------------------------
    void __fastcall TForm1::btnCalcCircleClick(TObject *Sender)
    {
        double radius, circumference, area;
    
        try {
            radius = this->edtCircleRadius->Text.ToDouble();
            circumference = radius * 2 * myPI;
            area = radius * radius * myPI;
    
            this->edtCircleCircumf->Text = FloatToStr(circumference);
            this->edtCircleArea->Text    = FloatToStr(area);
        }
        catch(EConvertError *err)
        {
            ShowMessage("The value you provided for the radius is incorrect.");
            this->edtCircleRadius->Text  = "0.00";
            this->edtCircleCircumf->Text = "0.00";
            this->edtCircleArea->Text    = "0.00";
        }
    }
    //---------------------------------------------------------------------------
  7. Return to the Circular property page and double-click the bottom Calculate button
  8. Implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::edtCalcEllipseClick(TObject *Sender)
    {
        double smallRadius, largeRadius, circumference, area;
    
        try {
            smallRadius = this->edtEllipseSRadius->Text.ToDouble();
            largeRadius = this->edtEllipseLRadius->Text.ToDouble();
            circumference = (smallRadius + largeRadius) * myPI;
            area = smallRadius * largeRadius * myPI;
    
            this->edtEllipseCircumf->Text = FloatToStr(circumference);
            this->edtEllipseArea->Text    = FloatToStr(area);
        }
        catch(EConvertError *err)
        {
            ShowMessage("Invalid Value(s): Please try again."); 
            this->edtEllipseCircumf->Text = "0.00";
            this->edtEllipseArea->Text    = "0.00";
        }
    }
    //---------------------------------------------------------------------------
  9. Return to the form and click the 3-Dimensional tab
  10. Double-click the top Calculate button and implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::edtCalcCubeClick(TObject *Sender)
    {
        double side, area, volume;
    
        try {
            side   = this->edtCubeSide->Text.ToDouble();
            area   = side * side * 6;
            volume = side * side * side;
    
            this->edtCubeArea->Text = FloatToStr(area);
            this->edtCubeVolume->Text = FloatToStr(volume);
        }
        catch(EConvertError *err)
        {
            ShowMessage("The value you provided for the Side is invalid.");
            this->edtCubeSide->Text   = "0.00";
            this->edtCubeArea->Text   = "0.00";
            this->edtCubeVolume->Text = "0.00";
        }
    }
    //---------------------------------------------------------------------------
  11. Return to the 3-Dimensional property page and double-click the bottom Calculate button
  12. Implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::btnCalcBoxClick(TObject *Sender)
    {
        double base, height, width, area, volume;
    
        try {
            base   = this->edtBoxBase->Text.ToDouble();
            height = this->edtBoxHeight->Text.ToDouble();
            width  = this->edtBoxWidth->Text.ToDouble();
            area   = 2 * ((base*height) + (height*width) + (base*width));
            volume = base * height * width;
    
            this->edtBoxArea->Text   = FloatToStr(area);
            this->edtBoxVolume->Text = FloatToStr(volume);
        }
        catch(EConvertError *err)
        {
            ShowMessage("Invalid Value(s): Please try again."); 
            this->edtBoxArea->Text   = "0.00";
            this->edtBoxVolume->Text = "0.00";
        }
    }
    //---------------------------------------------------------------------------
  13. Execute the application and test each geometric figure
  14. Close the form and return to your programming environment

Edit Control Events

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 a text-based 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:

//---------------------------------------------------------------------------
void __fastcall TfrmPersInfo::edtFirstNameChange(TObject *Sender)
{
	edtFullName->Text = edtFirstName->Text + " " + edtLastName->Text;
}
//---------------------------------------------------------------------------

When the second edit box is being edited, you can implement its OnChange event as follows:

//---------------------------------------------------------------------------
void __fastcall TfrmPersInfo::edtLastNameChange(TObject *Sender)
{
	edtFullName->Text = edtFirstName->Text + " " + edtLastName->Text;
}
//---------------------------------------------------------------------------

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.

 

The Labeled Edit Box

 

Introduction

It is by an unavoidable habit that almost every edit control is accompanied by a label. The reason is that, as stated already when reviewing the edit control, a text box has no mechanism of indicating what it is used for. That precision is usually handled by a label. To make it easy, starting with C++ Builder 6, Borland created a control that combines an edit control and its accompanying label: the LabeledEdit control.

To create a LabeledEdit control, click its button LabeledEdit in the Additional tab of the Tool Palette and add it to a container of your choice.

Characteristics of the Labeled Edit Control

The LabeledEdit control is an object of type TLabeledEdit. This control shares its ancestry with the edit control: their parent is the TCustomEdit class. The TLabeledEdit class itself is derived from the based on the TCustomLabeledEdit class. Based on its ancestry, the LabeledEdit control inherits the same functionality as the edit control.

After adding a LabeledEdit control to your application, you notice that it is accompanied by a label but both are treated as one control. By default, the (accompanying) label is positioned above the edit control. The position of the label is controlled by the LabelPosition property. This property is type TLabelPosition, which is an enumerator. It can have one of four values:

  • lpAbove: (the defualt) Causes the label to be positioned on top of the edit control
  • lpBelow: Causes the label to be positioned under the edit control
  • lpLeft: Positions the label to the left of the edit control
  • lbRight: The label is positioned on the right side of the edit control

If you use a separate label and edit controls in your application, you know that you can decide about the distance between both controls. For a LabeledEdit object, this characteristic is handled by the LabelSpacing property, which is an integer. The default value of this property is 3. In most cases, and especially if you decide to position the label to the left, this value would be too little.

We mentioned that the TLabeledEdit class, on which the LabeledEdit control is based, derived from the TCustomEdit class, which provides functionality only for an edit control. To respect the avoidance of double-inheritance in a VCL control, the LabeledEdit control is equipped with a property called EditLabel. The role of this property is to identify or represent the label part of the LabeledEdit. To support the whole functionality of a label, the EditLabel property is of type TBoundLabel. The TBoundLabel class is derived from the TCustomLabel class, which is the same immediate class of the Label control. Based on this, to perform any label-related operation on a LabeledEdit control, first invoke its EditLabel property and then access any of the properties and characteristics we reviewed for the label control. At design time, the EditLabel property is represented with a + field in the object inspector. As such, you can click the + button:

This allows you to manipulate the label side of the control.

Practical Learning Practical Learning: Using the LabeledEdit Control

  1. Start a new Application with its default form and change the form's BorderStyle to bsDialog
  2. Save the application in a new folder named ColumnChart1
  3. Save the unit as Exercise and the project as ColumnChart
  4. In the Tool Palette, click Additional. Click LabeledEdit LabeledEdit and click form
  5. While the new control is still selected, in the Object Inspector, click Name and type ledMonday
  6. Click the + button of the EditLabel field. Under it, click Caption and type Monday
  7. Complete the design of the form as follows:
     
    Control Caption Text EditLabel=>Caption Name
    Label Furniture Sales      
    LabeledEdit     Monday ledMonday
    LabeledEdit     Tuesday ledTuesday
    LabeledEdit     Wednesday ledWednesday
    LabeledEdit     Thursday ledThursday
    LabeledEdit     Friday ledFriday
    Button Generate     btnGenerate
    PaintBox        
  8. Press F12 to access the Code Editor. In the header file (Exercise.h), declare a private variable as
     
    Graphics::TBitmap *DrawingBoard;
  9. Access the source code of the form and initialize the variable in the constructor as follows:
     
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
        DrawingBoard = new Graphics::TBitmap;
        DrawingBoard->Width  = PaintBox1->Width;
        DrawingBoard->Height = PaintBox1->Height;
    }
    //---------------------------------------------------------------------------
  10. Press F12 to display the form. On the form, click the PaintBox1 control to select it
  11. In the Object Inspector, click the Events tab and double-click the right field to OnPaint
  12. Implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
    {
        PaintBox1->Canvas->Draw(0, 0, DrawingBoard);
    }
    //---------------------------------------------------------------------------
  13. Return to the form and double-click the Generate button
  14. Implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::btnGenerateClick(TObject *Sender)
    {
        this->DrawingBoard->Canvas->Brush->Color = clWhite;
        this->DrawingBoard->Canvas->Brush->Style = bsSolid;
        this->DrawingBoard->Canvas->Pen->Color   = clWhite;
        this->DrawingBoard->Canvas->Rectangle(0, 0, Width, Height);
    
        Invalidate();
    
        int monday    = this->ledMonday->Text.ToInt() / 100;
        int tuesday   = this->ledTuesday->Text.ToInt() / 100;
        int wednesday = this->ledWednesday->Text.ToInt() / 100;
        int thursday  = this->ledThursday->Text.ToInt() / 100;
        int friday    = this->ledFriday->Text.ToInt() / 100;
    
        this->DrawingBoard->Canvas->Brush->Color = clGreen;
        this->DrawingBoard->Canvas->Brush->Style = bsCross;
        this->DrawingBoard->Canvas->Pen->Color   = clBlack;
        this->DrawingBoard->Canvas->Pen->Width = 1;
        this->DrawingBoard->Canvas->Rectangle(ledMonday->Left+20,
                                              PaintBox1->Height-20-monday,
                                              ledMonday->Left+60,
                                              PaintBox1->Height-20);
    
        this->DrawingBoard->Canvas->Brush->Color = clRed;
        this->DrawingBoard->Canvas->Brush->Style = bsBDiagonal;
        this->DrawingBoard->Canvas->Rectangle(ledTuesday->Left+20,
                                              PaintBox1->Height-20-tuesday,
                                              ledTuesday->Left+60,
                                              PaintBox1->Height-20);
    
        this->DrawingBoard->Canvas->Brush->Color = clBlue;
        this->DrawingBoard->Canvas->Brush->Style = bsFDiagonal;
        this->DrawingBoard->Canvas->Rectangle(ledWednesday->Left+20,
                                              PaintBox1->Height-20-wednesday,
                                              ledWednesday->Left+60,
                                              PaintBox1->Height-20);
    
        this->DrawingBoard->Canvas->Brush->Color = clFuchsia;
        this->DrawingBoard->Canvas->Brush->Style = bsDiagCross;
        this->DrawingBoard->Canvas->Rectangle(ledThursday->Left+20,
                                              PaintBox1->Height-20-thursday,
                                              ledThursday->Left+60,
                                              PaintBox1->Height-20);
    
        this->DrawingBoard->Canvas->Brush->Color = clNavy;
        this->DrawingBoard->Canvas->Brush->Style = bsVertical;
        this->DrawingBoard->Canvas->Rectangle(ledFriday->Left+20,
                                              PaintBox1->Height-20-friday,
                                              ledFriday->Left+60,
                                              PaintBox1->Height-20);
    
        this->DrawingBoard->Canvas->Pen->Width = 4;
        this->DrawingBoard->Canvas->MoveTo(PaintBox1->Left+20,
                                           PaintBox1->Height-20);
        this->DrawingBoard->Canvas->LineTo(PaintBox1->Width-5,
                                           PaintBox1->Height-20);
        Invalidate();
    }
    //---------------------------------------------------------------------------
  15. Execute the application and enter some values in the edit boxes before clicking Generate. Here is an example:
     
  16. Close the form and return to your programming environment

The MaskEdit Control

 

Introduction

The MaskEdit is a special Edit object that provides more control over text entered or displaying in an edit box. The biggest difference between the Edit and the MaskEdit controls is the masking possibilities available on the latter.

To add a MaskEdit control to your form, from the Additional tab of the Tool Palette, click the MaskEdit button and click on the form.

MaskEdit Characteristics

The most important property of a MaskEdit control, which sets it apart from the (traditional) Edit control, is its ability to control what the user can and cannot enter in the text side. To configure this text, on the Object Inspector, click the EditMask field to reveal its ellipsis button. You have two options:

  • If you are familiar with the masking properties of this control, you can type a value using the appropriate symbols. Otherwise you should use an appropriate dialog box to guide you. You have two alternatives. You can double-click the empty area of the EditMask field or you can click the ellipsis button. This would call the Input Mask Editor dialog box



    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 desired format 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 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.

    Another alternative is to create your own list of masks. To do this, follow the format used to create a mask. This is:

    Name | Sample | Mask

    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:

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

MaskEdit Methods

On its own, the MaskEdit control has only two methods: the constructor and the destructor. The TMaskEdit constructor is used to dynamically create a MaskEdit object. 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.

MaskEdit Events

The main event of the MaskEdit control occurs when the content of the control has been altered. The compiler takes care of validating the characters and symbols while the user is editing the edit box. When the user has finished and presses Enter or Tab to possibly shift the focus to another control, a notification is sent to the operating system. If the value entered in the control does not conform to the EditMask property, an error is thrown and the application may stop responding. For this reason, you should use the MaskEdit control only when appropriately needed; or you should write an event handler or function that would deal with errors of this control.

The Database Edit Control

 

Introduction

To make it easy to edit single-line text values of a database, the VCL provides the DBEdit control implement through the TDBEdit class that is part of the DBCtrls.hpp library. This control is explicitly made to interpret the value of a database field created using the Alpha, the Date, or the Time data types of a Paradox database. It can also recognize character-based data types of SQL or ADO. The TDBEdit class is derived from the TCustomMaskEdit class.

To add a DBEdit control to your application, click the DBEdit button in the Data Controls tab of the Tool Palette and click the container that would hold it.

Characteristics of the Database Edit Control

The database edit control is meant to hold one line of text. Probably the first action you take to configure it is to specify the source of its value. This is done using the DataSource property, which is a TDataSource value. After pointing out the source of its value, you can specify the particular database field that would feed its value. This done by assigning the name of a field to the DataField property. If you had properly created your database, these two properties may be the only ones you would need to configure.

When a DBEdit control is not empty, the value it holds is represented by the Text property it inherits from the TCustomerMaskEdit class. You can use this property either to change the value in the control or to retrieve the value held by the control.

In most cases, you create an edit control to let the user enter and view data. If you want to prevent the user from entering values in the DBEdit control, you can set its ReadOnly property to false.

If you had created the field as a date-based, time-based, or a specific type of value, and you want to assist the user during data entry, the DBEdit control is equipped with various masks inherited from its parent, exactly like those used on the MaskEdit control. To configure the mask for this control, you must open the table's Field Editor and display the field's properties in the Object Inspector. At any time, to find out if the DBEdit control holds a mask, you can check the value of the Boolean IsMasked property. Keep in mind that this property only lets you know whether the control has a mask. If you want to find what that mask is, in case there is one, you can get the value of the EditMask property of the control through its Field property.

Practical Learning Practical Learning: Using the DBEdit Control

  1. Re-open the CPAS database project
  2. In Class Explorer, right-click TfrmWorkOrders and click New Method...
  3. Set the Method Name to CalculateOrder, its Function Result to void, and check __fastcall
     
  4. Click OK and implement the method as follows:
     
    //----------------------------------------------------------------------------
    void __fastcall TfrmWorkOrders::CalculateOrder()
    {
        //TODO: Add your source code here
        double part1UnitPrice, part1SubTotal, part2UnitPrice, part2SubTotal,
    		    part3UnitPrice, part3SubTotal, part4UnitPrice, part4SubTotal,
    		part5UnitPrice, part5SubTotal, totalParts;
    	 int    part1Quantity = 0, part2Quantity = 0, part3Quantity = 0,
    		    part4Quantity = 0, part5Quantity = 0;
    	 double job1Price = 0.00, job2Price = 0.00, job3Price = 0.00,
    		    job4Price = 0.00, job5Price = 0.00;
    	 double totalLabor;
    	 double taxRate, taxAmount, totalOrder;
    
    	 // Don't charge a part unless it is clearly identified
    	 if( this->EditUnitPrice->Text == "" )
    	 {
    		 this->EditUnitPrice->Text = "0.00";
    		 this->EditQuantity->Text   = "0";
    		 this->EditSubTotal->Text  = "0.00";
    		 part1UnitPrice = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 part1UnitPrice = this->EditUnitPrice->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid unit price");
    			 this->EditUnitPrice->Text = "0.00";
    			 this->EditUnitPrice->SetFocus();
    		 }
    
    		 try {
    			 part1Quantity = this->EditQuantity->Text.ToInt();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Quantity");
    			 this->EditQuantity->Text = "0";
    			 this->EditQuantity->SetFocus();
    		 }
    	 }
    
    	 if( this->EditPartName2->Text == "" )
    	 {
    		 this->EditUnitPrice2->Text = "0.00";
    		 this->EditQuantity2->Text  = "0";
    		 this->EditSubTotal2->Text  = "0.00";
    		 part2UnitPrice = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 part2UnitPrice = this->EditUnitPrice2->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Unit Price");
    			 this->EditUnitPrice2->Text = "0.00";
    			 this->EditUnitPrice2->SetFocus();
    		 }
    
    		 try {
    			 part2Quantity = this->EditQuantity2->Text.ToInt();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Quantity");
    			 this->EditQuantity2->Text = "0";
    			 this->EditQuantity2->SetFocus();
    		 }
    	 }
    
    	 if( this->EditPartName3->Text == "" )
    	 {
    		 this->EditUnitPrice3->Text = "0.00";
    		 this->EditQuantity3->Text  = "0";
    		 this->EditSubTotal3->Text  = "0.00";
    		 part3UnitPrice = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 part3UnitPrice = this->EditUnitPrice3->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Unit Price");
    			 this->EditUnitPrice3->Text = "0.00";
    			 this->EditUnitPrice3->SetFocus();
    		 }
    
    		 try {
    			 part3Quantity = this->EditQuantity3->Text.ToInt();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Quantity");
    			 this->EditQuantity3->Text = "0";
    			 this->EditQuantity3->SetFocus();
    		 }
    	 }
    
    	 if( this->EditPartName4->Text == "" )
    	 {
    		 this->EditUnitPrice4->Text = "0.00";
    		 this->EditQuantity4->Text  = "0";
    		 this->EditSubTotal4->Text  = "0.00";
    		 part4UnitPrice = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 part4UnitPrice = this->EditUnitPrice4->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Unit Price");
    			 this->EditUnitPrice4->Text = "0.00";
    			 this->EditUnitPrice4->SetFocus();
    		 }
    
    		 try {
    			 part4Quantity = this->EditQuantity4->Text.ToInt();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Quantity");
    			 this->EditQuantity4->Text = "0";
    			 this->EditQuantity4->SetFocus();
    		 }
    	 }
    
    	 if( this->EditPartName5->Text == "" )
    	 {
    		 this->EditUnitPrice5->Text = "0.00";
    		 this->EditQuantity5->Text  = "0";
    		 this->EditSubTotal5->Text  = "0.00";
    		 part5UnitPrice = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 part5UnitPrice = this->EditUnitPrice5->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Unit Price");
    			 this->EditUnitPrice5->Text = "0.00";
    			 this->EditUnitPrice5->SetFocus();
    		 }
    
    		 try {
    			 part5Quantity = this->EditQuantity5->Text.ToInt();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Quantity");
    			 this->EditQuantity5->Text = "0";
    			 this->EditQuantity5->SetFocus();
    		 }
    	 }
    
    	 // Don't bill the customer for a job that is not specified
    	 if( this->EditJobPerformed->Text == "" )
    	 {
    		 this->EditJobPrice->Text = "0.00";
    		 job1Price = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 job1Price = this->EditJobPrice->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Job Price");
    			 this->EditJobPrice->Text = "0.00";
    			 this->EditJobPrice->SetFocus();
    		 }
    	 }
    				 
    	 if( this->EditJobPerformed2->Text == "" )
    	 {
    		 this->EditJobPrice2->Text = "0.00";
    		 job2Price = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 job2Price = this->EditJobPrice2->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Job Price");
    			 this->EditJobPrice2->Text = "0.00";
    			 this->EditJobPrice2->SetFocus();
    		 }
    	 }
    
    	 if( this->EditJobPerformed3->Text == "" )
    	 {
    		 this->EditJobPrice3->Text = "0.00";
    		 job3Price = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 job3Price = this->EditJobPrice3->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Job Price");
    			 this->EditJobPrice3->Text = "0.00";
    			 this->EditJobPrice3->SetFocus();
    		 }
    	 }
    
    	 if( this->EditJobPerformed4->Text == "" )
    	 {
    		 this->EditJobPrice4->Text = "0.00";
    		 job4Price = 0.00;
    	 }
    	 else
    	 {
    		 try {
    			 job4Price = this->EditJobPrice4->Text.ToDouble();
    		 }
    		 catch(EConvertError *)
    		 {
    			 ShowMessage("Invalid Job Price");
    			 this->EditJobPrice4->Text = "0.00";
    			 this->EditJobPrice4->SetFocus();
    		 }
    	 }
    				 
    	 part1SubTotal = part1UnitPrice * part1Quantity;
    	 part2SubTotal = part2UnitPrice * part2Quantity;
    	 part3SubTotal = part3UnitPrice * part3Quantity;
    	 part4SubTotal = part4UnitPrice * part4Quantity;
    	 part5SubTotal = part5UnitPrice * part5Quantity;
    
    	 this->EditSubTotal->Text  = FloatToStrF(part1SubTotal, ffFixed, 8, 2);
    	 this->EditSubTotal2->Text = FloatToStrF(part2SubTotal, ffFixed, 8, 2);
    	 this->EditSubTotal3->Text = FloatToStrF(part3SubTotal, ffFixed, 8, 2);
    	 this->EditSubTotal4->Text = FloatToStrF(part4SubTotal, ffFixed, 8, 2);
    	 this->EditSubTotal5->Text = FloatToStrF(part5SubTotal, ffFixed, 8, 2);
    
    	 totalParts    = part1SubTotal + part2SubTotal + part3SubTotal +
    			 part4SubTotal + part5SubTotal;
    				 
    	 totalLabor    = job1Price + job2Price + job3Price +
    		             job4Price + job5Price;
    				 
    	 try {
    		 taxRate = this->EditTaxRate->Text.ToDouble();
    	 }
    	 catch(EConvertError *)
    	 {
    		 ShowMessage("Invalid Tax Rate");
    		 this->EditTaxRate->Text = "7.75";
    		 this->EditTaxRate->SetFocus();
    	 }
    				 
    	 double totalPartsAndLabor = totalParts + totalLabor;
    	 taxAmount  = totalPartsAndLabor * taxRate / 100;
    	 totalOrder = totalPartsAndLabor + taxAmount;
    				 
    	 this->EditTotalParts->Text = FloatToStrF(totalParts, ffFixed, 8, 2);
    	 this->EditTotalLabor->Text = FloatToStrF(totalLabor, ffFixed, 8, 2);
    	 this->EditTaxAmount->Text  = FloatToStrF(taxAmount,  ffFixed, 8, 2);
    	 this->EditOrderTotal->Text = FloatToStrF(totalOrder, ffFixed, 8, 2);
    }
    //----------------------------------------------------------------------------
  5. Return to the form and click the Qty control corresponding to the first part used
  6. In the Object Inspector, click the Events tab and double-click the event of the OnExit field
  7. Implement it as follows:
     
    //----------------------------------------------------------------------------
    void __fastcall TfrmWorkOrders::EditQuantityExit(TObject *Sender)
    {
        CalculateOrder();
    }
    //---------------------------------------------------------------------------
  8. Return to the form. Click each Qty and, in the Events tab of the Object Inspector, select EditQuantityExit in the combo box
  9. In the Jobs Performed section, click each control under Job Price and, in the Object Inspector, select EditQuantityExit in the OnExit event
  10. Execute the application to test it
  11. Update the first order as follows:
     
  12. Click the Post Edit button
  13. Close the form and return to your programming environment

Methods and Events of the Database Edit Control

The DBEdit control inherits most of its methods and properties from its parents: The TCustomMaskEdit and the TCustomEdit classes. We had already reviewed them for the Edit control.

The IP Address Control

 

Introduction

The IP Address control is an object that allows the user to enter an IP address or you to retrieve one. The control appears like an edit box or a masked edit box divided in four (semi-independent) sections:

The IP Address control is aware of the basic rules of IP address formatting. To proceed with the control, the user can click the first field and start typing. Each section allows only digits. By default, the control is configured to allow only numbers that range from 0 to 255 but you the programmer can change this allowed range. It does not allow a negative character. If the user enters a value higher than the allowed, the number is reset. Each field can allow only three digits. Once a valid value has been entered in a field, the focus shifts to the next section to the right.

Operations on an IP Address Control

To create an IP Address control, you can either use the traditional Win32 approach or create your own component that would implement the behavior set by the Win32 API. Because in this book we will not create custom components, we will use the Win32 technique. Therefore, to create an IP Address control, call the CreateWindow() or the CreateWindowEx() function and specify the class name as WC_IPADDRESS. 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
	void __fastcall FormCreate(TObject *Sender);
private:
	HWND hWndIPAddress; // User declarations
public: // User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	hWndIPAddress = CreateWindowEx( 0,
					WC_IPADDRESS,
					NULL,
					WS_CHILD | WS_VISIBLE | WS_TABSTOP,
					90, 14, 120, 20,
					Handle,
					NULL,
					HInstance,
					NULL );
}
//---------------------------------------------------------------------------

Some of the jobs you will perform on an IP Address control consist of checking whether the control contains an address, setting an IP address in its fields, retrieving the current address from its fields, or deleting an address from its fields.

Before doing anything on an IP Address control, you may want to check whether its fields are filled with some entries. To do this, you can send an IPM_ISBLANK message using the SendMessage() function. Because you are only checking the contents of the control, the wParam and the lParam parameters are not used and must be passed with 0 values. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormDblClick(TObject *Sender)
{
	BOOL IsThereAnAddress = SendMessage(hWndIPAddress, IPM_ISBLANK, 0, 0);

	if( IsThereAnAddress == True )
		ShowMessage("There is no IP address");
}
//---------------------------------------------------------------------------

On the other hand, if the control already contains an IP address, whether it is complete or not, before performing such operations as changing its values or else, you may want to completely delete the current IP address. This is done by sending an IPM_CLEARADDRESS message to the control using the SendMessage() function. The wParam and the lParam parameters are not used and will be passed as 0. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	SendMessage(hWndIPAddress, IPM_CLEARADDRESS, 0, 0);
}
//---------------------------------------------------------------------------

By default, when the IP Address control is created, it is blank: its field do not contain values. Whether the control is empty or not, if you want to fill it up, you must first create an address. This is done by calling the MAKEIPADDRESS macro. Its syntax is:

LPARAM MAKEIPADDRESS(BYTE b0, BYTE b1, BYTE b2, BYTE b3);

This macro simply requires 4 byte values as arguments. Each value should range from 0 to 255. Here is an example:

MAKEIPADDRESS(212, 56, 198, 92);

The MAKEIPADDRESS macro is only used to create an address. If you want to pass that address to an IP Address control, you can send it an IPM_SETADDRESS message using the SendMessage() function. The wParam argument is not used and must be passed as 0. The address to be set is passed as the lParam argument, which results from a call to the MAKEIPADDRESS macro. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	LPARAM lpAdr = MAKEIPADDRESS(212, 56, 198, 92);

	hWndIPAddress = CreateWindowEx( 0,
					WC_IPADDRESS,
					NULL,
					WS_CHILD | WS_VISIBLE | WS_TABSTOP,
					90, 14, 120, 20,
					Handle,
					NULL,
					HInstance,
					NULL );

	SendMessage(hWndIPAddress, IPM_SETADDRESS, 0, lpAdr);
}
//---------------------------------------------------------------------------

If the control already contains an address and you want to retrieve it, send it an IPM_GETADDRESS message using the SendMessage() function. The syntax you would use is:

lResult = SendMessage((HWND) hWndControl,
		      (UINT) IPM_GETADDRESS,
		      0,
		      (LPARAM) lParam);

This version of the SendMessage() function returns the number of non-empty fields of the address. Each one of the four fields of an IP address has a particular value. The values of these fields can be identified using the following macros:

BYTE FIRST_IPADDRESS(LPARAM lParam);
BYTE SECOND_IPADDRESS(LPARAM lParam);
BYTE THIRD_IPADDRESS(LPARAM lParam);
BYTE FOURTH_IPADDRESS(LPARAM lParam);

Each one of these macros retrieves the value stored in their respective fields. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	DWORD CurAddress;

	LRESULT SM = SendMessage(hWndIPAddress, IPM_GETADDRESS, 0,
				(LPARAM)(LPDWORD)&CurAddress);

	BYTE IPPart1 = FIRST_IPADDRESS((LPARAM)CurAddress);
	BYTE IPPart2 = SECOND_IPADDRESS((LPARAM)CurAddress);
	BYTE IPPart3 = THIRD_IPADDRESS((LPARAM)CurAddress);
	BYTE IPPart4 = FOURTH_IPADDRESS((LPARAM)CurAddress);

	ShowMessage("First:\t\t" + AnsiString(IPPart1) + "\n" +
		    "Second:\t\t" + AnsiString(IPPart2) + "\n" +
		    "Third:\t\t" + AnsiString(IPPart3) + "\n" +
		    "Fourth:\t\t" + AnsiString(IPPart4) + "\n" +
		    "Non-Blank Fields: " + AnsiString(SM));
}
//---------------------------------------------------------------------------

When the fields of an IP Address control are empty, the user can fill them up with some vales. To use it, the user must give it focus and start typing. Once he has provided the three digits of a field, the caret moves to the next field. This is automatically done. If you want to programmatically set the focus to a particular field in response to some userís action, you can send an IPM_SETFOCUS message to the control. The fields of the control are in a zero-based array where the most left field has an index of 0 and the most right field has an index of 3. To set focus to a field, pass its index as the wParam parameter. The lParam parameter is not used.

By default, each field of an IP address has a range of values from a minimum whose default value is 0 and a maximum whose default value is 255. The control is so much aware of these values that, if the user tries entering a value that is lower than the set range, the control would not respond. For example if the user tries typing Ė for a negative value, it would not be accepted. On the other hand, if the user tries to enter a value that is higher than the range, the control would reset the field to the set maximum. If you want to control the range of values allowed in a particular field, create it using the MAKEIPRANGE macro. Its syntax is:

LPARAM MAKEIPRANGE(BYTE low, BYTE high);

The MAKEIPRANGE macro is only used to create a range of values. In order to actually assign this range to an IP Address control, send an IPM_SETRANGE message to the control using the SendMessage() function. The wParam parameter is used to specify the index of the field whose range you want to set. The lParam parameter contains the new range set by the return value of the MAKEIPRANGE macro. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	LPARAM wRangeForField3 = MAKEIPRANGE(52, 212);

	hWndIPAddress = CreateWindowEx( 0,
					WC_IPADDRESS,
					NULL,
					WS_CHILD | WS_VISIBLE | WS_TABSTOP,
					90, 14, 120, 20,
					Handle,
					NULL,
					HInstance,
					NULL );

	SendMessage(hWndIPAddress, IPM_SETRANGE, 2, wRangeForField3);
}
//---------------------------------------------------------------------------

Normally, you will usually need to control the range of values for a field in response to the userís entry in the previous field. This assignment is not handled by the control because it lets the programmer take this role and responsibility.

IP Address Control Events

Although the IP Address control is not an edit box, both share a few characteristics such as their appearance. Like every visual and non-static control, in order to use an IP Address control, the user must give it focus. This can be done by clicking a field in the control. When the IP Address control receives focus, it sends an EN_SETFOCUS message, which produces an event similar to the Edit controlís OnEnter() event.

Like the edit control, when the user starts typing a new value in the IP Address control, it sends an EN_CHANGE message which produces an OnChange() event (similar to that of the Edit control). If the user starts changing the value of a field, the control sends the IPN_FIELDCHANGED notification message.

If the user clicks away, which causes the control to lose focus, it sends an EN_KILLFOCUS message. This produces an event similar to the OnExit() event of the VCLís Edit control.

 

 
Previous Copyright © 2005 Yevol Next