Home

Win32 Controls: The Up-Down Button

 

Introduction to the Up-Down Control

 

Description

A spin button, also called up-down, is a Windows control equipped with two opposite arrow buttons or . The user clicks one of the arrow buttons at one time to increase or decrease the current value of the control. The value held by the control is also called its position.

The values of a spin button range from a minimum to a maximum. When the up or right arrow is clicked, the value of the control increases. If the user clicks and holds the mouse on the up or right pointing arrow button, the value of the control keeps increasing until it reaches its maximum and then stops. The opposite behavior applies when the user clicks or holds the mouse on the down or left-pointing arrow button.

Because a spin button is only equipped with arrows, it does not inherently show its value. Therefore, this control is usually accompanied by another, text-based, control, usually an edit box, that indicates its position ..

 

Practical LearningPractical Learning: Introducing Up-Down Buttons

  1. Start Embarcadero C++Builder
  2. To start a new project, on the main menu, click File -> New -> VCL Forms Application - C++Builder
  3. In the Object Inspector, change the properties of the form as follows:
    Caption: Pledge Distribution
    Name: frmPledge
    Position: poScreenCenter
  4. To save the project, on the Standard toolbar, click the Save All button Save All
  5. Click the New Folder button
  6. Set the name of the folder to PledgeDistribution1 and press Enter
  7. Set the name of the unit to Pledge and press Enter
  8. Set the name of the project to PledgeDistribution and press Enter

Creating an Up-Down Control

To suport up-down controls, the VCL provides a class named TUpDown. The TUpDown class implements the TCustomUpDown class that is derived from TWinControl:

TUpDown Inheritance

To visually create an up-down button, in the Win32 section of the Tool Palette, click the TUpDown icon TUpDown and click the form or container. To programmatically get an up-down control, create a pointer to TUpDown. Call its constructor to initialize the control and make sure you specify its parent. Here is an example:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TUpDown *Counter = new TUpDown(this);
	Counter->Parent = this;
}
//---------------------------------------------------------------------------

Although not required, an up-down control should be accompanied by another object that would display the current value of the up-down control. The most commonly used accompanying object is an edit control but you can use any control you judge appropriate.

Characteristics of an Up-Down Control

 

Introduction

After adding the up-down control on a container such as a form, use the Object Inspector to control its properties. You can also specify the control's characteristics programmatically by assigning the desired values to its properties. At the least, you can use some of the properties that the TUpDown class inherits from TWinControl or from TControl. Here are examples:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TUpDown *Counter = new TUpDown(this);
	Counter->Parent = this;
	
	Counter->Left = Displayer->Left + Displayer->Width;
	Counter->Top = Displayer->Top;
}
//---------------------------------------------------------------------------

The Orientation

Although its name suggests an up and a down directions, an up-down control can be made horizontal:

Up-Down Orientation

The direction is controlled by a property named Orientation, which is based on the TUDOrientation enumeration:

__property Comctrls::TUDOrientation Orientation = 
{
    read=FOrientation,
    write=SetOrientation
};

The TUDOrienation enumeration has two members:

enum TUDOrientation{
	udHorizontal,
	udVertical
};

The default appearance of an up-down button is to show a up-pointing button and a down-pointing arrow. In this case, the value of the Orientation property is udVertical. You can visually change it in the Orientation field of the Object Inspector or programmatically by assigning the desired value to this property.

The Associate

As mentioned already, an up-down control does not visually display its value. Therefore, you can add a text-based or other control to it. This accompanying object is specified using the Associate property:

__property Controls::TWinControl * Associate = {read=FAssociate,write=SetAssociate};

The associated control would display the current value of the up-down control. To associate a control to the up-down control, first create or add the desired control to your application. Then, at design time on the Object Inspector, you can click the Associate field to display its combo box. Click the arrow and select the desired control:

Up-Down Control

You can also associate a control programmatically using code such as this:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TUpDown *Counter = new TUpDown(this);
	Counter->Parent = this;
	
	TEdit *Displayer = new TEdit(this);
	Displayer->Parent = this;
	
	Displayer->Left = 16;
	Displayer->Top = 16;
	Displayer->Width = 32;
	Counter->Left = Displayer->Left + Displayer->Width;
	Counter->Top = Displayer->Top;
	
	Counter->Associate = Displayer;
}//---------------------------------------------------------------------------

The UpDown control usually has its associated control on the left side. This is controlled by the AlignButton property. This property is based on the TUDAlignButton enumeration:

__property Comctrls::TUDAlignButton AlignButton = {read=FAlignButton,write=SetAlignButton};

