Виджеты диапазона

Иерархия наследования

Object +--- Widget +--- Range

Категория диапазона включает в себя наиболее часто встречающийся скроллбар-виджет и почти идентичный по своим действиям скейл-виджет. Весь спектр виджетов имеет общие графические элементы, в каждом из которых есть свое окно X-сисетмы, которое обменивается событиями о своем изменении. Все они содержат окно прокрутки и ползунок(иногда называемый thumbwheel в других GUI - графический пользовательский интерфейс). Соответственно положение ползунка можно изменять, либо кликать на полоске прокрутки(подобно тому, как это сделано при проигрывании mp3 в xmms или winamp). Согласно вышеописанному выравниванию, величина области, где бегает ползунок, пропорционально постраивается под значения переменных, свойственных для этого виджета.

Основные функции виджетов диапазона.

Класс виджетов диапазона довольно сложен внутренне, но, подобно всем базовым классам виджетов, большинство его особенностей представляют интерес для того, кто хочет сам программировать свойства классов. Почти все функции и исгналы являются специфическими для данного класса, но, тем не менее, имеется несколько широкоиспользуемых функций, которые работают для всх виджетов диапазона.

"update policy" определяет когда во время работы пользователя происходит изменение переменных, влияющих на выравнивание(относительное построение? - перевести кусок текста заново). Правила изменения

'continuous' - по умолчанию, сигнал 'value_changed' испускается непрерывно, даже при малейших изменениях ползунка.

'discontinuous' - 'value_changed' испускается, когда ползунок перемещен и кнопка манипулятора "МЫШЬ" отпущена.

'delayed' - 'value_changed' появляется, когда юзер отпускает кнопку мыши или когда ползунок неподвижен в течении какого-то короткого времени. Функция, с помощью которой можно переопределять эти свойства, выглядить так:

$range->set_update_policy( $policy );

Получение и установка диапазона на лету выполняется примерно так:

$range->get_adjustment();

$range->set_adjustment( $adjustment );

get_adjustment() возвращает выравнивание, с которым связана переменная $range and set_adjustment() does absolutely nothing if you pass it the adjustment that the Range is already using, regardless of whether you changed any of its fields or not. If you pass it a new Adjustment, it will unreference the old one if it exists (possibly destroying it), connect the appropriate signals to the new one, and call the private function adjustment_changed(), which will (or at least, is supposed to...) recalculate the size and/or position of the slider and redraw if necessary. As mentioned in the section on adjustments, if you wish to reuse the same Adjustment, when you modify its values directly, you should emit the "changed" signal on it, like this:

$adjustment->signal_emit( "changed" );

Все виджеты диапазона GTK реагируют на нажатие мышиной клавиши более или менее одинаково. Нажатие в области прокрутки соответственно изменяет значение page_increment вичитая или добавляя его к текущей величине. В соответствии с этими действиями так-же перемещается и бегунок(slider). Щелчок любой кнопкой мыши на стрелках полосы прокрутки(скроллбара) заставляет изменяться step_increment.

Скроллбары и скейл-виджеты в GTK могут менять фокус в соответствии с нажатием клавиш на клавиатуре. Если необходимо отключить фокусировку на виджете, то это можно сделать при помощи функции

$scrollbar->unset_flags( 'focus' );

(пропущено о том, что есть невеликие различия между горизонтальными и вертикальными виджетами)

