SpinButton
| Chapter 6. Miscellaneous Widgets |

## SpinButton

A `SpinButton` allows the user to select a value from a range of numeric values. It has an Entry widget with up and down arrow buttons at the side. Clicking the buttons causes the value to 'spin' up and down across the range of possible values. The `Entry` widget may also be used to enter a value directly.

The value can have an adjustable number of decimal places, and the step size is configurable. `SpinButton`s have an 'auto-repeat' feature as well: holding down one of the arrows can optionally cause the value to change more quickly the longer the arrow is held down.

`SpinButton`s use an Adjustment object to hold information about the range of values. These Adjustment attributes are used by the Spin Button like so:

- `value`: 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.

The `SpinButton` can create a default `Adjustment`, which you can access via the `get_adjustment()` method, or you can specify an existing `Adjustment` in the constructor.

### Methods

The number of decimal places can be altered using the `set_digits()` method.

You can set the spinbutton's value using the `set_value()` method, and retrieve it with `get_value()`.

The `spin()` method 'spins' the `SpinButton`, as if one of its arrows had been clicked. You need to specify a `Gtk::SpinType` to specify the direction or new position.

To prevent the user from typing non-numeric characters into the entry box, pass `true` to the `set_numeric()` method.

To make the `SpinButton` 'wrap' between its upper and lower bounds, use the `set_wrap()` method.

To force it to snap to the nearest `step_increment`, use `set_snap_to_ticks()`.

You can modify the update policy using the `set_update_policy()` method, specifying either `Gtk::UPDATE_ALWAYS` or `Gtk::UPDATE_IF_VALID`. `Gtk::UPDATE_ALWAYS` causes the `SpinButton` to ignore errors encountered while converting the text in the entry box to a numeric value. This setting also therefore allows the `SpinButton` to accept non-numeric values. You can force an immediate update using the `update()` method.

Reference

### Example

Here's an example of a `SpinButton` in action:

Figure 6.6. SpinButton

Source Code

File: `examplewindow.h` (For use with gtkmm 3, not gtkmm 2)

    #ifndef GTKMM_EXAMPLEWINDOW_H
    #define GTKMM_EXAMPLEWINDOW_H

    #include <gtkmm.h>

    class ExampleWindow : public Gtk::Window
    {
    public:
      ExampleWindow();
      virtual ~ExampleWindow();

    protected:
      //Signal handlers:
      void on_checkbutton_snap();
      void on_checkbutton_numeric();
      void on_spinbutton_digits_changed();
      void on_button_close();

      enum enumValueFormats
      {
        VALUE_FORMAT_INT,
        VALUE_FORMAT_FLOAT
      };
      void on_button_getvalue(enumValueFormats display);

      //Child widgets:
      Gtk::Frame m_Frame_NotAccelerated, m_Frame_Accelerated;
      Gtk::HBox m_HBox_NotAccelerated, m_HBox_Accelerated,
        m_HBox_Buttons;
      Gtk::VBox m_VBox_Main, m_VBox, m_VBox_Day, m_VBox_Month, m_VBox_Year,
        m_VBox_Accelerated, m_VBox_Value, m_VBox_Digits;
      Gtk::Label m_Label_Day, m_Label_Month, m_Label_Year,
        m_Label_Value, m_Label_Digits,
        m_Label_ShowValue;
      Glib::RefPtr<Gtk::Adjustment> m_adjustment_day, m_adjustment_month, m_adjustment_year,
        m_adjustment_value, m_adjustment_digits;
      Gtk::SpinButton m_SpinButton_Day, m_SpinButton_Month, m_SpinButton_Year,
        m_SpinButton_Value, m_SpinButton_Digits;
      Gtk::CheckButton m_CheckButton_Snap, m_CheckButton_Numeric;
      Gtk::Button m_Button_Int, m_Button_Float, m_Button_Close;
    };

    #endif //GTKMM_EXAMPLEWINDOW_H

