Le widget calendrier est une moyen efficace d'afficher et de retrouver des informations liées aux dates. C'est un widget très simple à créer et à utiliser.
Créer un widget calendrier est aussi simple que :
$calendar = new Gtk::Calendar();
Il arrive parfois que vous ayez beaucoup d'informations à changer à l'intérieur de ce widget. Les fonctions suivantes vous permettent de faire de multiples changements sans que l'utilisateur voient les multiples mises à jour à l'écran :
$calendar->freeze();$calendar->thaw();
Elles fonctionnent comme les fonctions freeze et thaw des autres
widgets.
Le widget calendrier possède quelques options qui vous permettent de changer le look du widget ainsi que la manière dont il opère :
$calendar->display_options( $flags );
L'argument $flag peut être formé en combinant les cinq options suivantes
:
'heading' - cette option spécifie que le mois et l'année doivent être
montrés quand on dessine le calendrier.
'show_day_names' - cette option spécifie que les trois premières lettres
de chaque jour doivent être affichées ( e.g. MON, TUE,...)
'no_month_change' - cette option stipule que l'utilisateur ne devrait
pas et ne peut pas changer le mois affiché. Cela peut être bon si vous avez
seulement besoin d'un mois particulier, par exemple quand vous afficher 12 widgets
calendrier pour chaque mois d'une année particulière.
'show_week_numbers' - cette option spécifie que le numéro de chaque semaine
doit être affiché sous le côté gauche sur calendrier ( e.g. Jan 1 = Week 1,
Dec 31 = Week 52 ).
week_start_monday' - cette option stipule que le premier jour de la semaine
est lundi à la place de dimanche qui est la valeur par défaut. Cela affecte
uniquement l'ordre dans lequel sont affichés les jours de la gauche vers la
droite.
Les fonctions suivantes sont utilisées pour déclarer la date courante affichée :
$calendar->selected_month ( $ mois , $année ) ;$calendar->selected_day ( $jour );
La valeur de retour de selected_month est une valeur booléenne qui indique
si la sélection est réussie.
Avec selected_day, le nombre spécifié est sélectionné à l'intérieur du
mois courant, si c'est possible. Une valeur $jour de 0 déselectionnera
la sélection courante.
En plus d'avoir un jour sélectionné, n'importe quel nombre de jour dans le mois peuvent être ``marqués''. Un jour marqué est surligné dans l'affichage du calendrier. Les fonctions suivantes sont fournies pour manipuler les jours marqués :
$calendar->mark_day ( $jour ) ;$calendar->unmark_day ( $jour );
$calendar->clear_marks();
Les jours marqués actuellement sont stockés dans un tableau. Ce tableau est composé de 31 éléments ainsi si vous voulez savoir si un jour est marqué, vous devez accéder à l'élément correspondant du tableau ( n'oubliez pas que les éléments d'un tableau sont numérotés de 0 à n-1 ). Par exemple :
if ( $calendar->marked_date [ $jour - 1 ] )
{
print ( ``Le jour $jour est marqué.\n );
}
Notez que les marques sont persistantes à travers les changements de mois et d'années.
La dernière fonction concernant le calendrier est utilisée pour retrouver la date courante sélectionnée.
( $ année , $mois , $jour ) = $calendar->get_date();
Le widget calendrier peut générer un nombre de signaux indiquant les sélections de dates et les changements. Les noms des signaux sont très explicites :
'month_changed' - mois changé
'day_selected' - jour sélectionné
'day_selected_double_click' - jour sélectionné par un double clic
'prev_month' - mois précédent
'next_month' - mois suivant
'prev_year' - année précédente
'next_year' - année suivante
Il ne nous reste plus qu'à mettre ensemble toutes ces fonctions. On obtient :
#!/usr/bin/perl -wuse Gtk;
use strict;
Gtk->set_locale();
init Gtk;
my $false = 0;
my $true = 1;
my $year_base = 1900;
my $i;
my @flags = ( "Show Heading", # Montre les titres "Show Day Names", # Montre les noms des mois "No Month Change", # Pas de changement de mois "Show Week Numbers", # Montre les numéros de semaine "Week Start Monday" ); # La semaine commence Lundi
my %calendar_data = ( "", "" );
my $window;
my $vbox;
my $vbox2;
my $vbox3;
my $hbox;
my $hbbox;
my $calendar;
my $toggle;
my $button;
my $frame;
my $separator;
my $label;
my $bbox;
$calendar_data{ "window" } = undef;
$calendar_data{ "font" } = undef;
$calendar_data{ "font_dialog" } = undef;
$calendar_data{ "settings" } = [ 0, 0, 0, 0, 0 ];
$window = new Gtk::Window( 'toplevel' );
$window->set_title( "Calendar Example" );
$window->border_width( 5 );
$window->signal_connect( 'destroy', sub { Gtk->exit( 0 ); } );
$window->signal_connect( 'delete-event', \>k_false );
$window->set_policy( $false, $false, $true );
$vbox = new Gtk::VBox( $false, 10 );
$window->add( $vbox );
# La partie haute de la fenêtre, Calendrier, flags et fontsel.
$hbox = new Gtk::HBox( $false, 10 );
$vbox->pack_start( $hbox, $true, $true, 10 );
$hbbox = new Gtk::HButtonBox();
$hbox->pack_start( $hbbox, $false, $false, 10 );
$hbbox->set_layout( 'spread' );
$hbbox->set_spacing( 5 );
# Le widget calendrier
$frame = new Gtk::Frame( "Calendar" );
$hbbox->pack_start( $frame, $false, $true, 10 );
$calendar = new Gtk::Calendar();
$calendar_data{ "window" } = $calendar;
calendar_set_flags();
$calendar->mark_day( 19 );
$frame->add( $calendar );
$calendar->signal_connect( 'month_changed', \&calendar_month_changed );
$calendar->signal_connect( 'day_selected', \&calendar_day_selected );
$calendar->signal_connect( 'day_selected_double_click', \&calendar_day_selected_double_click );
$calendar->signal_connect( 'prev_month', \&calendar_prev_month );
$calendar->signal_connect( 'next_month', \&calendar_next_month );
$calendar->signal_connect( 'prev_year', \&calendar_prev_year );
$calendar->signal_connect( 'next_year', \&calendar_next_year );
$separator = new Gtk::VSeparator();
$hbox->pack_start( $separator, $false, $true, 0 );
$vbox2 = new Gtk::VBox( $false, 10 );
$hbox->pack_start( $vbox2, $false, $false, 10 );
# Construit le bon cadre avec le flag à l'intérieur
$frame = new Gtk::Frame( "Flags" );
$vbox2->pack_start( $frame, $true, $true, 10 );
$vbox3 = new Gtk::VBox( $true, 5 );
$frame->add( $vbox3 );
for ( $i = 0; $i < 5; $i++ ) { $toggle = new Gtk::CheckButton( $flags[ $i ] ); $toggle->signal_connect( 'toggled', \&calendar_toggle_flag ); $vbox3->pack_start( $toggle, $true, $true, 0 ); $calendar_data{ 'flag_checkboxes' }[ $i ] = $toggle; }
# Contruit le bon bouton de police
$button = new Gtk::Button( "Font..." );
$button->signal_connect( 'clicked', \&calendar_select_font );
$vbox2->pack_start( $button, $false, $false, 0 );
# Construit la partie signaux et évènements
$frame = new Gtk::Frame( "Signal Events" );
$vbox->pack_start( $frame, $true, $true, 10 );
$vbox2 = new Gtk::VBox( $true, 5 );
$frame->add( $vbox2 );
$hbox = new Gtk::HBox( $false, 3 );
$vbox2->pack_start( $hbox, $false, $true, 0 );
$label = new Gtk::Label( "Signal:" );
$hbox->pack_start( $label, $false, $true, 0 );
$calendar_data{ "last_sig" } = new Gtk::Label( "" );
$hbox->pack_start( $calendar_data{ "last_sig" }, $false, $true, 0 );
$hbox = new Gtk::HBox( $false, 3 );
$vbox2->pack_start( $hbox, $false, $true, 0 );
$label = new Gtk::Label( "Previous Signal:" );
$hbox->pack_start( $label, $false, $true, 0 );
$calendar_data{ "prev_sig" } = new Gtk::Label( "" );
$hbox->pack_start( $calendar_data{ "prev_sig" }, $false, $true, 0 );
$hbox = new Gtk::HBox( $false, 3 );
$vbox2->pack_start( $hbox, $false, $true, 0 );
$label = new Gtk::Label( "Second Previous Signal:" );
$hbox->pack_start( $label, $false, $true, 0 );
$calendar_data{ "prev2_sig" } = new Gtk::Label( "" );
$hbox->pack_start( $calendar_data{ "prev2_sig" }, $false, $true, 0 );
$bbox = new Gtk::HButtonBox();
$vbox->pack_start( $bbox, $false, $false, 0 );
$bbox->set_layout( 'end' );
$button = new Gtk::Button( "Close" );
$button->signal_connect( 'clicked', sub { Gtk->exit( 0 ); } );
$bbox->add( $button );
$button->can_default( $true );
$button->grab_default();
$window->show_all();
main Gtk;
exit( 0 );
### Routines
sub calendar_date_to_string { my $string; my $year; my $month; my $day; my @months = qw( January February March April May June July August September October November December ); ( $year, $month, $day ) = $calendar_data{ 'window' }->get_date(); $string = $months[ $month ] . " " . $day . ", " . $year; return ( $string ); }
sub calendar_set_signal_strings { my ( $sig_str ) = @_; my $prev_sig; $prev_sig = $calendar_data{ 'prev_sig' }->get(); $calendar_data{ 'prev2_sig' }->set( $prev_sig ); $prev_sig = $calendar_data{ 'last_sig' }->get(); $calendar_data{ 'prev_sig' }->set( $prev_sig ); $calendar_data{ 'last_sig' }->set( $sig_str ); }
sub calendar_month_changed { my $buffer = "month_changed: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); }
sub calendar_day_selected { my $buffer = "day_selected: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); }
sub calendar_day_selected_double_click { my $year; my $month; my $day; my $buffer; $buffer = "day_selected_double_click: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); ( $year, $month, $day ) = $calendar_data{ 'window' }->get_date(); if ( $calendar_data{ 'window' }->marked_date( $day - 1 ) == 0 ) { $calendar_data{ 'window' }->mark_day( $day ); } else { $calendar_data{ 'window' }->unmark_day( $day ); } }
sub calendar_prev_month { my $buffer = "prev_month: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); }
sub calendar_next_month { my $buffer = "next_month: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); }
sub calendar_prev_year { my $buffer = "prev_year: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); }
sub calendar_next_year { my $buffer = "next_year: " . calendar_date_to_string(); calendar_set_signal_strings( $buffer ); }
sub calendar_set_flags { my $i; my $options = 0; for ( $i = 0; $i < 5; $i++ ) { if ( $calendar_data{ 'settings' }[ $i ] ) { $options = $options + ( 1 << $i ); } } if ( $calendar_data{ 'window' } ) { $calendar_data{ 'window' }->display_options( $options ); } }
sub calendar_toggle_flag { my ( $toggle ) = @_; my $i; my $j = 0; for ( $i = 0; $i < 5; $i++ ) { if ( $calendar_data{ 'flag_checkboxes' }[ $i ] == $toggle ) { $j = $i; } } $calendar_data{ 'settings' }[$j] = not $calendar_data{ 'settings' }[$j]; calendar_set_flags(); }
sub calendar_font_selection_ok { ### Il y a une erreur dans cette fonction. Aucune erreur n'est reportée ### Mais la police ne change pas. Envoyez moi la solution si vous l'avez ### à swilhelm@computer.org. ### Désolé pour les inconvénients. my ( $button ) = @_; my $style; my $font; $calendar_data{'font'} = $calendar_data{ 'font_dialog' }->get_font_name(); if ( $calendar_data{ 'window' } ) { $font = $calendar_data{ 'font_dialog' }->get_font(); if ( $font ) { $style = $calendar_data{ 'window' }->get_style()->copy(); $style->{ 'font' } = $font; $calendar_data{ 'window' }->set_style( $style ); } } }
sub calendar_select_font { my ( $button ) = @_; my $window; if ( $calendar_data{ 'font_dialog' } ) { $window = $calendar_data{ 'font_dialog' }; } else { $window = new Gtk::FontSelectionDialog( "Font Selection Dialog" ); $window->position( 'mouse' ); $window->signal_connect( 'destroy', sub { $window->destroyed(); } ); $window->ok_button->signal_connect( 'clicked', \&calendar_font_selection_ok ); $window->cancel_button->signal_connect( 'clicked', sub { $window->hide(); } ); $calendar_data{ 'font_dialog' } = $window; } if ( $window->visible ) { $window->destroy(); } else { $window->show(); }
}