The TUDAlignButton enumeration has two members:

enum TUDAlignButton{
	udLeft,
	udRight
};

You can ask the up-down control to have the accompanying object on its right side by setting the AlignButton property to udRight. At design time, both controls still display as they are designed. If you change the AlignButton value, the control would apply the value only at runtime.

Using the Arrow Keys

One of the nicest features that make the up-down button easy to use is that the user can change its values by pressing the up and down arrow keys of the keyboard. This ability is by default set to true from the Boolean ArrowKeys property:

__property bool ArrowKeys = {read=FArrowKeys,write=SetArrowKeys};

If you want to prevent the user from using the keyboard to increase or decrease the value of the UpDown control, set the ArrowKeys property to false.

Practical LearningPPractical Learning: Designing an UpDown control

  1. Design the form as follows:
     
    Pledge Distribution
    Control Alignment Associate Caption Name Text
    TLabel TLabel     Amount Pledged:    
    TEdit TEdit taRightJustify     edtAmountPledged 0.00
    TLabel TLabel     Rotherham College:    
    TEdit TEdit taRightJustify     edtRate1 50
    TUpDown TUpDown   edtRate1   updAmount1  
    TLabel TLabel     %    
    TEdit TEdit taRightJustify   0.00 edtAmount1 0.00
    TLabel TLabel     Leicester University:    
    TEdit TEdit taRightJustify     edtRate2 25
    TUpDown TUpDown   edtRate2   updAmount2  
    TLabel TLabel     %    
    TEdit TEdit taRightJustify     edtAmount2 0.00
    TLabel TLabel     Lars Union Academy:    
    TEdit TEdit taRightJustify     edtRate3 25
    TUpDown TUpDown   edtRate3 25 updAmount3  
    TLabel TLabel     %    
    TEdit TEdit taRightJustify     edtAmount3 0.00
    TLabel TLabel     Message lblMessage  
    TBitBtn TBitBtn         Kind: bkClose
  2. Save all

The Minimum and Maximum Values

Probably the most important piece of information you would need from an up-down control is the value it is holding at a particular time. As mentioned already, the up-down control navigates from a minimum to a maximum values. The values of the control are short integer numbers. These numbers range from a minimum controlled by the Min property to a maximum value controlled by the Max property:

__property int Min = {read=FMin,write=SetMin};
__property int Max = {read=FMax,write=SetMax};

By default, a freshly added UpDown control on a form has its Min and Max values set to 0 and 100 respectively. You can set the minimum value of the control to 32768 and the maximum to 32767. These values are set using the Min and Max fields of the Object Inspector. You can change them programmatically as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TUpDown *Counter = new TUpDown(this);
	Counter->Parent = this;
	TEdit *Displayer = new TEdit(this);
	Displayer->Parent = this;
	
	Displayer->Left = 16;
	Displayer->Top = 16;
	Displayer->Width = 32;
	
	Counter->Left = Displayer->Left + Displayer->Width;
	Counter->Top = Displayer->Top;
	
	Counter->Min = 12;
	Counter->Max = 248;
	
	Counter->Associate = Displayer;
}
//---------------------------------------------------------------------------

Thousands

If you use numbers in the thousands, the control that accompanies the up-down (such as the edit control) will display the values using the comma to separate the thousands. This is because the up-down control is configured, by default, to separate the thousands. To support this, the TCustomUpDown class provides the Thousands Boolean property:

__property bool Thousands = {read=FThousands,write=SetThousands};

If you do not want this feature, change the value of the Thousands property from true to false.

Incrementing

When using the UpDown button, the user can click one of the arrows of the control to increase or decrease the value. By default, the value increases or decreases by 1. If you want the value to augment by more than 1, set an integer value using the Increment property:

__property int Increment = {read=FIncrement,write=SetIncrement};

To set the Increment value programmatically, you can use code as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TUpDown *Counter = new TUpDown(this);
	Counter->Parent = this;
	
	TEdit *Displayer = new TEdit(this);
	Displayer->Parent = this;
	
	Displayer->Left = 16;
	Displayer->Top = 16;
	Displayer->Width = 32;
	
	Counter->Left = Displayer->Left + Displayer->Width;
	Counter->Top = Displayer->Top;
	Counter->Min = 12;
	Counter->Max = 248;
	
	Counter->Increment = 2;
	
	Counter->Associate = Displayer;
}
//---------------------------------------------------------------------------

The Position of the Control

When an up-down control is accessed, the value it holds can be set by its Position property:

