9.10. Кнопка-счётчик (SpinButton)

Виджет SpinButton используется для того чтобы выбрать значение из определённого диапазона чисел. Он содержит поле ввода текста и кнопки вверх и вниз. Выбор одной из кнопок прокручивает значение вверх или вниз. Поэтому этот составной виджет можно называть "кнопка-счётчик". Поле ввода также может быть отредактировано напрямую, вводом нужного значения.

Виджет SpinButton позволяет значению иметь 0 или больше десятичных позиций, и увеличиваться/уменьшаться с определённым настроенным шагом. Зажатие одной из кнопок может приводить к ускорению изменений значения, в зависимости от времени зажатия.

Виджет SpinButton использует регулятор (см. Глава 7, Регуляторы), для хранения информации о диапазоне значений который может принимать. Это делает виджет SpinButton мощным.

Напоминаем, что виджет Adjustment создаётся с помощью следующей функции:

  adjustment = gtk.Adjustment(value=0, lower=0, upper=0, step_incr=0, page_incr=0, page_size=0)

Эти параметры регулятора используются виджетом SpinButton следующим путём:

value Начальное значение SpinButton
lower Минимальное значение
upper Максимальное значение
step_increment Значение увеличения/уменьшения при клике левой кнопкой.
page_increment Значение увеличения/уменьшения при клике правой кнопкой.
page_size Не используется

Дополнительно, третья кнопка мыши может быть использована для прыжка напрямую к минимальному или максимальному значению. Давайте посмотрим как создать SpinButton::

  spin_button = gtk.SpinButton(adjustment=None, climb_rate=0.0, digits=0)

Аргумент climb_rate принимает значение между 0.0 и 1.0, и показывает величину ускорения. Аргумент digits указывает количество отображаемых десятичных позиций.

SpinButton может быть перенастроена с помощью следующего метода:

  spin_button.configure(adjustment, climb_rate, digits)

Аргумент spin_button указывает какой из виджетов SpinButton должен быть перенастроен. Другие аргументы объяснены выше.

Регулятор может быть указан или получен с помощью следующих методов:

  spin_button.set_adjustment(adjustment)

adjustment = spin_button.get_adjustment()

Количество десятичных позиций может быть изменено с помощью:

  spin_button.set_digits(digits)

Значение отображаемое в SpinButton может быть изменено с помощью метода:

  spin_button.set_value(value)

Текущее значение SpinButton может быть получено как дробное или целое значение с помощью следующих методов:

  float_value = spin_button.get_value()

int_value = spin_button.get_value_as_int()

Если вы хотите изменить значение SpinButton относительно текущего значения, используйте следующий метод:

  spin_button.spin(direction, increment)

Параметр direction может принимать одно из следующих значений:

  SPIN_STEP_FORWARD
SPIN_STEP_BACKWARD
SPIN_PAGE_FORWARD
SPIN_PAGE_BACKWARD
SPIN_HOME
SPIN_END
SPIN_USER_DEFINED

Этот метод содержит совсем немного функционала, который мы постараемся ясно объяснить. Большинство этих настроек использует регулятор, связанный со SpinButton.

SPIN_STEP_FORWARD и SPIN_STEP_BACKWARD изменяют значение SpinButton в размере указанном в increment, за исключением того что если increment равен 0, то в таком случае значение изменяется на step_increment в регляторе.

SPIN_PAGE_FORWARD и SPIN_PAGE_BACKWARD просто меняют значение SpinButton на increment.

SPIN_HOME устанавливает минимальное значение из диапазона регулятора.

SPIN_END устанавливает максимально значение из диапазона регулятора.

SPIN_USER_DEFINED просто меняет значение SpinButton на указанную величину.

Мы уходим от методов для настройки и получения значения или диапазона, и переходим к методам, отвечающим за внешний вид и поведение виджета SpinButton.

Первый из этих методов используется для ограничения поля ввода, которое может содержать только числа. Это защищает от ввода отличных от цифр символов в поле ввода SpinButton:

  spin_button.set_numeric(numeric)

numeric  содержащий TRUE контролирует ввод в поле, и позволяет любой ввод при значении FALSE.

