微调按钮(SpinButton)

SpinButton允许用户从一个数值范围内选择一个值。它包含了一个Entry部件在其侧边有递增和递减按钮。单击按钮会使得值在可能的范围内“旋转”。你也可以直接在Entry部件中输入一个值。

这个值的小数位可以进行调整,步长也可以进行配置。SpinButton具有“自动重复”功能:长按递增、递减按钮该值的变化速度会越来越快。

SpinButton使用调整(Adjustment)对象保存值的范围信息。下述调整属性由微调按钮使用:

  • value:微调按钮的值
  • lower:微调按钮允许的最小值
  • upper:微调按钮允许的最大值
  • step_increment:鼠标键1(通常是左键)点击一下递增/递减的值
  • page_increment:鼠标键2(通常是右键)点击一下递增/递减的值
  • page_size:目前没作用

另外,鼠标键3(通常是中键)用于直接跳到upperlower values。

SpinButton可以创建一个默认状态的Adjustment,然后你可以调用get_adjustment()方法访问这个Adjustment,也可以通过SpinButton的构造函数直接使用一个已经存在的Adjustment

8.3.1. 方法

数值的小数位可以使用set_digits()方法进行调整。

你可以使用set_value()方法设置微调按钮的值,也可以使用get_value()方法获得微调按钮的值。

spin()方法的行为和手动点击递增/递减按钮一样。你需要传递一个Gtk::SpinType对象给该方法以指定是递增还是递减。

true传递给set_numeric()方法可以阻止用户在条目框内输入非数字字符。

使用set_wrap()方法指定SpinButton的值到达上下限的时候是否绕回。

使用set_snap_to_ticks()方法可以在向微调按钮设置了无效值的时候强制校正到最接近step_increment策略可达到的有效值。

参考

8.3.2. 示例

这是一个使用SpinButton的示例:

Figure 8-6微调按钮(SpinButton)

源代码

File: examplewindow.h (For use with gtkmm 4)

#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::Box m_HBox_NotAccelerated, m_HBox_Accelerated,
    m_HBox_Buttons;
  Gtk::Box 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: main.cc (For use with gtkmm 4)

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

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<ExampleWindow>(argc, argv);
}

File: examplewindow.cc (For use with gtkmm 4)

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

ExampleWindow::ExampleWindow()
:
  m_Frame_NotAccelerated("Not accelerated"),
  m_Frame_Accelerated("Accelerated"),
  m_VBox_Main(Gtk::Orientation::VERTICAL, 5),
  m_VBox(Gtk::Orientation::VERTICAL),
  m_VBox_Day(Gtk::Orientation::VERTICAL),
  m_VBox_Month(Gtk::Orientation::VERTICAL),
  m_VBox_Year(Gtk::Orientation::VERTICAL),
  m_VBox_Accelerated(Gtk::Orientation::VERTICAL),
  m_VBox_Value(Gtk::Orientation::VERTICAL),
  m_VBox_Digits(Gtk::Orientation::VERTICAL),
  m_Label_Day("Day: ", Gtk::Align::START),
  m_Label_Month("Month: ", Gtk::Align::START),
  m_Label_Year("Year: ", Gtk::Align::START),
  m_Label_Value("Value: ", Gtk::Align::START),
  m_Label_Digits("Digits: ", Gtk::Align::START),
  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(2012.0, 1.0, 2200.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_margin(10);
  set_child(m_VBox_Main);

  m_VBox_Main.append(m_Frame_NotAccelerated);

  m_VBox.set_margin(5);
  m_Frame_NotAccelerated.set_child(m_VBox);

  /* Day, month, year spinners */

  m_VBox.set_spacing(5);
  m_VBox.append(m_HBox_NotAccelerated);

  m_Label_Day.set_expand();
  m_VBox_Day.append(m_Label_Day);

  m_SpinButton_Day.set_wrap();
  m_SpinButton_Day.set_expand();
  m_VBox_Day.append(m_SpinButton_Day);

  m_HBox_NotAccelerated.set_spacing(5);
  m_HBox_NotAccelerated.append(m_VBox_Day);

  m_Label_Month.set_expand();
  m_VBox_Month.append(m_Label_Month);

  m_SpinButton_Month.set_wrap();
  m_SpinButton_Month.set_expand();
  m_VBox_Month.append(m_SpinButton_Month);

  m_HBox_NotAccelerated.append(m_VBox_Month);

  m_Label_Year.set_expand();
  m_VBox_Year.append(m_Label_Year);

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

  m_HBox_NotAccelerated.append(m_VBox_Year);

  //Accelerated:
  m_VBox_Main.append(m_Frame_Accelerated);

  m_VBox_Accelerated.set_margin(5);
  m_Frame_Accelerated.set_child(m_VBox_Accelerated);

  m_VBox_Accelerated.set_spacing(5);
  m_VBox_Accelerated.append(m_HBox_Accelerated);

  m_HBox_Accelerated.append(m_VBox_Value);

  m_Label_Value.set_expand();
  m_VBox_Value.append(m_Label_Value);

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

  m_HBox_Accelerated.append(m_VBox_Digits);

  m_VBox_Digits.append(m_Label_Digits);
  m_Label_Digits.set_expand();

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

  m_VBox_Digits.append(m_SpinButton_Digits);
  m_SpinButton_Digits.set_expand();

  //CheckButtons:
  m_VBox_Accelerated.append(m_CheckButton_Snap);
  m_CheckButton_Snap.set_expand();
  m_CheckButton_Snap.set_active();
  m_CheckButton_Snap.signal_toggled().connect( sigc::mem_fun(*this,
              &ExampleWindow::on_checkbutton_snap) );

  m_VBox_Accelerated.append(m_CheckButton_Numeric);
  m_CheckButton_Numeric.set_expand();
  m_CheckButton_Numeric.set_active();
  m_CheckButton_Numeric.signal_toggled().connect( sigc::mem_fun(*this,
              &ExampleWindow::on_checkbutton_numeric) );

  //Buttons:
  m_VBox_Accelerated.append(m_HBox_Buttons);

  m_Button_Int.signal_clicked().connect( sigc::bind( sigc::mem_fun(*this,
                  &ExampleWindow::on_button_getvalue), VALUE_FORMAT_INT) );
  m_HBox_Buttons.set_spacing(5);
  m_HBox_Buttons.append(m_Button_Int);
  m_Button_Int.set_expand();

  m_Button_Float.signal_clicked().connect( sigc::bind( sigc::mem_fun(*this,
                  &ExampleWindow::on_button_getvalue), VALUE_FORMAT_FLOAT) );
  m_HBox_Buttons.append(m_Button_Float);
  m_Button_Float.set_expand();

  m_VBox_Accelerated.append(m_Label_ShowValue);
  m_Label_ShowValue.set_expand();
  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.append(m_Button_Close);
}

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);
}