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 se necesite cambiar mucha información dentro de este control y los siguientes métodos permiten 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 (desactivando los cambios y reanudándolos).

El control Calendar tiene unas cuantas opciones que 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 se necesita mostrar un mes en particular como cuando se muestran 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. A partir de PyGTK 2.4 esta opción está obsoleta.

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. Ha de advertirse que las marcas son persistentes entre cambios de mes y año.

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 ello 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	# ejemplo calendar.py
    4	#
    5	# Copyright (C) 1998 Cesar Miquel, Shawn T. Amundson, Mattias Gronlund
    6	# Copyright (C) 2000 Tony Gale
    7	# Copyright (C) 2001-2004 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 pygtk
   24	pygtk.require('2.0')
   25	import gtk, pango
   26	import time
   27	
   28	class CalendarExample:
   29	    DEF_PAD = 10
   30	    DEF_PAD_SMALL = 5
   31	    TM_YEAR_BASE = 1900
   32	
   33	    calendar_show_header = 0
   34	    calendar_show_days = 1
   35	    calendar_month_change = 2 
   36	    calendar_show_week = 3
   37	
   38	    def calendar_date_to_string(self):
   39	        year, month, day = self.window.get_date()
   40	        mytime = time.mktime((year, month+1, day, 0, 0, 0, 0, 0, -1))
   41	        return time.strftime("%x", time.localtime(mytime))
   42	
   43	    def calendar_set_signal_strings(self, sig_str):
   44	        prev_sig = self.prev_sig.get()
   45	        self.prev2_sig.set_text(prev_sig)
   46	
   47	        prev_sig = self.last_sig.get()
   48	        self.prev_sig.set_text(prev_sig)
   49	        self.last_sig.set_text(sig_str)
   50	
   51	    def calendar_month_changed(self, widget):
   52	        buffer = "month_changed: %s" % self.calendar_date_to_string()
   53	        self.calendar_set_signal_strings(buffer)
   54	
   55	    def calendar_day_selected(self, widget):
   56	        buffer = "day_selected: %s" % self.calendar_date_to_string()
   57	        self.calendar_set_signal_strings(buffer)
   58	
   59	    def calendar_day_selected_double_click(self, widget):
   60	        buffer = "day_selected_double_click: %s"
   61	        buffer = buffer % self.calendar_date_to_string()
   62	        self.calendar_set_signal_strings(buffer)
   63	
   64	        year, month, day = self.window.get_date()
   65	
   66	        if self.marked_date[day-1] == 0:
   67	            self.window.mark_day(day)
   68	            self.marked_date[day-1] = 1
   69	        else:
   70	            self.window.unmark_day(day)
   71	            self.marked_date[day-1] = 0
   72	
   73	    def calendar_prev_month(self, widget):
   74	        buffer = "prev_month: %s" % self.calendar_date_to_string()
   75	        self.calendar_set_signal_strings(buffer)
   76	
   77	    def calendar_next_month(self, widget):
   78	        buffer = "next_month: %s" % self.calendar_date_to_string()
   79	        self.calendar_set_signal_strings(buffer)
   80	
   81	    def calendar_prev_year(self, widget):
   82	        buffer = "prev_year: %s" % self.calendar_date_to_string()
   83	        self.calendar_set_signal_strings(buffer)
   84	
   85	    def calendar_next_year(self, widget):
   86	        buffer = "next_year: %s" % self.calendar_date_to_string()
   87	        self.calendar_set_signal_strings(buffer)
   88	
   89	    def calendar_set_flags(self):
   90	        options = 0
   91	        for i in range(5):
   92	            if self.settings[i]:
   93	                options = options + (1<<i)
   94	        if self.window:
   95	            self.window.display_options(options)
   96	
   97	    def calendar_toggle_flag(self, toggle):
   98	        j = 0
   99	        for i in range(5):
  100	            if self.flag_checkboxes[i] == toggle:
  101	                j = i
  102	
  103	        self.settings[j] = not self.settings[j]
  104	        self.calendar_set_flags()
  105	
  106	    def calendar_font_selection_ok(self, button):
  107	        self.font = self.font_dialog.get_font_name()
  108	        if self.window:
  109	            font_desc = pango.FontDescription(self.font)
  110	            if font_desc: 
  111	                self.window.modify_font(font_desc)
  112	
  113	    def calendar_select_font(self, button):
  114	        if not self.font_dialog:
  115	            window = gtk.FontSelectionDialog("Font Selection Dialog")
  116	            self.font_dialog = window
  117	    
  118	            window.set_position(gtk.WIN_POS_MOUSE)
  119	    
  120	            window.connect("destroy", self.font_dialog_destroyed)
  121	    
  122	            window.ok_button.connect("clicked",
  123	                                     self.calendar_font_selection_ok)
  124	            window.cancel_button.connect_object("clicked",
  125	                                                lambda wid: wid.destroy(),
  126	                                                self.font_dialog)
  127	        window = self.font_dialog
  128	        if not (window.flags() & gtk.VISIBLE):
  129	            window.show()
  130	        else:
  131	            window.destroy()
  132	            self.font_dialog = None
  133	
  134	    def font_dialog_destroyed(self, data=None):
  135	        self.font_dialog = None
  136	
  137	    def __init__(self):
  138	        flags = [
  139	            "Show Heading",
  140	            "Show Day Names",
  141	            "No Month Change",
  142	            "Show Week Numbers",
  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", lambda x: gtk.main_quit())
  155	
  156	        window.set_resizable(gtk.FALSE)
  157	
  158	        vbox = gtk.VBox(gtk.FALSE, self.DEF_PAD)
  159	        window.add(vbox)
  160	
  161	        # La parte superior de la ventana, el Calendario, las opcines y fuente.
  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	        # Control calendario
  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	        # Crear el frame derecho con sus opciones
  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(len(flags)):
  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	        # Crear el botón de fuentes derecho
  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	        #  Crear la parte relativo a señales
  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", lambda w: gtk.main_quit())
  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()