9.12. Calendario

El control Calendar (Calendario) es una forma efectiva para visualizar y obtener información relativa a fechas mensuales. Es un control muy fácil de usar y trabajar con él.

Crear un control GtkCalendar es tan simple como:

  calendar = gtk.Calendar()

El calendario mostrará el mes y el año actual de manera predeterminada.

Puede haber ocasiones en las que necesites cambiar mucha información dentro de este control y los siguientes métodos te permitirán realizar múltiples cambios al control Calendar sin que el usuario vea muchos cambios en pantalla.

  calendar.freeze() # congelar

  calendar.thaw()   # reanudar

Funcionan exactamente igual que los métodos freeze/thaw de cualquier otro control.

El control Calendar tiene unas cuantas opciones que te permiten cambiar la manera en la que el control se visualiza y se comporta usando el método:

  calendar.display_options(flags)

El argumento flags (banderas) se puede formar combinando cualquiera de las siguientes cinco opciones usando el operador lógico (|):

CALENDAR_SHOW_HEADINGesta opción especifica que el mes y el año deben mostrarse cuando se dibuje el calendario.
CALENDAR_SHOW_DAY_NAMESesta opción especifica que la descripción de tres letras para cada día (Lun, Mar, etc.) debe mostrarse.
CALENDAR_NO_MONTH_CHANGEesta opción dice que el usuario no podrá cambiar el mes que se muestra. Esto puede ser bueno si sólo necesitas mostrar un mes en particular como cuando muestras 12 controles de calendario uno para cada mes dentro de un mes en particular.
CALENDAR_SHOW_WEEK_NUMBERSesta opción especifica que se muestre el número de cada semana en la parte de abajo izquierda del calendario (ejemplo: Enero 1 = Semana 1, Diciembre 31 = Semana 52).
CALENDAR_WEEK_START_MONDAYesta opción dice que la semana empezará en Lunes en lugar de en Domingo, que es el valor predeterminado. Esto solo afecta al orden en el que se muestran los días de izquierda a derecha.

Los siguientes métodos se usan para fijar la fecha que se muestra:

  result = calendar.select_month(month, year)

  calendar.select_day(day)

El valor que devuelve el método select_month() es un valor booleano que indica si la selección tuvo éxito.

Con el método select_day() el día especificado se selecciona dentro del mes actual, si eso es posible. Un valor para el día de 0 limpiará la selección actual.

Además de tener un día seleccionado, un número arbitrario de días se pueden "marcar". Un día marcado se destaca en el calendario. Los siguientes métodos se proporcionan para manipular días marcados:

  result = calendar.mark_day(day)

  result = calendar.unmark_day(day)

  calendar.clear_marks()

mark_day() y unmark_day() devuelven un valor booleano que indica si el método tuvo éxito. Fíjate que las marcas son persistentes entre cambios de meses y años.

El último método del control Calendar se usa para obtener la fecha seleccionada, mes y/o año.

  año, mes, día = calendar.get_date()

El control Calendar puede generar varias señales que indican la selección y cambio de la fecha. Los nombres de estas señales son autoexplicativos, y son:

  month_changed # cambio de mes

  day_selected  # día seleccionado

  day_selected_double_click # doble clic en día seleccionado

  prev_month    # mes anterior

  next_month    # mes siguiente

  prev_year     # año anterior

  next_year     # año siguiente

Esto nos deja con la necesidad de poner todo esto junto en el programa de ejemplo calendar.py . La figura Figura 9.12. Ejemplo de Calendario muestra el resultado del programa:

Figura 9.12. Ejemplo de Calendario

Ejemplo de Calendario