File: `examplewindow.cc` (For use with gtkmm 3, not gtkmm 2)

    #include "examplewindow.h"
    #include <iostream>
    #include <cstdio>

    ExampleWindow::ExampleWindow()
    :
      m_Frame_NotAccelerated("Not accelerated"),
      m_Frame_Accelerated("Accelerated"),
      m_VBox_Main(false, 5),
      m_Label_Day("Day: "),
      m_Label_Month("Month: "),
      m_Label_Year("Year: "),
      m_Label_Value("Value: "),
      m_Label_Digits("Digits: "),
      m_adjustment_day( Gtk::Adjustment::create(1.0, 1.0, 31.0, 1.0, 5.0, 0.0) ),
      m_adjustment_month( Gtk::Adjustment::create(1.0, 1.0, 12.0, 1.0, 5.0, 0.0) ),
      m_adjustment_year( Gtk::Adjustment::create(1998.0, 0.0, 2100.0, 1.0, 100.0, 0.0) ),
      m_adjustment_value( Gtk::Adjustment::create(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0) ),
      m_adjustment_digits( Gtk::Adjustment::create(2.0, 1.0, 5.0, 1.0, 1.0, 0.0) ),
      m_SpinButton_Day(m_adjustment_day),
      m_SpinButton_Month(m_adjustment_month),
      m_SpinButton_Year(m_adjustment_year),
      m_SpinButton_Value(m_adjustment_value, 1.0, 2),
      m_SpinButton_Digits(m_adjustment_digits),
      m_CheckButton_Snap("Snap to 0.5-ticks"),
      m_CheckButton_Numeric("Numeric only input mode"),
      m_Button_Int("Value as Int"),
      m_Button_Float("Value as Float"),
      m_Button_Close("Close")
    {
      set_title("SpinButton");

      m_VBox_Main.set_border_width(10);
      add(m_VBox_Main);

      m_VBox_Main.pack_start(m_Frame_NotAccelerated);

      m_VBox.set_border_width(5);
      m_Frame_NotAccelerated.add(m_VBox);

      /* Day, month, year spinners */

      m_VBox.pack_start(m_HBox_NotAccelerated, Gtk::PACK_EXPAND_WIDGET, 5);

      m_Label_Day.set_alignment(Gtk::ALIGN_START);
      m_VBox_Day.pack_start(m_Label_Day);

      m_SpinButton_Day.set_wrap();

      m_VBox_Day.pack_start(m_SpinButton_Day);

      m_HBox_NotAccelerated.pack_start(m_VBox_Day, Gtk::PACK_EXPAND_WIDGET, 5);

      m_Label_Month.set_alignment(Gtk::ALIGN_START);
      m_VBox_Month.pack_start(m_Label_Month);

      m_SpinButton_Month.set_wrap();
      m_VBox_Month.pack_start(m_SpinButton_Month);

      m_HBox_NotAccelerated.pack_start(m_VBox_Month, Gtk::PACK_EXPAND_WIDGET, 5);

      m_Label_Year.set_alignment(Gtk::ALIGN_START);
      m_VBox_Year.pack_start(m_Label_Year);

      m_SpinButton_Year.set_wrap();
      m_SpinButton_Year.set_size_request(55, -1);
      m_VBox_Year.pack_start(m_SpinButton_Year);

      m_HBox_NotAccelerated.pack_start(m_VBox_Year, Gtk::PACK_EXPAND_WIDGET, 5);

      //Accelerated:
      m_VBox_Main.pack_start(m_Frame_Accelerated);

      m_VBox_Accelerated.set_border_width(5);
      m_Frame_Accelerated.add(m_VBox_Accelerated);

      m_VBox_Accelerated.pack_start(m_HBox_Accelerated, Gtk::PACK_EXPAND_WIDGET, 5);

      m_HBox_Accelerated.pack_start(m_VBox_Value, Gtk::PACK_EXPAND_WIDGET, 5);

      m_Label_Value.set_alignment(Gtk::ALIGN_START);
      m_VBox_Value.pack_start(m_Label_Value);

      m_SpinButton_Value.set_wrap();
      m_SpinButton_Value.set_size_request(100, -1);
      m_VBox_Value.pack_start(m_SpinButton_Value);

      m_HBox_Accelerated.pack_start(m_VBox_Digits, Gtk::PACK_EXPAND_WIDGET, 5);

      m_Label_Digits.set_alignment(Gtk::ALIGN_START);
      m_VBox_Digits.pack_start(m_Label_Digits);

      m_SpinButton_Digits.set_wrap();
      m_adjustment_digits->signal_value_changed().connect( sigc::mem_fun(*this,
                  &ExampleWindow::on_spinbutton_digits_changed) );

      m_VBox_Digits.pack_start(m_SpinButton_Digits);

      //CheckButtons:
      m_VBox_Accelerated.pack_start(m_CheckButton_Snap);
      m_CheckButton_Snap.set_active();
      m_CheckButton_Snap.signal_clicked().connect( sigc::mem_fun(*this,
                  &ExampleWindow::on_checkbutton_snap) );

      m_VBox_Accelerated.pack_start(m_CheckButton_Numeric);
      m_CheckButton_Numeric.set_active();
      m_CheckButton_Numeric.signal_clicked().connect( sigc::mem_fun(*this,
                  &ExampleWindow::on_checkbutton_numeric) );

      //Buttons:
      m_VBox_Accelerated.pack_start (m_HBox_Buttons, Gtk::PACK_SHRINK, 5);

      m_Button_Int.signal_clicked().connect( sigc::bind( sigc::mem_fun(*this,
                      &ExampleWindow::on_button_getvalue), VALUE_FORMAT_INT) );
      m_HBox_Buttons.pack_start(m_Button_Int, Gtk::PACK_EXPAND_WIDGET, 5);

      m_Button_Float.signal_clicked().connect( sigc::bind( sigc::mem_fun(*this,
                      &ExampleWindow::on_button_getvalue), VALUE_FORMAT_FLOAT) );
      m_HBox_Buttons.pack_start(m_Button_Float, Gtk::PACK_EXPAND_WIDGET, 5);

      m_VBox_Accelerated.pack_start(m_Label_ShowValue);
      m_Label_ShowValue.set_text("0");

      //Close button:
      m_Button_Close.signal_clicked().connect( sigc::mem_fun(*this,
                  &ExampleWindow::on_button_close) );
      m_VBox_Main.pack_start(m_Button_Close, Gtk::PACK_SHRINK);

      show_all_children();
    }

    ExampleWindow::~ExampleWindow()
    {
    }

    void ExampleWindow::on_button_close()
    {
      hide();
    }

    void ExampleWindow::on_checkbutton_snap()
    {
      m_SpinButton_Value.set_snap_to_ticks( m_CheckButton_Snap.get_active() );
    }

    void ExampleWindow::on_checkbutton_numeric()
    {
      m_SpinButton_Value.set_numeric( m_CheckButton_Numeric.get_active() );
    }

    void ExampleWindow::on_spinbutton_digits_changed()
    {
      m_SpinButton_Value.set_digits( m_SpinButton_Digits.get_value_as_int() );
    }

    void ExampleWindow::on_button_getvalue(enumValueFormats display)
    {
      gchar buf[32];

      if (display == VALUE_FORMAT_INT)
        sprintf (buf, "%d", m_SpinButton_Value.get_value_as_int());
      else
        sprintf (buf, "%0.*f", m_SpinButton_Value.get_digits(),
                m_SpinButton_Value.get_value());

      m_Label_ShowValue.set_text(buf);
    }

File: `main.cc` (For use with gtkmm 3, not gtkmm 2)

    #include "examplewindow.h"
    #include <gtkmm/main.h>

    int main(int argc, char *argv[])
    {
      Gtk::Main kit(argc, argv);

      ExampleWindow window;
      //Shows the window and returns when it is closed.
      Gtk::Main::run(window);

      return 0;
    }

Entry |  | ProgressBar