Вы можете выбрать будет ли SpinButton перескакивать между максимальным и минимальным значением, достигая предела, с помощью следующего метода:

  spin_button.set_wrap(wrap)

SpinButton будет перескакивать если wrap равен TRUE.

Вы можете приказать SpinButton округлять значения до ближайшего step_increment, указанного в регуляторе. Это происходит, если передать аргументу snap_to_ticks в следующем методе TRUE:

  spin_button.set_snap_to_ticks(snap_to_ticks)

Политика обновления SpinButton может быть изменена следующим методом:

  spin_button.set_update_policy(policy)

Возможные значения:

  UPDATE_ALWAYS

UPDATE_IF_VALID

Эти значения определяют поведение SpinButton при просмотре введённого текста и синхронизации его значения с регулятором.

В случае UPDATE_IF_VALID значение изменяется только если введённое значение является числом входящим в диапазон значений регулятора.  Изменит текст на текущее значение.

В случае UPDATE_ALWAYS мы игнорируем ошибки конвертации текста в числовое значение.

Наконец, вы можете явно запросить обновление для SpinButton.

  spin_button.update()

Пример spinbutton.py показывает использование виджетов SpinButton, включая настройку характеристик. Рисунок  9.11, “Пример виджетов Spin Button” показывает результат запуска программы:

Рисунок 9.11. Пример виджетов Spin Button

Spin Button Example