El código fuente es calendar.py:

    1   #!/usr/bin/env python
    2   
    3   # example calendar.py
    4	#
    5	# Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gronlund
    6	# Copyright (C) 2000 Tony Gale
    7	# Copyright (C) 2001-2002 John Finlay
    8	#
    9	# This program is free software; you can redistribute it and/or modify
   10	# it under the terms of the GNU General Public License as published by
   11	# the Free Software Foundation; either version 2 of the License, or
   12	# (at your option) any later version.
   13	#
   14	# This program is distributed in the hope that it will be useful,
   15	# but WITHOUT ANY WARRANTY; without even the implied warranty of
   16	# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17	# GNU General Public License for more details.
   18	#
   19	# You should have received a copy of the GNU General Public License
   20	# along with this program; if not, write to the Free Software
   21	# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   22	
   23	import gtk, pango
   24	import time
   25	
   26	class CalendarExample:
   27	    DEF_PAD = 10
   28	    DEF_PAD_SMALL = 5
   29	    TM_YEAR_BASE = 1900
   30	
   31	    calendar_show_header = 0
   32	    calendar_show_days = 1
   33	    calendar_month_change = 2 
   34	    calendar_show_week = 3
   35	    calendar_monday_first = 4
   36	
   37	    def calendar_date_to_string(self):
   38	        year, month, day = self.window.get_date()
   39	        mytime = time.mktime((year, month+1, day, 0, 0, 0, 0, 0, 0))
   40	        return time.strftime("%x", time.gmtime(mytime))
   41	
   42	    def calendar_set_signal_strings(self, sig_str):
   43	        prev_sig = self.prev_sig.get()
   44	        self.prev2_sig.set_text(prev_sig)
   45	
   46	        prev_sig = self.last_sig.get()
   47	        self.prev_sig.set_text(prev_sig)
   48	        self.last_sig.set_text(sig_str)
   49	
   50	    def calendar_month_changed(self, widget):
   51	        buffer = "month_changed: %s" % self.calendar_date_to_string()
   52	        self.calendar_set_signal_strings(buffer)
   53	
   54	    def calendar_day_selected(self, widget):
   55	        buffer = "day_selected: %s" % self.calendar_date_to_string()
   56	        self.calendar_set_signal_strings(buffer)
   57	
   58	    def calendar_day_selected_double_click(self, widget):
   59	        buffer = "day_selected_double_click: %s"
   60	        buffer = buffer % self.calendar_date_to_string()
   61	        self.calendar_set_signal_strings(buffer)
   62	
   63	        year, month, day = self.window.get_date()
   64	
   65	        if self.marked_date[day-1] == 0:
   66	            self.window.mark_day(day)
   67	            self.marked_date[day-1] = 1
   68	        else:
   69	            self.window.unmark_day(day)
   70	            self.marked_date[day-1] = 0
   71	
   72	    def calendar_prev_month(self, widget):
   73	        buffer = "prev_month: %s" % self.calendar_date_to_string()
   74	        self.calendar_set_signal_strings(buffer)
   75	
   76	    def calendar_next_month(self, widget):
   77	        buffer = "next_month: %s" % self.calendar_date_to_string()
   78	        self.calendar_set_signal_strings(buffer)
   79	
   80	    def calendar_prev_year(self, widget):
   81	        buffer = "prev_year: %s" % self.calendar_date_to_string()
   82	        self.calendar_set_signal_strings(buffer)
   83	
   84	    def calendar_next_year(self, widget):
   85	        buffer = "next_year: %s" % self.calendar_date_to_string()
   86	        self.calendar_set_signal_strings(buffer)
   87	
   88	    def calendar_set_flags(self):
   89	        options = 0
   90	        for i in range(5):
   91	            if self.settings[i]:
   92	                options = options + (1<<i)
   93	        if self.window:
   94	            self.window.display_options(options)
   95	
   96	    def calendar_toggle_flag(self, toggle):
   97	        j = 0
   98	        for i in range(5):
   99	            if self.flag_checkboxes[i] == toggle:
  100	                j = i
  101	
  102	        self.settings[j] = not self.settings[j]
  103	        self.calendar_set_flags()
  104	
  105	    def calendar_font_selection_ok(self, button):
  106	        self.font = self.font_dialog.get_font_name()
  107	        if self.window:
  108	            font_desc = pango.FontDescription(self.font)
  109	            if font_desc: 
  110	                self.window.modify_font(font_desc)
  111	
  112	    def calendar_select_font(self, button):
  113	        if not self.font_dialog:
  114	            window = gtk.FontSelectionDialog("Font Selection Dialog")
  115	            self.font_dialog = window
  116	    
  117	            window.set_position(gtk.WIN_POS_MOUSE)
  118	    
  119	            window.connect("destroy", self.font_dialog_destroyed)
  120	    
  121	            window.ok_button.connect("clicked",
  122	                                     self.calendar_font_selection_ok)
  123	            window.cancel_button.connect_object("clicked",
  124	                                                lambda wid: wid.destroy(),
  125	                                                self.font_dialog)
  126	        window = self.font_dialog
  127	        if not (window.flags() & gtk.VISIBLE):
  128	            window.show()
  129	        else:
  130	            window.destroy()
  131	            self.font_dialog = None
  132	
  133	    def font_dialog_destroyed(self, data=None):
  134	        self.font_dialog = None
  135	
  136	    def __init__(self):
  137	        flags = [
  138	            "Show Heading",
  139	            "Show Day Names",
  140	            "No Month Change",
  141	            "Show Week Numbers",
  142	            "Week Start Monday"
  143	            ]
  144	        self.window = None
  145	        self.font = None
  146	        self.font_dialog = None
  147	        self.flag_checkboxes = 5*[None]
  148	        self.settings = 5*[0]
  149	        self.marked_date = 31*[0]
  150	
  151	        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
  152	        window.set_title("Calendar Example")
  153	        window.set_border_width(5)
  154	        window.connect("destroy", gtk.mainquit)
  155	
  156	        window.set_resizable(gtk.FALSE)
  157	
  158	        vbox = gtk.VBox(gtk.FALSE, self.DEF_PAD)
  159	        window.add(vbox)
  160	
  161	        # The top part of the window, Calendar, flags and fontsel.
  162	        hbox = gtk.HBox(gtk.FALSE, self.DEF_PAD)
  163	        vbox.pack_start(hbox, gtk.TRUE, gtk.TRUE, self.DEF_PAD)
  164	        hbbox = gtk.HButtonBox()
  165	        hbox.pack_start(hbbox, gtk.FALSE, gtk.FALSE, self.DEF_PAD)
  166	        hbbox.set_layout(gtk.BUTTONBOX_SPREAD)
  167	        hbbox.set_spacing(5)
  168	
  169	        # Calendar widget
  170	        frame = gtk.Frame("Calendar")
  171	        hbbox.pack_start(frame, gtk.FALSE, gtk.TRUE, self.DEF_PAD)
  172	        calendar = gtk.Calendar()
  173	        self.window = calendar
  174	        self.calendar_set_flags()
  175	        calendar.mark_day(19)
  176	        self.marked_date[19-1] = 1
  177	        frame.add(calendar)
  178	        calendar.connect("month_changed", self.calendar_month_changed)
  179	        calendar.connect("day_selected", self.calendar_day_selected)
  180	        calendar.connect("day_selected_double_click",
  181	                         self.calendar_day_selected_double_click)
  182	        calendar.connect("prev_month", self.calendar_prev_month)
  183	        calendar.connect("next_month", self.calendar_next_month)
  184	        calendar.connect("prev_year", self.calendar_prev_year)
  185	        calendar.connect("next_year", self.calendar_next_year)
  186	
  187	        separator = gtk.VSeparator()
  188	        hbox.pack_start(separator, gtk.FALSE, gtk.TRUE, 0)
  189	
  190	        vbox2 = gtk.VBox(gtk.FALSE, self.DEF_PAD)
  191	        hbox.pack_start(vbox2, gtk.FALSE, gtk.FALSE, self.DEF_PAD)
  192	  
  193	        # Build the Right frame with the flags in 
  194	        frame = gtk.Frame("Flags")
  195	        vbox2.pack_start(frame, gtk.TRUE, gtk.TRUE, self.DEF_PAD)
  196	        vbox3 = gtk.VBox(gtk.TRUE, self.DEF_PAD_SMALL)
  197	        frame.add(vbox3)
  198	
  199	        for i in range(5):
  200	            toggle = gtk.CheckButton(flags[i])
  201	            toggle.connect("toggled", self.calendar_toggle_flag)
  202	            vbox3.pack_start(toggle, gtk.TRUE, gtk.TRUE, 0)
  203	            self.flag_checkboxes[i] = toggle
  204	
  205	        # Build the right font-button 
  206	        button = gtk.Button("Font...")
  207	        button.connect("clicked", self.calendar_select_font)
  208	        vbox2.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
  209	
  210	        #  Build the Signal-event part.
  211	        frame = gtk.Frame("Signal events")
  212	        vbox.pack_start(frame, gtk.TRUE, gtk.TRUE, self.DEF_PAD)
  213	
  214	        vbox2 = gtk.VBox(gtk.TRUE, self.DEF_PAD_SMALL)
  215	        frame.add(vbox2)
  216	  
  217	        hbox = gtk.HBox (gtk.FALSE, 3)
  218	        vbox2.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
  219	        label = gtk.Label("Signal:")
  220	        hbox.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
  221	        self.last_sig = gtk.Label("")
  222	        hbox.pack_start(self.last_sig, gtk.FALSE, gtk.TRUE, 0)
  223	
  224	        hbox = gtk.HBox (gtk.FALSE, 3)
  225	        vbox2.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
  226	        label = gtk.Label("Previous signal:")
  227	        hbox.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
  228	        self.prev_sig = gtk.Label("")
  229	        hbox.pack_start(self.prev_sig, gtk.FALSE, gtk.TRUE, 0)
  230	
  231	        hbox = gtk.HBox (gtk.FALSE, 3)
  232	        vbox2.pack_start(hbox, gtk.FALSE, gtk.TRUE, 0)
  233	        label = gtk.Label("Second previous signal:")
  234	        hbox.pack_start(label, gtk.FALSE, gtk.TRUE, 0)
  235	        self.prev2_sig = gtk.Label("")
  236	        hbox.pack_start(self.prev2_sig, gtk.FALSE, gtk.TRUE, 0)
  237	
  238	        bbox = gtk.HButtonBox ()
  239	        vbox.pack_start(bbox, gtk.FALSE, gtk.FALSE, 0)
  240	        bbox.set_layout(gtk.BUTTONBOX_END)
  241	
  242	        button = gtk.Button("Close")
  243	        button.connect("clicked", gtk.mainquit)
  244	        bbox.add(button)
  245	        button.set_flags(gtk.CAN_DEFAULT)
  246	        button.grab_default()
  247	
  248	        window.show_all()
  249	
  250	def main():
  251	    gtk.main()
  252	    return 0
  253	
  254	if __name__ == "__main__":
  255	    CalendarExample()
  256	    main()