Home

Progress-Based Controls

 

Timers

 

Introduction

A timer is a non-spatial object that uses recurring lapses of time in a computer or in your application. To work, every lapse of period, the control sends a message to the operating system. The message is something to the effect of "I have counted the number of lapses you asked me to count".

As opposed to the time that controls your computer, a timer is partly but greatly under your control. Users do not see nor do they use a timer as a control. As a programmer, you decide if, why, when, and how to use this control.

 

Practical Learning Practical Learning: Introducing the Timer Control

  1. Start a new application with the default form
  2. Save it in a new folder named TrafficLight1
  3. Save the unit as Exercise and save the project as TrafficLight
  4. Change the Caption of the form to Traffic Light
  5. Change its BorderStyle property to bsDialog
  6. Change its dimensions to Height = 256 and Width = 112
  7. From the Statndard tab of the Tool Palette, double-click the Panel control
  8. Change the properties of the panel as follows:
    BevelInner = bvNone
    BevelOuter = bvLowered
    BevelWidth = 5
    Caption = Empty
    Color = clBlack
    Height = 209
    Left = 17
    Top = 8
    Width = 81
  9. While the panel is still selected on the form, from the Additional tab of the Tool Palette, double-click the Shape control
  10. Change the following properties for the new Shape:
    Brush: Color = clGray
    Brush: Style = bsSolid
    Height = 65
    Left = 8
    Top = 8
    Width = 65
  11. On the panel, click the newly added Shape to make sure it is selected. Press Ctrl + C to copy it to the clipboard
  12. Click anywhere on the panel to select it
  13. Press Ctrl + V to paste the Shape
  14. While the new Shape is still selected, change its Left value to 8 and its Top value to 72
  15. Click an empty area on the panel to select it and press Ctrl + V
  16. While the new shape is still selected, change its Left value to 8 and its Top value to 136
  17. Click the panel on the form and ress Ctrl + V again
  18. Change the properties of the new shape as follows:
    Brush: Color = clRed
    Height = 57
    Left = 8
    Name = shpRed
    Shape = stCircle
    Top = 12
  19. On the form, click the red circle and press Ctrl + C. Then press Ctrl + V to add a new Shape
  20. Change its properties as follows:
    Brush: Color = clSilver
    Height = 57
    Left = 8
    Name = shpYellow
    Shape = stCircle
    Top = 76
  21. On the form, click the Panel and press Ctrl + V
  22. Change the properties of the new Shape to:
    Brush: Color = clSilver
    Height = 57
    Left = 8
    Name = shpGreen
    Shape = stCircle
    Top = 140
  23. Save All

Characteristics of a Timer

The timer in VCL applications is made available through the TTimer class. To add it to your application at design time, from the System property page of the Tool Palette, click Timer and click on the form.

The Interval

The Timer control has two properties that are particularly important for its functionality. A timer is an object used to count lapses of time and send a message when it has finished counting. The amount of time allocated for counting is called an interval. The Interval is probably the most important characteristic of the Timer control because it measures and controls the total time needed to perform a complete count. The Interval is measured in milliseconds. Like any counter, the lower the value, the faster the count will finish, and the higher the value, the longer the count (if you ask one kid to count from 1 to 10 and you ask another to count from 1 to 20 and shout when finished, the first kid would finish first and would shout first). The amount of interval you specify will depend on what you are trying to do.

Enabled

One of the uses you can make of a Timer control is to decide when it should start counting. In some applications, you may want the control to work full-time while in some other applications, you may want the control to work only in response to an intermediate event. The ability to stop and start a Timer control is set using the Enabled Boolean property. When, or as soon as, this property is set to true, the control starts counting. If, when, or as soon as, the Enabled property is set to false, the control stops and resets its counter to 0.

Practical Learning Practical Learning: Using Timer Controls

  1. From the System tab of the Tool Palette, double-click Timer 
  2. On the Object Inspector, click the Events tab
  3. Although the dialog box will be equipped with the system Close button, we should provide our own mean of closing the application
  4. On the form, click the red circle
  5. Press and hold Shift, then click the other two circles
  6. On the Object Inspector, double-click the empty area on the right side of OnMouseDown
  7. Change the event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::shpGreenMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	Close();
    }
    //---------------------------------------------------------------------------
  8. Press F12 to display the form
  9. Double-click the Timer on the form to access its OnTimer event
  10. Change its code as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    	// If the current color is red
    	if( shpRed->Brush->Color == clRed )
    	{
    		// Change the color to green
    		Timer1->Interval = 3500;
    		shpRed->Brush->Color = clSilver;
    		shpYellow->Brush->Color = clSilver;
    		shpGreen->Brush->Color = clGreen;
    	}
    	// But if the color is green
    	else if( shpGreen->Brush->Color == clGreen )
    	{
    		// Change the color to yellow
    		Timer1->Interval = 2000;
    		shpRed->Brush->Color = clSilver;
    		shpYellow->Brush->Color = clYellow;
    		shpGreen->Brush->Color = clSilver;
    	}
    	// Otherwise, if the color is yellow
    	else // if(shpYellow->Brush->Color == clYellow
    	{
    		// Change the color to red
    		Timer1->Interval = 5000;
    		shpRed->Brush->Color = clRed;
    		shpYellow->Brush->Color = clSilver;
    		shpGreen->Brush->Color = clSilver;
    	}
    }
    //---------------------------------------------------------------------------
  11. Test your program
     
  12. Close it and return to Borland C++ Builder
  13. Save All

The Tick Counter

The Win32 API provides a special function used to count a specific number of lapses that have occurred since you started your computer. This information or counter is available through the GetTickCount() function. Its syntax is:

DWORD GetTickCount(VOID);

This function takes no argument. If it succeeds in performing its operation, which it usually does, it provides the number of milliseconds that have elapsed since you started your computer. Just like the VCL Timer control, what you do with the result of this function is up to you and it can be used in various circumstances. For example, computer games and simulations make great use of this function.

After retrieving the value that this function provides, you can display it in a text-based control. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::btnElapsedClick(TObject *Sender)
{
	unsigned long Elapsed = GetTickCount();
	edtElapsed->Text = IntToStr(Elapsed);
}
//---------------------------------------------------------------------------