__property int Position = {read=GetPosition,write=SetPosition};

You can use this property to specify what value the control would use at startup. It should be an integer between the Min and the Max values. You can also set it programmatically as follows:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
	TUpDown *Counter = new TUpDown(this);
	Counter->Parent = this;
	TEdit *Displayer = new TEdit(this);
	
	Displayer->Parent = this;
	Displayer->Left = 16;
	Displayer->Top = 16;
	Displayer->Width = 32;
	
	Counter->Left = Displayer->Left + Displayer->Width;
	Counter->Top = Displayer->Top;
	Counter->Min = 12;
	Counter->Max = 248;
	Counter->Increment = 2;
	
	Counter->Position = 36;
	
	Counter->Associate = Displayer;
}
//---------------------------------------------------------------------------

The Position property also allows you to find out the value of the up-down control at any time.

Wrapping the Value

After setting the Increment value, when the user clicks the arrow buttons, the value would increase accordingly. When the maximum value is reached, the control would use the Wrap property:

__property bool Wrap = {read=FWrap,write=SetWrap};

To find out what to do:

  • If the Wrap Boolean property is set to false (the default), the increment would stop at the Max value even if Max is not divisible by the Increment value. The same goes for the Min value
  • If the Wrap property is set to true and if the user increases the value of the control, the incrementing would stop to the last value divisible by the Increment value but less than the Max. The same would apply when decrementing the value of the control

The Up-Down Control Events

The main event of the UpDown control occurs when the user clicks one of the arrows. Whether the user clicks the up pointing arrow to increase or the down pointing arrow to decrease the value or position of the control, the OnClick() event is fired. The pointing arrows are represented using the TUDBtnType enumerator that has two values. The up or right pointing arrow is recognized as btNext while the down or left pointing arrow is referred to as btPrev.

When the user clicks one of the arrows, you can write code to perform an action depending on the button that was clicked. Using this OnClick() event, you do not have to associate the UpDown control with an edit box to display integers; you can use the event to format the value or configure any other behavior you see fit. For example, instead of displaying an integer, you can display a floating number, a string, anything, that is traditionally not allowed.

When the user clicks one of the arrows of the UpDown control, the operating system is notified just before this action occurs. This notification is done through the OnChanging() event. This allows you to perform a last minute configuration before the value or position of the control changes. You can also use this event to deny changing the value of the control.

The OnChangingEx() event also fires just before the value of the UpDown control changes. This time, you can set a new value for the control if the change is successful.

It is important and professionally convenient to make sure that the user can use the up and down arrow keys of the keyboard to increase or decrease the value of the UpDown control. If the user presses and holds the up arrow key, the UpDown control would be incrementing its value until either the user releases the key or the control reaches its maximum limit. Here is an example of how to track the OnMouseUp mouse event of the UpDown control:

//---------------------------------------------------------------------------
void __fastcall TForm1::UpDown1MouseUp(TObject *Sender, TMouseButton Button,
				       TShiftState Shift, int X, int Y)
{
	ShowMessage(L"You stopped spinning at " + AnsiString(edtSpin->Text));
}
//---------------------------------------------------------------------------