Пример кода, который показывает действия описанных свойств виджетов диапазона. #!/usr/bin/perl -w use Gtk; use strict; set_locale Gtk; init Gtk; my $false = 0; my $true = 1; my $hscale; my $vscale; my $window; my $box1; my $box2; my $box3; my $button; my $scrollbar; my $separator; my $opt; my $menu; my $item; my $label; my $scale; my $adj1; my $adj2; # Стандартное создание виджета X-window $window = new Gtk::Window( "toplevel" ); $window->set_title( "range controls" ); $window->signal_connect( "destroy", sub { Gtk->exit( 0 ); } ); $box1 = new Gtk::VBox( $false, 0 ); $window->add( $box1 ); $box1->show(); $box2 = new Gtk::HBox( $true, 10 ); $box2->border_width( 10 ); $box1->pack_start( $box2, $true, $true, 0 ); $box2->show(); # value, lower, upper, step_increment, page_increment, page_size #обратим внимание, что переменная page_size показывает разницу #между скроллбар-виджетом и максимальным значением, #которое получается после взаимодействия(еще раз перевести) # Note that the page_size value only makes a difference for # scrollbar widgets, and the highest value you'll get is actually # (upper - page_size). $adj1 = new Gtk::Adjustment( 0.0, 0.0, 101.0, 0.1, 1.0, 1.0 ); $vscale = new Gtk::VScale( $adj1 ); scale_set_default_values( $vscale ); $box2->pack_start( $vscale, $true, $true, 0 ); $vscale->show(); $box3 = new Gtk::VBox( $false, 10 ); $box2->pack_start( $box3, $true, $true, 0 ); $box3->show(); # Reuse the same adjustment # повторное использование того-же самого выравнивания $hscale = new Gtk::HScale( $adj1 ); $hscale->set_usize( 200, 30 ); scale_set_default_values( $hscale ); $box3->pack_start( $hscale, $true, $true, 0 ); $hscale->show(); # Reuse the same adjustment again # еще одно повторное использование $scrollbar = new Gtk::HScrollbar( $adj1 ); # сделать обновление мгновенным в соответствии с положением скроллбара $scrollbar->set_update_policy( 'continuous' ); $box3->pack_start( $scrollbar, $true, $true, 0 ); $scrollbar->show(); $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); $box1->pack_start( $box2, $true, $true, 0 ); $box2->show(); # A checkbutton to control whether the value is displayed or not # Чекбокс, указывающий, показывать или нет значение переменной $button = new Gtk::CheckButton( "Display value on scale widgets" ); $button->set_active( $true ); $button->signal_connect( "toggled", \&cb_draw_value ); $box2->pack_start( $button, $true, $true, 0 ); $button->show(); $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); # An option menu to change the position of the value # меню для выбора положения переменной $label = new Gtk::Label( "Scale Value Position:" ); $box2->pack_start( $label, $false, $false, 0 ); $label->show(); $opt = new Gtk::OptionMenu(); $menu = new Gtk::Menu(); $item = make_menu_item( "Top", \&cb_pos_menu_select, 'top' ); $menu->append( $item ); $item = make_menu_item( "Bottom", \&cb_pos_menu_select, 'bottom' ); $menu->append( $item ); $item = make_menu_item( "Left", \&cb_pos_menu_select, 'left' ); $menu->append( $item ); $item = make_menu_item( "Right", \&cb_pos_menu_select, 'right' ); $menu->append( $item ); $opt->set_menu( $menu ); $box2->pack_start( $opt, $true, $true, 0 ); $opt->show(); $box1->pack_start( $box2, $true, $true, 0 ); $box2->show(); $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); # Yet another option menu, this time for the update policy of the # scale widgets $label = new Gtk::Label( "Scale Update Policy:" ); $box2->pack_start( $label, $false, $false, 0 ); $label->show(); $opt = new Gtk::OptionMenu(); $menu = new Gtk::Menu(); $item = make_menu_item ("Continuous", \&cb_update_menu_select, 'continuous' ); $menu->append( $item ); $item = make_menu_item ("Discontinuous", \&cb_update_menu_select, 'discontinuous' ); $menu->append( $item ); $item = make_menu_item ("Delayed", \&cb_update_menu_select, 'delayed' ); $menu->append( $item ); $opt->set_menu( $menu ); $box2->pack_start( $opt, $true, $true, 0 ); $opt->show(); $box1->pack_start( $box2, $true, $true, 0 ); $box2->show(); $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); # An HScale widget for adjusting the number of digits on the # sample scales. $label = new Gtk::Label( "Scale Digits:" ); $box2->pack_start( $label, $false, $false, 0 ); $label->show(); $adj2 = new Gtk::Adjustment( 1.0, 0.0, 5.0, 1.0, 1.0, 0.0 ); $adj2->signal_connect( "value_changed", \&cb_digits_scale ); $scale = new Gtk::HScale( $adj2 ); $scale->set_digits( 0 ); $box2->pack_start( $scale, $true, $true, 0 ); $scale->show(); $box1->pack_start( $box2, $true, $true, 0 ); $box2->show(); $box2 = new Gtk::HBox( $false, 10 ); $box2->border_width( 10 ); # And, one last HScale widget for adjusting the page size of the scrollbar $label = new Gtk::Label( "Scrollbar Page Size:" ); $box2->pack_start( $label, $false, $false, 0 ); $label->show(); $adj2 = new Gtk::Adjustment( 1.0, 1.0, 101.0, 1.0, 1.0, 0.0 ); $adj2->signal_connect( "value_changed", \&cb_page_size, $adj1 ); $scale = new Gtk::HScale( $adj2 ); $scale->set_digits( 0 ); $box2->pack_start( $scale, $true, $true, 0 ); $scale->show(); $box1->pack_start( $box2, $true, $true, 0 ); $box2->show(); $separator = new Gtk::HSeparator(); $box1->pack_start( $separator, $false, $true, 0 ); $separator->show(); $box2 = new Gtk::VBox( $false, 10 ); $box2->border_width( 10 ); $box1->pack_start( $box2, $false, $true, 0 ); $box2->show(); $button = new Gtk::Button( "Quit" ); $button->signal_connect( "clicked", sub { Gtk->exit( 0 ); } ); $box2->pack_start( $button, $true, $true, 0 ); $button->can_default( $true ); $button->grab_default(); $button->show(); $window->show(); main Gtk; exit( 0 ); ### Subroutines sub cb_pos_menu_select { my ( $item, $pos ) = @_; # Set the value position on both scale widgets $hscale->set_value_pos( $pos ); $vscale->set_value_pos( $pos ); } sub cb_update_menu_select { my ( $item, $policy ) = @_; # Set the update policy for both scale widgets $hscale->set_update_policy( $policy ); $vscale->set_update_policy( $policy ); } sub cb_digits_scale { my ( $adj ) = @_; # Set the number of decimal places to which adj->value is rounded $hscale->set_digits( $adj->value ); $vscale->set_digits( $adj->value ); } sub cb_page_size { my ( $get, $set ) = @_; # Set the page size and page increment size of the sample # adjustment to the value specified by the "Page Size" scale $set->page_size( $get->value ); $set->page_increment( $get->value ); # Now emit the "changed" signal to reconfigure all the widgets # that are attached to this adjustment $set->signal_emit_by_name( "changed" ); } sub cb_draw_value { my ( $button ) = @_; # Turn the value display on the scale widgets off or on depending # on the state of the checkbutton $hscale->set_draw_value( $button->active ); $vscale->set_draw_value( $button->active ); } # Convenience functions sub make_menu_item { my ( $name, $callback, $data ) = @_; my $item; $item = new Gtk::MenuItem( $name ); $item->signal_connect( "activate", $callback, $data ); $item->show(); return $item; } sub scale_set_default_values { my ( $scale ) = @_; $scale->set_update_policy( 'continuous' ); $scale->set_digits( 1 ); $scale->set_value_pos( 'top' ); $scale->set_draw_value( $true ); } # END EXAMPLE PROGRAM (поместить скриншот)

Можно заметить, что программа не вызывает функцию signal_connect() для 'delete_event', но вызывает для сигнала 'destroy', так как необработанный сигнал 'Delete_event' будет завершен сигналом 'destroy', закрывающим окно.