Practical Learning Practical Learning: Counting the Computer's Ticks

  1. Start a new application with the default form
  2. Save it in a new folder named CompTicks1
  3. Save the unit as Exercise and save the project CompTicks
  4. Design the form as follows:
     
  5. Set its BorderStyle to bsDialog
  6. Change its name to frmMain and set its Caption to Counting Computer Ticks
  7. Add a GroupBox control GroupBox and set its Caption to Elapsed Time
  8. Add a Timer control Timer from the System tab of the Tool Palette
  9. Set its Interval to 20
  10. Add an Edit control Edit and change its Name to edtComputerTime
  11. Add another Edit control Edit and change its Name to edtApplicationTime
  12. Press F12 to access the Code Editor. In the private section of the form, declare an unsigned integer as follows:
     
    private:
    	unsigned int TimeTheComputerStarted; // User declarations
    public: // User declarations
    	__fastcall TfrmMain(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
  13. On the form, double-click the Timer1 icon to access its OnTimer event and implement the source file as follows:
     
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TfrmMain *frmMain;
    //---------------------------------------------------------------------------
    __fastcall TfrmMain::TfrmMain(TComponent* Owner)
    	: TForm(Owner)
    {
    	TimeTheComputerStarted = GetTickCount();
    }
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::Timer1Timer(TObject *Sender)
    {
    	unsigned long CurrentTickValue = GetTickCount();
    	unsigned int Difference = CurrentTickValue - TimeTheComputerStarted;
    
    	edtComputerTime->Text = IntToStr(CurrentTickValue);
    	edtApplicationTime->Text = IntToStr(Difference);
    }
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::BitBtn1Click(TObject *Sender)
    {
    	Close();
    }
    //---------------------------------------------------------------------------
  14. Press F9 to test the application
     
  15. After testing the application, close it and return to Borland C++ Builder
  16. To make the values easier to read, change the form as follows. Delete both Edit boxes and replace them with Label controls named lblComputerTime and lblApplicationTime respectively:
     
  17. Change the code of the OnTimer event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::Timer1Timer(TObject *Sender)
    {
    	unsigned long CurrentTickValue = GetTickCount();
    	unsigned int Difference = CurrentTickValue - TimeTheComputerStarted;
    
    	unsigned int ComputerHours, ComputerMinutes, ComputerSeconds;
    	unsigned int ApplicationHours, ApplicationMinutes, ApplicationSeconds;
    
    	ComputerHours = (CurrentTickValue / (3600 * 999)) % 24;
    	ComputerMinutes = (CurrentTickValue / (60 * 999)) % 60;
    	ComputerSeconds = (CurrentTickValue / 999) % 60;
    	ApplicationHours = (Difference / (3600 * 999)) % 24;
    	ApplicationMinutes = (Difference / (60 * 999)) % 60;
    	ApplicationSeconds = (Difference / 999) % 60;
    
    	AnsiString ComputerTime, ApplicationTime;
    
    	ComputerTime = IntToStr(ComputerHours) + " hours, " +
    	IntToStr(ComputerMinutes) + " minutes " +
    	IntToStr(ComputerSeconds) + " seconds";
    	ApplicationTime = IntToStr(ApplicationHours) + " hours " +
    	IntToStr(ApplicationMinutes) + " minutes " +
    	IntToStr(ApplicationSeconds) + " seconds";
    
    	lblComputerTime->Caption = ComputerTime;
    	lblApplicationTime->Caption = ApplicationTime;
    }
    //---------------------------------------------------------------------------
  18. Test the application
     
  19. After testing the application, close it
  20. Save All

Progress Bars

 

Overview

A progress bar is a control that displays (small) rectangles that are each filled with a color. These (small) rectangles are separate but adjacent each other so that, as they display, they produce a bar. To have the effect of a progress bar, not all these rectangles display at the same time. Instead, a numeric value specifies how many of these (small) rectangles can display at one time.

There are two types of progress bars and various characteristics they can have. For example, although most progress bars are horizontal, the control can assume a vertical orientation:

As mentioned already, a progress bar is made of small colored rectangles. These rectangles can display distinctively from each other although they are always adjacent. The programmer can also specify what color would fill the small rectangles. To make it less confusing, all of the small rectangles display in the same color. The small rectangles can be "glued" to produce a smooth effect, in which case they would not appear distinct.

To create a progress bar, use the ProgressBar control ProgressBar from the Win32 tab.

Practical Learning Practical Learning: Introducing Progress Bars

  1. Start a new project with its default form
  2. Save it in a new folder named BodyMonitor1
  3. Save the unit as Exercise and save the project as BodyMonitor
  4. Open Image Editor. Design a 32 x 32 icon and its associated 16 x 16 icon as follows:
     
  5. Save it as BMon
  6. Open the Project Options dialog. In the Application property page, set the title to Body Monitor Simulation
  7. Change the icon to the above
  8. Change the form’s properties as follows:
    Name: frmMain
    Caption: Body Monitoring
    ShowHint: true
    Position: poScreenCenter
  9. Save All

Progress Bar Properties

By default, a newly added progress bar assumes a horizontal position. This aspect is controlled by the Orientation property which is a TProgressBarOrientation enumerator defined as follows:

enum TProgressBarOrientation { pbHorizontal, pbVertical };

The default value of the Orientation property is pbHorizontal. This is equivalent to not specifying an orientation when programmatically creating the control using either the VCL or the Win32 libraries. If you want the progress bar to appear vertical, at design time, set the Orientation value to pbVertical. If you are creating the progress bar using the Win32 library, OR the PBS_VERTICAL style. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	CreateWindowEx(0, PROGRESS_CLASS, NULL,
		       WS_CHILD | WS_VISIBLE | PBS_VERTICAL,
		       20, 20, 18, 170,
		       Handle, NULL, HInstance, NULL);
}
//---------------------------------------------------------------------------

As mentioned already, a progress bar appears as a series of small adjacent rectangles. By default, these rectangles display distinctively. If on the other hand you want to “glue” them and produce a smooth bar, use the Smooth Boolean property whose default value is false, making the small rectangles separate. If you set this property to true, the bar would appear continuous. If creating the control using the CreateWindow() or CreateWindowEx() Win32 function, you can OR the PBS_SMOOTH style.