Practical LearningPractical Learning: Configuring an UpDown control

  1. Double-click the Amount Pledge edit control to generate its OnChange event
  2. Implement the event as follows:
    //---------------------------------------------------------------------------
    void __fastcall TfrmPledge::edtAmountPledgedChange(TObject *Sender)
    {
    	if( this->edtAmountPledged->Text == "" )
    	{
    		this->updAmount1->Enabled = false;
    		this->updAmount2->Enabled = false;
    		this->updAmount3->Enabled = false;
    	}
    	else
    	{
    		this->updAmount1->Enabled = true;
    		this->updAmount2->Enabled = true;
    		this->updAmount3->Enabled = true;
    	}
    }
    //---------------------------------------------------------------------------
  3. Return to the form and double-click the top up-down control to generate its OnClick event
  4. Implement the event as follows:
    //---------------------------------------------------------------------------
    void __fastcall TfrmPledge::updAmount1Click(TObject *Sender, TUDBtnType Button)
    {
        double AmountPledged,
    	   RateAmount1, RateAmount2, RateAmount3,
    	   Amount1, Amount2, Amount3,
    	   Rest;
    
        AmountPledged = this->edtAmountPledged->Text.ToDouble();
    
        RateAmount2 = static_cast<double>(this->updAmount2->Position);
        RateAmount3 = static_cast<double>(this->updAmount3->Position);
        this->updAmount1->Max = 100 - RateAmount2 - RateAmount3;
        RateAmount1 = static_cast<double>(this->updAmount1->Position);
    
        Amount1 = AmountPledged * RateAmount1 / 100;
        Amount2 = AmountPledged * RateAmount2 / 100;
        Amount3 = AmountPledged * RateAmount3 / 100;
        Rest = AmountPledged - Amount1 - Amount2 - Amount3;
    
        this->edtAmount1->Text = FloatToStrF(Amount1, ffCurrency, 8, 2);
        this->edtAmount2->Text = FloatToStrF(Amount2, ffCurrency, 8, 2);
        this->edtAmount3->Text = FloatToStrF(Amount3, ffCurrency, 8, 2);
    
        if( Rest > 0 )
    	 this->lblMessage->Caption = FloatToStrF(Rest,
    						ffCurrency, 8, 2)
    					 + L" still to be used";
        else
    	this->lblMessage->Caption = "";
    }
    //---------------------------------------------------------------------------
  5. Return to the form and double-click the middle up-down control
  6. Implement its events as follows:
    //---------------------------------------------------------------------------
    void __fastcall TfrmPledge::updAmount2Click(TObject *Sender, TUDBtnType Button)
    {
    	double AmountPledged,
    		   RateAmount1, RateAmount2, RateAmount3,
    		   Amount1, Amount2, Amount3,
    		   Rest;
    
    	AmountPledged = this->edtAmountPledged->Text.ToDouble();
    
    	RateAmount1 = static_cast<double>(this->updAmount1->Position);
    	RateAmount3 = static_cast<double>(this->updAmount3->Position);
    	this->updAmount2->Max = 100 - RateAmount1 - RateAmount3;
    	RateAmount2 = static_cast<double>(this->updAmount2->Position);
    
    	Amount1 = AmountPledged * RateAmount1 / 100;
    	Amount2 = AmountPledged * RateAmount2 / 100;
    	Amount3 = AmountPledged * RateAmount3 / 100;
    	Rest = AmountPledged - Amount1 - Amount2 - Amount3;
    
    	this->edtAmount1->Text = FloatToStrF(Amount1, ffCurrency, 8, 2);
    	this->edtAmount2->Text = FloatToStrF(Amount2, ffCurrency, 8, 2);
    	this->edtAmount3->Text = FloatToStrF(Amount3, ffCurrency, 8, 2);
    
    	if( Rest > 0 )
    		this->lblMessage->Caption = FloatToStrF(Rest, ffCurrency, 8, 2) + L" still to be used";
    	else
    		this->lblMessage->Caption = "";
    }
    //---------------------------------------------------------------------------
  7. Return to the form and double-click the bottom up-down control
  8. Implement its events as follows:
    //---------------------------------------------------------------------------
    void __fastcall TfrmPledge::updAmount3Click(TObject *Sender, TUDBtnType Button)
    {
    	double AmountPledged,
    	RateAmount1, RateAmount2, RateAmount3,
    	Amount1, Amount2, Amount3,
    	Rest;
    
    	AmountPledged = this->edtAmountPledged->Text.ToDouble();
    
    	RateAmount1 = static_cast<double>(this->updAmount1->Position);
    	RateAmount2 = static_cast<double>(this->updAmount2->Position);
    	this->updAmount3->Max = 100 - RateAmount1 - RateAmount2;
    	RateAmount3 = static_cast<double>(this->updAmount3->Position);
    
    	Amount1 = AmountPledged * RateAmount1 / 100;
    	Amount2 = AmountPledged * RateAmount2 / 100;
    	Amount3 = AmountPledged * RateAmount3 / 100;
    	Rest = AmountPledged - Amount1 - Amount2 - Amount3;
    
    	this->edtAmount1->Text = FloatToStrF(Amount1, ffCurrency, 8, 2);
    	this->edtAmount2->Text = FloatToStrF(Amount2, ffCurrency, 8, 2);
    	this->edtAmount3->Text = FloatToStrF(Amount3, ffCurrency, 8, 2);
    
    	if( Rest > 0 )
    		this->lblMessage->Caption = FloatToStrF(Rest,
    		 ffCurrency, 8, 2),
    		 " still to be used";
    	else
    		this->lblMessage->Caption = "";
    }
    //---------------------------------------------------------------------------
  9. Save all
  10. Press F9 to execute
  11. Test the application with a value in the Amount Pledged edit control and use the up-down controls
     
    Pledge Distribution
     
  12. Close the form and return to your programming environment
 
 
 
 

Home Copyright © 2010-2011 FunctionX, Inc.