Исходный код spinbutton.py:

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. # example spinbutton.py
  4.  
  5. import pygtk
  6. pygtk.require('2.0')
  7. import gtk
  8.  
  9. class SpinButtonExample:
  10. def toggle_snap(self, widget, spin):
  11. spin.set_snap_to_ticks(widget.get_active())
  12.  
  13. def toggle_numeric(self, widget, spin):
  14. spin.set_numeric(widget.get_active())
  15.  
  16. def change_digits(self, widget, spin, spin1):
  17. spin1.set_digits(spin.get_value_as_int())
  18.  
  19. def get_value(self, widget, data, spin, spin2, label):
  20. if data == 1:
  21. buf = "%d" % spin.get_value_as_int()
  22. else:
  23. buf = "%0.*f" % (spin2.get_value_as_int(),
  24. spin.get_value())
  25. label.set_text(buf)
  26.  
  27. def __init__(self):
  28. window = gtk.Window(gtk.WINDOW_TOPLEVEL)
  29. window.connect("destroy", lambda w: gtk.main_quit())
  30. window.set_title("Кнопки-счётчики")
  31.  
  32. main_vbox = gtk.VBox(False, 5)
  33. main_vbox.set_border_width(10)
  34. window.add(main_vbox)
  35.  
  36. frame = gtk.Frame("Не ускоряемые")
  37. main_vbox.pack_start(frame, True, True, 0)
  38.  
  39. vbox = gtk.VBox(False, 0)
  40. vbox.set_border_width(5)
  41. frame.add(vbox)
  42.  
  43. # День, месяц, год.
  44. hbox = gtk.HBox(False, 0)
  45. vbox.pack_start(hbox, True, True, 5)
  46.  
  47. vbox2 = gtk.VBox(False, 0)
  48. hbox.pack_start(vbox2, True, True, 5)
  49.  
  50. label = gtk.Label("День :")
  51. label.set_alignment(0, 0.5)
  52. vbox2.pack_start(label, False, True, 0)
  53.  
  54. adj = gtk.Adjustment(1.0, 1.0, 31.0, 1.0, 5.0, 0.0)
  55. spinner = gtk.SpinButton(adj, 0, 0)
  56. spinner.set_wrap(True)
  57. vbox2.pack_start(spinner, False, True, 0)
  58.  
  59. vbox2 = gtk.VBox(False, 0)
  60. hbox.pack_start(vbox2, True, True, 5)
  61.  
  62. label = gtk.Label("Месяц :")
  63. label.set_alignment(0, 0.5)
  64. vbox2.pack_start(label, False, True, 0)
  65.  
  66. adj = gtk.Adjustment(1.0, 1.0, 12.0, 1.0, 5.0, 0.0)
  67. spinner = gtk.SpinButton(adj, 0, 0)
  68. spinner.set_wrap(True)
  69. vbox2.pack_start(spinner, False, True, 0)
  70.  
  71. vbox2 = gtk.VBox(False, 0)
  72. hbox.pack_start(vbox2, True, True, 5)
  73.  
  74. label = gtk.Label("Год :")
  75. label.set_alignment(0, 0.5)
  76. vbox2.pack_start(label, False, True, 0)
  77.  
  78. adj = gtk.Adjustment(2011.0, 0.0, 2100.0, 1.0, 100.0, 0.0)
  79. spinner = gtk.SpinButton(adj, 0, 0)
  80. spinner.set_wrap(False)
  81. spinner.set_size_request(55, -1)
  82. vbox2.pack_start(spinner, False, True, 0)
  83.  
  84. frame = gtk.Frame("Ускоряемые")
  85. main_vbox.pack_start(frame, True, True, 0)
  86.  
  87. vbox = gtk.VBox(False, 0)
  88. vbox.set_border_width(5)
  89. frame.add(vbox)
  90.  
  91. hbox = gtk.HBox(False, 0)
  92. vbox.pack_start(hbox, False, True, 5)
  93.  
  94. vbox2 = gtk.VBox(False, 0)
  95. hbox.pack_start(vbox2, True, True, 5)
  96.  
  97. label = gtk.Label("Значение :")
  98. label.set_alignment(0, 0.5)
  99. vbox2.pack_start(label, False, True, 0)
  100.  
  101. adj = gtk.Adjustment(0.0, -10000.0, 10000.0, 0.5, 100.0, 0.0)
  102. spinner1 = gtk.SpinButton(adj, 1.0, 2)
  103. spinner1.set_wrap(True)
  104. spinner1.set_size_request(100, -1)
  105. vbox2.pack_start(spinner1, False, True, 0)
  106.  
  107. vbox2 = gtk.VBox(False, 0)
  108. hbox.pack_start(vbox2, True, True, 5)
  109.  
  110. label = gtk.Label("Разрядов :")
  111. label.set_alignment(0, 0.5)
  112. vbox2.pack_start(label, False, True, 0)
  113.  
  114. adj = gtk.Adjustment(2, 1, 5, 1, 1, 0)
  115. spinner2 = gtk.SpinButton(adj, 0.0, 0)
  116. spinner2.set_wrap(True)
  117. adj.connect("value_changed", self.change_digits, spinner2, spinner1)
  118. vbox2.pack_start(spinner2, False, True, 0)
  119.  
  120. hbox = gtk.HBox(False, 0)
  121. vbox.pack_start(hbox, False, True, 5)
  122.  
  123. button = gtk.CheckButton("Округлять до 0.5")
  124. button.connect("clicked", self.toggle_snap, spinner1)
  125. vbox.pack_start(button, True, True, 0)
  126. button.set_active(True)
  127.  
  128. button = gtk.CheckButton("Только числовой ввод")
  129. button.connect("clicked", self.toggle_numeric, spinner1)
  130. vbox.pack_start(button, True, True, 0)
  131. button.set_active(True)
  132.  
  133. val_label = gtk.Label("")
  134.  
  135. hbox = gtk.HBox(False, 0)
  136. vbox.pack_start(hbox, False, True, 5)
  137. button = gtk.Button("Значение как Int")
  138. button.connect("clicked", self.get_value, 1, spinner1, spinner2,
  139. val_label)
  140. hbox.pack_start(button, True, True, 5)
  141.  
  142. button = gtk.Button("Значение как Float")
  143. button.connect("clicked", self.get_value, 2, spinner1, spinner2,
  144. val_label)
  145. hbox.pack_start(button, True, True, 5)
  146.  
  147. vbox.pack_start(val_label, True, True, 0)
  148. val_label.set_text("0")
  149.  
  150. hbox = gtk.HBox(False, 0)
  151. main_vbox.pack_start(hbox, False, True, 0)
  152.  
  153. button = gtk.Button(gtk.STOCK_CLOSE, gtk.STOCK_CLOSE)
  154. button.connect("clicked", lambda w: gtk.main_quit())
  155. hbox.pack_start(button, True, True, 5)
  156. window.show_all()
  157.  
  158. def main():
  159. gtk.main()
  160. return 0
  161.  
  162. if __name__ == "__main__":
  163. SpinButtonExample()
  164. main()
  165.