To display its small rectangles or the smooth bar, the progress bar uses a preset color, which is usually blue. If you prefer to use a different color, call the SendMessage() function with the PBM_SETBARCOLOR message. The syntax you would is:

SendMessage(HWND hWnd,
	    PBM_SETBARCOLOR,
	    wParam = 0,
	    lParam = (LPARAM)(COLORREF)clrBar;

As you can see from this syntax, the wParam argument is not used and must be passed as 0. The desired color for the bar is specified using the lParam argument. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	SendMessage(ProgressBar1->Handle, PBM_SETBARCOLOR, 0, clRed);
}
//---------------------------------------------------------------------------

To show its effect, the progress bar draws its small rectangles on a bar. These small shapes are from a starting position to an end. This means that the progress bar uses a range of values. This range is controlled by the Min and the Max properties whose default values are 0 and 100 respectively. At design time, you can set them using the limits of an unsigned short integer, that is, from 0 to 65,535. In Win32, the range of values of a progress bar is set using the PBM_SETRANGE message using the following syntax:

SendMessage(HWND hWnd,
	    PBM_SETRANGE,
	    wParam = 0,
	    lParam = MAKELPARAM(nMinRange, nMaxRange);

Alternative, you can send the PBM_SETRANGE32 message to set the range of the progress bar. This time, the syntax used would be:

SendMessage(HWND hWnd,
	    PBM_SETRANGE32,
	    wParam = (WPARAM)(int) iLowLim,
	    lParam = (LPARAM)(int) iHighLim);

For a horizontal progress bar, the small rectangles are drawn from left to right. For a vertical progress bar, the small rectangles are drawn from bottom to top. At one particular time, the most top or the most right rectangle of a progress bar is referred to as its position. At design time, to set a specific position for the control, change the value of the Position property whose default is 0. The position must always be between the Min and Max values. If you set it to a value lower than the Min, the Object Inspector would reset it to Min. In the same way, if it is set to a value higher than Max, it would be reset to the Max value. At run time, you can assign the desired value to the Position property. Once again, avoid specifying a value that is out of range.

Because a progress bar is usually meant to indicate the progress of an activity, when drawing its small rectangles, it increases its current position in order to draw the next rectangle, except if the control is reset. The number of units that the control must increase value is controlled by the Step property. By default, it is set to 1. Otherwise, you can set it to a different value of your choice.

Practical Learning Practical Learning: Creating Progress Bars

  1. On the Win32 tab of the Tool Palette, click the ProgressBar button and click on the form
  2. Change its properties as follows:
    Height: 225
    Left: 16
    Max: 250
    Name: pgrBlood
    Orientation: pbVertical
    Position: 128
    Smooth: true
    Top: 24
    Width: 18
  3. In the same way, add other progress bars and design the form as follows:
     
    Control Name Caption Additional Properties
    Label lblHeart 000  
    Label lblKidney 000  
    Label lblBrain 000  
    Label lblLLung 000  
    Label lblRLung 000  
    Label lblPancreas 000  
    Label lblLiver 000  
    Label lblBladder 000  
    Label lblStomach 000  
    Label lblBlood 000  
    ProgressBar pgrBlood   Max: 650
    Position: 288
    ProgressBar pgrHeart   Max: 240
    Position: 204
    ProgressBar pgrKidney   Max: 450
    Position: 120
    ProgressBar pgrBrain   Max: 1000
    Position: 760
    ProgressBar pgrLLung   Max: 750
    Position: 428
    ProgressBar pgrRLung   Max: 750
    Position: 320
    ProgressBar pgrPancreas   Max: 800
    Position: 224
    ProgressBar pgrLiver   Max: 1200
    Position: 240
    ProgressBar pgrBladder   Max: 550
    Position: 350
    ProgressBar pgrStomach   Max: 1250
    Position: 650
    Shape shpBlood   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Blood Monitoring
    Shape shpHeart   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Heart Monitoring
    Shape shpKidney   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Kidney Monitoring
    Shape shpBrain   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Brain Monitoring
    Shape shpLLung   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Left Lung
    Shape shpRLung   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Right Lung
    Shape shpPancreas   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Pancreas Monitoring
    Shape shpLiver   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Liver Monitoring
    Shape shpBladder   Brush: Color: clGray
    Shape: stCircle
    Shape shpStomach   Brush: Color: clGray
    Shape: stCircle
    Hint: Start Stomach Monitoring
    Bevel      
    Label   Blood  
    Label   Heart  
    Label   Kidney  
    Label   Brain  
    Label   Lungs  
    Label   Left  
    Label   Right  
    Label   Pancreas  
    Label   Liver  
    Label   Bladder  
    Label   Stomach  
    Panel pnlClose Close  
  4. Add 10 timers to the form and configure them as follows:
     
    Control Name Enabled Interval
    Timer tmrBlood False 650
    Timer tmrHeart False 240
    Timer tmrKidney False 450
    Timer tmrBrain False 1000
    Timer tmrLLung False 750
    Timer tmrRLung False 750
    Timer tmrPancreas False 800
    Timer tmrLiver False 1200
    Timer tmrBladder False 550
    Timer tmrStomach False 1250
  5. Double-click an unoccupied area on the form and implement its OnCreate() event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::FormCreate(TObject *Sender)
    {
    	SendMessage(pgrBlood->Handle, PBM_SETBARCOLOR, 0, clRed);
    	SendMessage(pgrHeart->Handle, PBM_SETBARCOLOR, 0, clGreen);
    	SendMessage(pgrKidney->Handle, PBM_SETBARCOLOR, 0, clYellow);
    	SendMessage(pgrBrain->Handle, PBM_SETBARCOLOR, 0, clGray);
    	SendMessage(pgrLLung->Handle, PBM_SETBARCOLOR, 0, clFuchsia);
    	SendMessage(pgrRLung->Handle, PBM_SETBARCOLOR, 0, clFuchsia);
    	SendMessage(pgrPancreas->Handle, PBM_SETBARCOLOR, 0, clBlue);
    	SendMessage(pgrLiver->Handle, PBM_SETBARCOLOR, 0, clAqua);
    	SendMessage(pgrBladder->Handle, PBM_SETBARCOLOR, 0, clLime);
    	SendMessage(pgrStomach->Handle, PBM_SETBARCOLOR, 0, clNavy);
    }
    //---------------------------------------------------------------------------
  6. Save all

Progress Bar Methods and Messages

 

The ProgressBar control is based on the TProgressBar class. Like every VCL class, it is equipped with a constructor that can be used to dynamically create the control.

We have seen that a progress bar implements its behavior by drawing small adjacent rectangles. This control does not know and does not decide when to draw these indicators. Therefore, after creating a progress bar, you must provide a means of changing its value, that is, a way to increment its position. Although it is usually used to show the evolution of a task, it does not actually have an internal mechanism to monitor such an activity. Another control is usually used to trigger this. Nevertheless, when the value of a progress bar changes, the control refers to the Step property to increment its Position. Based on this Step value, when it is time to increment, the progress bar calls its StepIt() method. Its syntax is:

void __fastcall StepIt(void);

If you want to increase the progress bar’s position by a value other than Step, you can call the StepBy() method. Its syntax is:

void __fastcall StepBy(int Delta);

Pass the desired incremental value as the Delta argument.

Practical Learning Practical Learning: Implementing Progress Bars

  1. On the form, double-click the tmrBlood timer to access its OnTimer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    __fastcall TfrmMain::TfrmMain(TComponent* Owner)
    	: TForm(Owner)
    {
    	Randomize();
    }
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrBloodTimer(TObject *Sender)
    {
    	int BloodLevel = random(650);
    
    	pgrBlood->Position = BloodLevel;
    
    	if( BloodLevel > 480 )
    		shpBlood->Brush->Color = clRed;
    	else
    		shpBlood->Brush->Color = clGreen;
    
    	lblBlood->Caption = lblBlood->Caption.sprintf("%d.%d",
    				BloodLevel/100, random(50));
    }
    //---------------------------------------------------------------------------
  2. Again, on the form, double-click the tmrHeart timer to access its OnTimer event event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrHeartTimer(TObject *Sender)
    {
    	int HeartLevel = random(240);
    
    	pgrHeart->Position = HeartLevel;
    
    	if( HeartLevel > 180 )
    		shpHeart->Brush->Color = clRed;
    	else
    		shpHeart->Brush->Color = clGreen;
    
    	lblHeart->Caption = lblHeart->Caption.sprintf("%d\260", HeartLevel);
    }
    //---------------------------------------------------------------------------
  3. In the same way, initiate the OnTimer event of the tmrKidney timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrKidneyTimer(TObject *Sender)
    {
    	int KidneyLevel = random(450);
    
    	pgrKidney->Position = KidneyLevel;
    
    	if( KidneyLevel > 400 )
    		shpKidney->Brush->Color = clRed;
    	else
    		shpKidney->Brush->Color = clGreen;
    
    	lblKidney->Caption = lblKidney->Caption.sprintf("%d\045", KidneyLevel);
    }
    //---------------------------------------------------------------------------
  4. Initiate the OnTimer event of the tmrBrain timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrBrainTimer(TObject *Sender)
    {
    	int BrainLevel = random(1000);
    
    	pgrBrain->Position = BrainLevel;
    
    	if( BrainLevel > 550 )
    		shpBrain->Brush->Color = clRed;
    	else
    		shpBrain->Brush->Color = clGreen;
    
    	lblBrain->Caption = lblBrain->Caption.sprintf("<%d>", BrainLevel-450);
    }
    //---------------------------------------------------------------------------
  5. Initiate the OnTimer event of the tmrLLung timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrLLungTimer(TObject *Sender)
    {
    	int LLungLevel = random(750);
    
    	pgrLLung->Position = LLungLevel;
    
    	if( LLungLevel > 600 )
    		shpLLung->Brush->Color = clRed;
    	else
    		shpLLung->Brush->Color = clGreen;
    
    	lblLLung->Caption = lblLLung->Caption.sprintf("%d.%d\"",
    	LLungLevel, 2 + random(5));
    }
    //---------------------------------------------------------------------------
  6. Initiate the OnTimer event of the tmrRLung timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrRLungTimer(TObject *Sender)
    {
    	int RLungLevel = random(750);
    
    	pgrRLung->Position = RLungLevel;
    
    	if( RLungLevel > 500 )
    		shpRLung->Brush->Color = clRed;
    	else
    		shpRLung->Brush->Color = clGreen;
    
    	lblRLung->Caption = lblRLung->Caption.sprintf("%d.%d\"",
    				RLungLevel, 2 + random(5));
    }
    //---------------------------------------------------------------------------
  7. Initiate the OnTimer event of the tmrPancreas timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrPancreasTimer(TObject *Sender)
    {
    	int PancreasLevel = random(800);
    
    	pgrPancreas->Position = PancreasLevel;
    
    	if( PancreasLevel > 600 )
    		shpPancreas->Brush->Color = clRed;
    	else
    		shpPancreas->Brush->Color = clGreen;
    
    	lblPancreas->Caption = lblPancreas->Caption.sprintf("\273%d",
    					PancreasLevel);
    }
    //---------------------------------------------------------------------------
  8. Initiate the OnTimer event of the tmrLiver timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrLiverTimer(TObject *Sender)
    {
    	int LiverLevel = random(1200);
    
    	pgrLiver->Position = LiverLevel;
    
    	if( LiverLevel > 1100 )
    		shpLiver->Brush->Color = clRed;
    	else
    		shpLiver->Brush->Color = clGreen;
    
    	lblLiver->Caption = lblLiver->Caption.sprintf("%d\264", LiverLevel);
    }
    //---------------------------------------------------------------------------
  9. Initiate the OnTimer event of the tmrBladder timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrBladderTimer(TObject *Sender)
    {
    	int BladderLevel = random(550);
    
    	pgrBladder->Position = BladderLevel;
    
    	if( BladderLevel > 450 )
    		shpBladder->Brush->Color = clRed;
    	else
    		shpBladder->Brush->Color = clGreen;
    
    	lblBladder->Caption = lblBladder->Caption.sprintf("\247%d\252",
    				BladderLevel);
    }
    //---------------------------------------------------------------------------
  10. Initiate the OnTimer event of the tmrStomach timer event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::tmrStomachTimer(TObject *Sender)
    {
    	int StomachLevel = random(1250);
    
    	pgrStomach->Position = StomachLevel;
    
    	if( StomachLevel > 1100 )
    		shpStomach->Brush->Color = clRed;
    	else
    		shpStomach->Brush->Color = clGreen;
    
    	lblStomach->Caption = lblStomach->Caption.sprintf("%d\274",
    				StomachLevel);
    }
    //---------------------------------------------------------------------------
  11. On the form, click the shape control above the Blood label. In the Object Inspector, click the Events tab. Double-click the right field to OnMouseDown and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpBloodMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrBlood->Enabled )
    	{
    		tmrBlood->Enabled = False;
    		shpBlood->Brush->Color = clGray;
    		shpBlood->Hint = "Start Blood Monitoring";
    	}
    	else
    	{
    		tmrBlood->Enabled = True;
    		shpBlood->Hint = "Stop Blood Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  12. In the same way, initiate the OnMouseDown event of the shape above the Heart label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpHeartMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrHeart->Enabled )
    	{
    		tmrHeart->Enabled = False;
    		shpHeart->Brush->Color = clGray;
    		shpHeart->Hint = "Start Heart Monitoring";
    	}
    	else
    	{
    		tmrHeart->Enabled = True;
    		shpHeart->Hint = "Stop Heart Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  13. Also, initiate the OnMouseDown event of the shape above the Kidney label and implement it as follows:
      
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpKidneyMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrKidney->Enabled )
    	{
    		tmrKidney->Enabled = False;
    		shpKidney->Brush->Color = clGray;
    		shpKidney->Hint = "Start Kidney Monitoring";
    	}
    	else
    	{
    		tmrKidney->Enabled = True;
    		shpKidney->Hint = "Stop Kidney Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  14. Initiate the OnMouseDown event of the shape above the Brain label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpBrainMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrBrain->Enabled )
    	{
    		tmrBrain->Enabled = False;
    		shpBrain->Brush->Color = clGray;
    		shpBrain->Hint = "Start Brain Monitoring";
    	}
    	else
    	{
    		tmrBrain->Enabled = True;
    		shpBrain->Hint = "Stop Brain Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  15. Initiate the OnMouseDown event of the shape above the Left label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpLLungMouseDown(TObject *Sender,
    TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrLLung->Enabled )
    	{
    		tmrLLung->Enabled = False;
    		shpLLung->Brush->Color = clGray;
    		shpLLung->Hint = "Start Left Lung Monitoring";
    	}
    	else
    	{
    		tmrLLung->Enabled = True;
    		shpLLung->Hint = "Stop Left Lung Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  16. Initiate the OnMouseDown event of the shape above the Right label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpRLungMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrRLung->Enabled )
    	{
    		tmrRLung->Enabled = False;
    		shpRLung->Brush->Color = clGray;
    		shpRLung->Hint = "Start Right Lung Monitoring";
    	}
    	else
    	{
    		tmrRLung->Enabled = True;
    		shpRLung->Hint = "Stop Right Lung Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  17. Initiate the OnMouseDown event of the shape above the Pancreas label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpPancreasMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrPancreas->Enabled )
    	{
    		tmrPancreas->Enabled = False;
    		shpPancreas->Brush->Color = clGray;
    	shpPancreas->Hint = "Start Pancreas Monitoring";
    	}
    	else
    	{
    		tmrPancreas->Enabled = True;
    		shpPancreas->Hint = "Stop Pancreas Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  18. Initiate the OnMouseDown event of the shape above the Liver label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpLiverMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrLiver->Enabled )
    	{
    		tmrLiver->Enabled = False;
    		shpLiver->Brush->Color = clGray;
    		shpLiver->Hint = "Start Liver Monitoring";
    	}
    	else
    	{
    		tmrLiver->Enabled = True;
    		shpLiver->Hint = "Stop Liver Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  19. Initiate the OnMouseDown event of the shape above the Bladder label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpBladderMouseDown(TObject *Sender,
    TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrBladder->Enabled )
    	{
    		tmrBladder->Enabled = False;
    		shpBladder->Brush->Color = clGray;
    		shpBladder->Hint = "Start Bladder Monitoring";
    	}
    	else
    	{
    		tmrBladder->Enabled = True;
    		shpBladder->Hint = "Stop Bladder Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  20. Initiate the OnMouseDown event of the shape above the Stomach label and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::shpStomachMouseDown(TObject *Sender,
    	TMouseButton Button, TShiftState Shift, int X, int Y)
    {
    	if( tmrStomach->Enabled )
    	{
    		tmrStomach->Enabled = False;
    		shpStomach->Brush->Color = clGray;
    		shpStomach->Hint = "Start Stomach Monitoring";
    	}
    	else
    	{
    		tmrStomach->Enabled = True;
    		shpStomach->Hint = "Stop Stomach Monitoring";
    	}
    }
    //---------------------------------------------------------------------------
  21. Double-click the (bottom) panel to access its OnClick event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::Panel1Click(TObject *Sender)
    {
    	Close();
    }
    //---------------------------------------------------------------------------
  22. Execute the application
     
  23. To test a progress bar, click the shape button under it. To stop it, click its shape button again
  24. After using the form, close it and return to Borland C++ Builder
  25. Save All

Scroll Bars

 

Introduction

A scrollbar is a control that allows the user to navigate a document in two directions by clicking a button that displays an arrow. The control is equipped with one button at each of its ends. Between the buttons, there is a (long) bar and on the bar, there is sliding object called a thumb:

To use a scroll bar, the user can click one of the arrows. This causes the thumb to move towards the button that was clicked. The user can also click and hold the mouse on a button. This causes the thumb to move continuously, as long as the button is held down, towards the button, until the thumb cannot move any farther. The user can also drag the thumb in one direction to move it or click between a button and the thumb. This causes the thumb to move faster than clicking a button. The thumb of a scroll bar can be positioned only along the scroll bar, between the scroll bar’s button.

Based on their orientation, there are two types of scroll bars: horizontal and vertical. The horizontal scroll bar allows the user to navigate a document left and right. The vertical scroll bar allows navigating up and down.

Based on their relationship with the parent control or owner, there are two types of scroll bars: those that are (automatically) associated with their parent or owner and scroll bar controls that are manually added by the programmer.

Automatically Generated Scroll Bars

To effectively implement their functionality, some controls must be equipped with one or two scroll bars. As we will see with list-based controls such as list boxes, combo boxes, tree views, list views, etc, when the items of their list exceed the allocated client area of the control, the list should display a scroll bar to give access to the hidden part of their list. This type of automatically added scroll bar is usually positioned on the right side of the control for most Latin-based languages including US English.

The Palette property page of Borland C++ Builder’s Environment Options dialog box shows the Pages list box and the Components list view. Because each control has a long list that it cannot show completely, it is equipped with a vertical scroll bar. This allows the user to display the hidden list when needed.

These types of scroll bars are automatically added by the operating system to the control that needs it, unless the programmer explicitly prevented their showing.

Some controls are ready to display a scroll bar upon request. Such controls include the form, the Memo, the RichEdit, the ScrollBox, etc. When designing one of these controls, you can ask to display or hide either or both scroll bars as you see fit. This type of scroll bar is implemented through the TScrollingWinControl class.

Text-Based Applications and Scroll Bars

Because they are always likely to display a long text, the Memo and the RichEdit controls of the VCL are natively ready to display scroll bars, either or both. This is easily done using the ScrollBars property. It provides four options as follows:

Value Comments
ssNone No scroll bar will be displayed
This is the default value
ssHorizontal A horizontal scroll bar will display at the bottom of the control or document
ssVertical A vertical scroll bar will display on the right side of the control or document
ssBoth A horizontal scroll bar will display at the bottom of the control and a vertical scroll bar will display on the right side of the control or document

Thanks to rapid application development (RAD) and object-oriented programming (OOP), you do not have to permanently set the scroll bar(s). You can act in response to the user doing something and decide when to display or hide either or both scroll bars.

Practical Learning Practical Learning: Using Scroll Bars on a Text-Based Application

  1. Open the Editor1 application you created in previous lessons. If you wo not have it, open the Editor1 project from the resources that accompany this book
  2. Display the main form and click the rchEditor control. On the Object Inspector, set the ScrollBars to ssVertical
  3. On the form, double-click the MainMenu1 icon on the form. On the Menu Designer, click the View menu item and add a separator on the first empty box. Then add a menu item named mnuWordWrap and whose Caption is &Word Wrap then set its Checked property to true. Close the Menu Designer
  4. On the main menu of the form, click View -> Word Wrap and implement its event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::mnuWordWrapClick(TObject *Sender)
    {
    	rchEditor->WordWrap = !rchEditor->WordWrap;
    	mnuWordWrap->Checked = !mnuWordWrap->Checked;
    
    	if( rchEditor->WordWrap )
    		rchEditor->ScrollBars = ssVertical;
    	else
    		rchEditor->ScrollBars = ssBoth;
    }
    //---------------------------------------------------------------------------
  5. Test the application. Close it and return to Borland C++ Builder

The Scroll Bar Control

 

Introduction

Microsoft Windows provides another type of scroll bar, considered a complete control in its own right. Like all other controls, this one must be explicitly created and is not added automatically but it provides most of the same basic functionality as if the operating system’s automatically added scroll bars.

To create a scroll bar control, on the Standard section of the Tool Palette, click the ScrollBar button and click a container. The scroll bar is one of the earliest controls of the Microsoft Windows operating system. To create it using the Win32 approach call the CreateWindow() or the CreateWindowEx() functions and specify the class name as SCROLLBAR. If you decide to create it in Win32, you would need to configure all of its functionality. In the VCL, all operations that are needed on a scroll bar control are ready to be used.

Practical Learning Practical Learning: Using Scroll Bars

  1. Start a new project with the default form
  2. Save it in a new folder named BodyTag1
  3. Save the unit as Main and save the project as BodyTag
  4. Change the following properties for the form:
    BorderStyle = bsDialog
    Caption = Body Tag Formatter
    Height = 316
    Name = frmMain
    Position: poScreenCenter
    ShowHint = true
    Width = 350
  5. Open Image Editor and create a new icon. Design the 32 x 32 and the 16 x 16 sizes as follows:
     
  6. Save the icon as BodyTag in the folder of the current project
  7. From the Project menu, access the project options. From the Application tab, seth the Title to Body Tag Formatter. set the Icon to the above
  8. Design the form as follows:
     
    Control Name Caption/Text Other Properties
    Label   Preview  
    Bevel     Shape: bsBottomLine
    Panel pnlPreview   Color: clWhite
    Hint: Current Color
    BitBtn     Kind: bkClose
    GroupBox   Hexadecimal  
    Label   Red  
    Edit edtHexaRed FF  
    Label   Green  
    Edit edtHexaGreen FF  
    Label   Blue  
    Edit edtHexaBlue FF  
    GroupBox   Numeric  
    Label   Red  
    Edit edtNumRed 255  
    Label   Green  
    Edit edtNumGreen 255  
    Label   Blue  
    Edit edtNumBlue 255  
    Label   Color  
    Edit edtBody   Hint: Hexadecimal formula of current color
  9. Save All

Characteristics of the Scroll Bar Control

By default, when you add a scroll bar to a form, the control assumes the horizontal position. This position is controlled by the Kind property whose default value is sbHorizontal. To change the direction of the control to vertical, set this property to sbVertical. The Kind property is controlled by the TScrollBarKind enumerator defined as follows:

enum TScrollBarKind { sbHorizontal, sbVertical };

To set this property programmatically, assign the desired value. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	ScrollBar1->Kind = sbVertical;
}
//---------------------------------------------------------------------------

When using a scroll bar, the user can navigate from one end of the control to the other end. These are the control’s minimum and maximum values. For a horizontal scrollbar, the minimum is the far left position that the bar can assume. For a vertical scrollbar, this would be the most bottom position. The maximum would be the opposite. These two values are controlled by the Min and Max properties. By default, a newly added scrollbar allows scrolling from 0 to 100. To change these values at design time, type an integer number for each field in the Object Inspector. The lowest number the Min property can have is –2147483648 and the highest number for Max would be 2147483647.

The primary technique the user applies to a scrollbar is to click one of the arrows at the ends of the control. As the bar slides inside of the control, it assumes an integer position from Min to Max. At design time, you can use the Position property to set the position that the scrollbar would assume when the form opens. If you set the Position to a value less than the Min, the Object Inspector would restore it to the Min. If you set a Position greater than the Max, the Object Inspector would assign it the Max value. To programmatically set the position of the bar, assign the desired value, which must be between Min and Max, to the Position property. At run time, when the user scrolls the control, you can find the position of the thumb by getting the value of the Position property. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Label1->Caption = ScrollBar1->Position;
	Label2->Caption = ScrollBar2->Position;
}
//---------------------------------------------------------------------------

When the user clicks an arrow of a scrollbar, the bar slides one unit. This unit is called SmallChange and is set to 1 by default. If you want the bar to slide more than one unit, change the SmallChange property to an integer value between Min and Max. The higher the value, the faster the sliding would occur because the bar would jump by SmallChange units.

There are two main ways the user can scroll faster using scrollbars: by pressing either page buttons or by clicking the scrolling region. The amount covered using this technique is controlled by the LargeChange property. Once again, the user can scroll only between Min and Max. This means that you can set this value only to an integer from Min to Max. To find the scrolling amount, the compiler would divide the actual scrolling range (the difference between the Max and Min) by the LargeChange value. When the user clicks in the scrolling region or presses the Page Up or Page Down keys, the bar would jump by LargeChange up to the scrolling amount value. You can change the LargeChange property programmatically as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	ScrollBar1->Kind = sbVertical;
	ScrollBar1->Min = -122;
	ScrollBar1->Max = 240;
	ScrollBar1->Position = 38;
	ScrollBar1->SmallChange = 4;
	ScrollBar1->LargeChange = 20;
}
//---------------------------------------------------------------------------

The bar inside the scroll region has a size relative to the Min and Max values. By default, it is a square of the approximate size of the arrow buttons. This size of the bar is controlled by the PageSize property. Approximately, this represents the percentage of the scrolling range (the difference between the Max and Min). You can change this value at design time in the Object Inspector, by an integer value between Min and Max. To change it programmatically, assign the desired integer to the PageSize property.

Practical Learning Practical Learning: Using Scroll Bars

  1. From the Standard section of the Tool Palette, click the ScrollBar control and, on the form, click on the right side of the panel
  2. On the Object Inspector, change its properties as follows:
    Kind = sbVertical
    Max = 255
    Min = 0
    Name = scrRed
    Position = 255
  3. On the form, click the scrollbar control to select it
  4. Press Ctrl + C to copy the control and press Ctrl + V to paste it on the form
  5. Move the new scroll bar to the right of the previous one. Change its Name to scrGreen
  6. Click on the form and press Ctrl + V. Move the new scroll bar to the right of the others
  7. Change its Name to scrBlue
  8. Add one label on top of each ScrollBar control. Set their captions to R, G, and B, respectively:

  9. Save All

Methods to Manage a Scroll Bar

The ScrollBar control is equipped with a constructor, TScrollBar, that is typically used to dynamically create a scrollbar. To do this, declare a pointer to a TScrollBar object. Specify the owner of the control, which is usually the form on which it is positioned. Also specify the parent of the control. This is usually the form but can also be any container that is hosting the scroll bar. This dynamic creation can be inside of an event or a function. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	TScrollBar * Scroller = new TScrollBar(Form1);
	Scroller->Parent = Form1;
}
//---------------------------------------------------------------------------

After declaring the variable, you can set its properties as desired. Another method of the TScrollBar class is the SetParams(). It allows you to set the Position, Min, and Max values using one function. Here is an example of using it:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	TScrollBar * Scroller = new TScrollBar(Form1);
	Scroller->Parent = Form1;
	Scroller->Left = 24;
	Scroller->Width = 228;
	Scroller->Top = 35;
	Scroller->Kind = sbVertical;
	Scroller->Max = 1500;
	Scroller->Position = 780;
	Scroller->SmallChange = 5;
	Scroller->LargeChange = 150;
	Scroller->PageSize = 250;
	Scroller->SetParams(780, 0, 1500);
}
//---------------------------------------------------------------------------

