Home

VCL Controls: The Scroll Bars

 

Scroll Bar Fundamentals

 

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 Bcb

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 tab of the Component 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 tab of the Component 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. Change its Name to scrBlue
  7. Add one label on top of each ScrollBar control. Set their captions to R, G, and B, respectively:

  8. 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 Component 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
Home Copyright © 2005-2012, FunctionX, Inc.