The Spin Button widget is generally used to allow the user to select a value from a range of numeric values. It consists of a text entry box with up and down arrow buttons attached to the side. Selecting one of the buttons causes the value to "spin" up and down the range of possible values. The entry box may also be edited directly to enter a specific value.
The Spin Button allows the value to have zero or a number of decimal places and to be incremented/decremented in configurable steps. The action of holding down one of the buttons optionally results in an acceleration of change in the value according to how long it is depressed.
The Spin Button uses Adjustments to hold information about the range of values that the spin button can take. This makes for a powerful Spin Button widget.
Recall that an adjustment widget is created with the following
function, which illustrates the information that it holds:
$adj = new Gtk::Adjustment( $value,
These attributes of an Adjustment are used by the Spin Button in
the following way:
$lower,
$upper,
$step_increment,
$page_increment,
$page_size );
- $value
Initial value for the Spin Button.
- $lower
Lower range value.
- $upper
Upper range value.
- $step_increment
Value to increment/decrement when pressing mouse button 1 on a button.
- $page_increment
Value to increment/decrement when pressing mouse button 2 on a button.
- $page_size
Unused.
Additionally, mouse button 3 can be used to jump directly to the
$upper
or
$lower
values when used to select one of the buttons. Lets look at how
to create a Spin Button:
$spin = new Gtk::SpinButton( $adjustment, $climb_rate, $digits );
The
$climb_rate
argument take a value between
0.0
and
1.0
and indicates the amount of acceleration that the Spin Button
has. The
$digits
argument specifies the number of decimal places to which the
value will be displayed.
A Spin Button can be reconfigured after creation using the
following function:
$spin->configure( $adjustment, $climb_rate, $digits );
The adjustment can be set and retrieved independantly using the
following two functions:
$spin->set_adjustment( $adjustment );
$spin->get_adjustment();
The number of decimal places can also be altered using:
$spin->set_digits( $digits );
The value that a Spin Button is currently displaying can be
changed using the following function:
$spin->set_value( $value );
The current value of a Spin Button can be retrieved as either a
floating point or integer value with the following functions:
$spin->get_value_as_float();
$spin->get_value_as_int();
If you want to alter the value of a Spin Value relative to its
current value, then the following function can be used:
$spin->spin( $direction, $increment );
'forward'
The
$direction
parameter can take one of the following values:
'backward'
'page_forward'
'page_backward'
'home'
'end'
'user_defined'
This function packs in quite a bit of functionality, which I will attempt to clearly explain. Many of these settings use values from the Adjustment object that is associated with a Spin Button.
'forward' and 'backward' change the value of the Spin Button by the amount specified by $increment, unless $increment is equal to 0, in which case the value is changed by the value of $step_increment in the Adjustment.
'page_forward' and 'page_backward' simply alter the value of the Spin Button by $increment.
'home' sets the value of the Spin Button to the bottom of the Adjustments range.
'end' sets the value of the Spin Button to the top of the Adjustments range.
'user_defined' simply alters the value of the Spin Button by the specified amount.
We now move away from functions for setting and retrieving the range attributes of the Spin Button now, and move onto functions that effect the appearance and behaviour of the Spin Button widget itself.
The first of these functions is used to constrain the text box
of the Spin Button such that it may only contain a numeric
value. This prevents a user from typing anything other than
numeric values into the text box of a Spin Button:
$spin->set_numeric( $numeric );
You can set whether a Spin Button will wrap around between the
upper and lower range values with the following function:
$spin->set_wrap( $wrap );
You can set a Spin Button to round the value to the nearest
step_increment,
which is set within the Adjustment object used with the Spin
Button. This is accomplished with the following function:
$spin->set_snap_to_ticks( $snap_to_ticks );
The update policy of a Spin Button can be changed with the
following function:
$spin->set_update_policy( $policy );
The possible values of
$policy
are either
'always'
or
'if_valid'.
These policies affect the behavior of a Spin Button when parsing inserted text and syncing its value with the values of the Adjustment.
In the case of 'if_valid' the Spin Button only value gets changed if the text input is a numeric value that is within the range specified by the Adjustment. Otherwise the text is reset to the current value.
In case of 'update_always' we ignore errors while converting text into a numeric value.
The appearance of the buttons used in a Spin Button can be
changed using the following function:
$spin->set_shadow_type( $shadow_type );
As usual, the
$shadow_type
can be one of:
'in'
'out'
'etched_in'
'etched_out'
Finally, you can explicitly request that a Spin Button update
itself:
$spin->update();
It's example time again.
#!/usr/bin/perl -w use Gtk; use strict; set_locale Gtk; init Gtk; my $false = 0; my $true = 1; my $spinner1; my $window; my $frame; my $hbox; my $main_vbox; my $vbox; my $vbox2; my $spinner2; my $spinner; my $button; my $label; my $val_label; my $adj; # Create the window $window = new Gtk::Window( "toplevel" ); $window->signal_connect( "destroy", sub { Gtk->exit( 0 ); } ); $window->set_title( "Spin Button" ); $main_vbox = new Gtk::VBox( $false, 5 ); $main_vbox->border_width( 10 ); $window->add( $main_vbox ); # create a frame for a non-accelerated spinner $frame = new Gtk::Frame( "Not accelerated" ); $main_vbox->pack_start( $frame, $true, $true, 0 ); $vbox = new Gtk::VBox( $false, 0 ); $vbox->border_width( 5 ); $frame->add( $vbox ); # Day, month, year spinners $hbox = new Gtk::HBox( $false, 0 ); $vbox->pack_start( $hbox, $true, $true, 5 ); $vbox2 = new Gtk::VBox( $false, 0 ); $hbox->pack_start( $vbox2, $true, $true, 5 ); $label = new Gtk::Label( "Day :" ); $label->set_alignment( 0, 0.5 ); $vbox2->pack_start( $label, $false, $true, 0 ); $adj = new Gtk::Adjustment( 1.0, 1.0, 31.0, 1.0, 5.0, 0.0 ); $spinner = new Gtk::SpinButton( $adj, 0, 0 ); $spinner->set_wrap( $true ); $spinner->set_shadow_type( 'out' ); $vbox2->pack_start( $spinner, $false, $true, 0 ); $vbox2 = new Gtk::VBox( $false, 0 ); $hbox->pack_start( $vbox2, $true, $true, 5 ); $label = new Gtk::Label( "Month :" ); $label->set_alignment( 0, 0.5 ); $vbox2->pack_start( $label, $false, $true, 0 ); $adj = new Gtk::Adjustment( 1.0, 1.0, 12.0, 1.0, 5.0, 0.0 ); $spinner = new Gtk::SpinButton( $adj, 0, 0 ); $spinner->set_wrap( $true ); $spinner->set_shadow_type( 'etched_in' ); $vbox2->pack_start( $spinner, $false, $true, 0 ); $vbox2 = new Gtk::VBox( $false, 0 ); $hbox->pack_start( $vbox2, $true, $true, 5 ); $label = new Gtk::Label( "Year :" ); $label->set_alignment( 0, 0.5 ); $vbox2->pack_start( $label, $false, $true, 0 ); $adj = new Gtk::Adjustment( 1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0 ); $spinner = new Gtk::SpinButton( $adj, 0, 0 ); $spinner->set_wrap( $false ); $spinner->set_shadow_type( 'in' ); $spinner->set_usize( 55, 0 ); $vbox2->pack_start( $spinner, $false, $true, 0 ); # Create the frame for accelerated spinners $frame = new Gtk::Frame( "Accelerated" ); $main_vbox->pack_start( $frame, $true, $true, 0 ); $vbox = new Gtk::VBox( $false, 0 ); $vbox->border_width( 5 ); $frame->add( $vbox ); $hbox = new Gtk::HBox( $false, 0 ); $vbox->pack_start( $hbox, $false, $true, 5 ); $vbox2 = new Gtk::VBox( $false, 0 ); $hbox->pack_start( $vbox2, $true, $true, 5 ); # Create the accelerated spinners $label = new Gtk::Label( "Value :" ); $label->set_alignment( 0, 0.5 ); $vbox2->pack_start( $label, $false, $true, 0 ); $adj = new Gtk::Adjustment( 0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0 ); $spinner1 = new Gtk::SpinButton( $adj, 1.0, 2 ); $spinner1->set_wrap( $true ); $spinner1->set_usize( 100, 0 ); $vbox2->pack_start( $spinner1, $false, $true, 0 ); $vbox2 = new Gtk::VBox( $false, 0 ); $hbox->pack_start( $vbox2, $true, $true, 5 ); $label = new Gtk::Label( "Digits :" ); $label->set_alignment( 0, 0.5 ); $vbox2->pack_start( $label, $false, $true, 0 ); $adj = new Gtk::Adjustment( 2, 1, 5, 1, 1, 0 ); $spinner2 = new Gtk::SpinButton( $adj, 0.0, 0 ); $spinner2->set_wrap( $true ); $adj->signal_connect( "value_changed", \&change_digits, $spinner2 ); $vbox2->pack_start( $spinner2, $false, $true, 0 ); $hbox = new Gtk::HBox( $false, 0 ); $vbox->pack_start( $hbox, $false, $true, 5 ); $button = new Gtk::CheckButton( "Snap to 0.5-ticks" ); $button->signal_connect( "clicked", \&toggle_snap, $spinner1 ); $vbox->pack_start( $button, $true, $true, 0 ); $button->set_active( $true ); $button = new Gtk::CheckButton( "Numeric only input mode" ); $button->signal_connect( "clicked", \&toggle_numeric, $spinner1 ); $vbox->pack_start( $button, $true, $true, 0 ); $button->set_active( $true ); $val_label = new Gtk::Label( "" ); $hbox = new Gtk::HBox( $false, 0 ); $vbox->pack_start( $hbox, $false, $true, 5 ); $button = new Gtk::Button( "Value as Int" ); $button->set_user_data( $val_label ); $button->signal_connect( "clicked", \&get_value, $spinner1, 1 ); $hbox->pack_start( $button, $true, $true, 5 ); $button = new Gtk::Button( "Value as Font" ); $button->set_user_data( $val_label ); $button->signal_connect( "clicked", \&get_value, $spinner1, 2 ); $hbox->pack_start( $button, $true, $true, 5 ); $vbox->pack_start( $val_label, $true, $true, 0 ); $val_label->set_text( "0" ); $hbox = new Gtk::HBox( $false, 0 ); $main_vbox->pack_start( $hbox, $false, $true, 0 ); $button = new Gtk::Button( "Close" ); $button->signal_connect( "clicked", sub { Gtk->exit( 0 ); } ); $hbox->pack_start( $button, $true, $true, 5 ); $window->show_all(); main Gtk; exit( 0 ); ### Subroutines # Toggle whether text entry should snap to the tick values sub toggle_snap { my ( $widget, $spin ) = @_; $spin->set_snap_to_ticks( $widget->active ); } # Toggle whether only numeric input is allowed sub toggle_numeric { my ( $widget, $spin ) = @_; $spin->set_numeric( $widget->active ); } # Set the number of digits displayed after the decimal point sub change_digits { my ( $widget, $spin ) = @_; $spinner1->set_digits( $spin->get_value_as_int() ); } # Get the value of the spinner and put in in a label sub get_value { my ( $widget, $spin, $num ) = @_; my $buf = ""; my $label; $label = new Gtk::Label( $widget->get_user_data() ); if ( $num == 1 ) { $buf = $spin->get_value_as_int(); } else { $buf = $spin->get_value_as_float(); } $val_label->set_text( $buf ); } # END EXAMPLE PROGRAM

Spin Button Example Screenshot