Scroll Bar Events

The most fundament event of a scrollbar occurs when the bar slides. This happens when:

  • The user clicks one of the arrows
  • The user presses one of the arrow keys
  • The user presses Page Up or Page Down

Every time the user performs one of these actions, the position of the bar changes unless it is already at one of the extremes. When the position of the bar has changed, a message is sent to the operating system that the bar has changed its position. Using the OnChange event of the scrollbar, you can tell the compiler what to do. Fundamentally you can find out the new position and display it on a label. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::ScrollBar1Change(TObject *Sender)
{
	Label1->Caption = ScrollBar1->Position;
}
//---------------------------------------------------------------------------

The OnScroll event occurs when the user scrolls the bar. This event is appropriate if or when you want to capture the specific action that caused the scrolling action. These actions relate to the TScrollCode enumerator:

enum TScrollCode { scLineUp, scLineDown, scPageUp, scPageDown, 
		   scPosition, scTrack, scTop, scBottom, scEndScroll };

The syntax of the OnScroll event is:

void __fastcall (__closure *TScrollEvent)(System::TObject* Sender,
					  TScrollCode ScrollCode,
					  int &ScrollPos);

Practical Learning Practical Learning: Using the Scroll Bar Events

  1. On the form, double-click the left ScrollBar control and implement its OnChange event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::scrRedChange(TObject *Sender)
    {
    	// While the user is scrolling the Red scroll bar
    	// get the integer value or position of the scroll bar
    	edtNumRed->Text = 255 - scrRed->Position;
    
    	// Get the Position value of the Red scroll bar.
    	// Format it to a HEX value
    	// Display the result in the Red Edit control of the RGB section
    	edtHexaRed->Text = IntToHex(255 - scrRed->Position, 2);
    
    	// Get the current Position of each scroll bar
    	// Combine these values to create an RGB color
    	// Preview the resulting color in the Panel
    	pnlPreview->Color = TColor(RGB(255 - scrRed->Position,
    					255 - scrGreen->Position,
    					255 - scrBlue->Position));
    
    	// Get the current Position of each scroll bar
    	// Convert this Position to a HEX value
    	// Using these HEX values, create an RGB (Web) color
    	// Display the resulting RGB color in the Color edit box,
    	// preceded by a # sign
    	edtBody->Text = "#" + IntToHex(255 - scrRed->Position, 2)
    			+ IntToHex(255 - scrGreen->Position, 2)
    			+ IntToHex(255 - scrBlue->Position, 2);
    }
    //---------------------------------------------------------------------------
  2. On the form, double-click the middle ScrollBar control and implement its OnChange event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::scrGreenChange(TObject *Sender)
    {
    	edtNumGreen->Text = 255 - scrGreen->Position;
    
    	edtHexaGreen->Text = IntToHex(255 - scrGreen->Position, 2);
    
    	pnlPreview->Color = TColor(RGB(255 - scrRed->Position,
    					255 - scrGreen->Position,
    					255 - scrBlue->Position));
    
    	edtBody->Text = "#" + IntToHex(255 - scrRed->Position, 2)
    			+ IntToHex(255 - scrGreen->Position, 2)
    			+ IntToHex(255 - scrBlue->Position, 2);
    }
    //---------------------------------------------------------------------------
  3. On the form, double-click the right ScrollBar control and implement its OnChange event as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::scrBlueChange(TObject *Sender)
    {
    	edtBlue->Text = 255 - scrBlue->Position;
    
    	edtHexaBlue->Text = IntToHex(255 - scrBlue->Position, 2);
    
    	pnlPreview->Color = TColor(RGB(255 - scrRed->Position,
    					255 - scrGreen->Position,
    					255 - scrBlue->Position));
    
    	edtBody->Text = "#" + IntToHex(255 - scrRed->Position, 2)
    			+ IntToHex(255 - scrGreen->Position, 2)
    			+ IntToHex(255 - scrBlue->Position, 2);
    }
    //---------------------------------------------------------------------------
  4. Test the application
  5. After using the form, close it and save the project. Press F12 to display the form
  6. Click the Red edit box in the Numeric GroupBox. On the Object Inspector, click the Events tab. Double-click the OnKeyPress event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::edtNumRedKeyPress(TObject *Sender, char &Key)
    {
    	// Allow only digits as entries
    	if( (Key != '0') &&
    	    (Key != '1') &&
    	    (Key != '2') &&
    	    (Key != '3') &&
    	    (Key != '4') &&
    	    (Key != '5') &&
    	    (Key != '6') &&
    	    (Key != '7') &&
    	    (Key != '8') &&
    	    (Key != '9') &&
    	    (Key != VK_DELETE) &&
    	    (Key != VK_BACK) )
    		Key = '\0';
    
    	scrRed->Position = 255 - edtNumRed->Text.ToInt();
    	scrRedChange(Sender);
    }
    //---------------------------------------------------------------------------
  7. In the Events tab of the Tool Palette, double-click the OnChange event and implement it as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::edtNumRedChange(TObject *Sender)
    {
    // If the user tries to have this box empty,
    // set its value to 0
    if( edtNumRed->Text.IsEmpty() )
    edtNumRed->Text = IntToStr(0);
    else if( edtNumRed->Text.ToInt() > 255 ) // No value > 255 allowed
    edtNumRed->Text = 255;
    
    scrRed->Position = 255 - edtNumRed->Text.ToInt();
    scrRedChange(Sender);
    }
    //---------------------------------------------------------------------------
  8. Implement the OnKeyPress event of the Green edit control from the same GroupBox control as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::edtNumGreenKeyPress(TObject *Sender, char &Key)
    {
    	if( (Key != '0') &&
    	    (Key != '1') &&
    	    (Key != '2') &&
    	    (Key != '3') &&
    	    (Key != '4') &&
    	    (Key != '5') &&
    	    (Key != '6') &&
    	    (Key != '7') &&
    	    (Key != '8') &&
    	    (Key != '9') &&
    	    (Key != VK_DELETE) &&
    	    (Key != VK_BACK) )
    		Key = '\0';
    
    	scrGreen->Position = 255 - edtNumGreen->Text.ToInt();
    	scrGreenChange(Sender);
    }
    //---------------------------------------------------------------------------
  9. Implement the OnChange event of the Green edit box from the same GroupBox control as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::edtNumGreenChange(TObject *Sender)
    {
    	if( edtNumGreen->Text.IsEmpty() )
    		edtNumGreen->Text = IntToStr(0);
    	else if( edtNumGreen->Text.ToInt() > 255 )
    		edtNumGreen->Text = 255;
    
    	scrGreen->Position = 255 - edtNumGreen->Text.ToInt();
    	scrGreenChange(Sender);
    }
    //---------------------------------------------------------------------------
  10. Implement the OnKeyPress event of the Blue edit box from the same GroupBox as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::edtBlueKeyPress(TObject *Sender, char &Key)
    {
    	if( (Key != '0') &&
    	    (Key != '1') &&
    	    (Key != '2') &&
    	    (Key != '3') &&
    	    (Key != '4') &&
    	    (Key != '5') &&
    	    (Key != '6') &&
    	    (Key != '7') &&
    	    (Key != '8') &&
    	    (Key != '9') &&
    	    (Key != VK_DELETE) &&
    	    (Key != VK_BACK) )
    		Key = '\0';
    
    	scrBlue->Position = 255 - edtBlue->Text.ToInt();
    	scrBlueChange(Sender);
    }
    //---------------------------------------------------------------------------
  11. Implement the OnChange event of the Blue edit box from the same GroupBox control as follows:
     
    //---------------------------------------------------------------------------
    void __fastcall TfrmMain::edtBlueChange(TObject *Sender)
    {
    	if( edtBlue->Text.IsEmpty() )
    		edtBlue->Text = IntToStr(0);
    	else if( edtBlue->Text.ToInt() > 255 )
    		edtBlue->Text = 255;
    
    	scrBlue->Position = 255 - edtBlue->Text.ToInt();
    	scrBlueChange(Sender);
    }
    //---------------------------------------------------------------------------
  12. Test the form
     
  13. After using it, close it and save the project

 

Previous Copyright © 2005-2007 Yevol Next