9.12. Calendar
Prev | Chapter 9. Miscellaneous Widgets | Next

## 9.12. Calendar

The `Calendar` widget is an effective way to display and retrieve monthly date related information. It is a very simple widget to create and work with.

Creating a `gtk.Calendar` widget is as simple as:

      calendar = gtk.Calendar()

The calendar will display the current month and year by default.

There might be times where you need to change a lot of information within this widget and the following methods allow you to make multiple changes to a `Calendar` widget without the user seeing multiple on-screen updates.

      calendar.freeze()

      calendar.thaw()

They work just like the freeze/thaw methods of every other widget.

The `Calendar` widget has a few options that allow you to change the way the widget both looks and operates by using the method:

      calendar.display_options(flags)

The `flags` argument can be formed by combining either of the following five options using the logical bitwise OR (|) operation:

CALENDAR_SHOW_HEADING | this option specifies that the month and year should be shown when drawing the calendar.
CALENDAR_SHOW_DAY_NAMES | this option specifies that the three letter descriptions should be displayed for each day (e.g. Mon,Tue, etc.).
CALENDAR_NO_MONTH_CHANGE | this option states that the user should not and can not change the currently displayed month. This can be good if you only need to display a particular month such as if you are displaying 12 calendar widgets for every month in a particular year.
CALENDAR_SHOW_WEEK_NUMBERS | this option specifies that the number for each week should be displayed down the left side of the calendar. (e.g. Jan 1 = Week 1,Dec 31 = Week 52).
CALENDAR_WEEK_START_MONDAY | this option states that the calender week will start on Monday instead of Sunday which is the default. This only affects the order in which days are displayed from left to right. Note that in PyGTK 2.4 and above this option is deprecated.

The following methods are used to set the the currently displayed date:

      result = calendar.select_month(month, year)

      calendar.select_day(day)

The return value from the `select_month`() method is a boolean value indicating whether the selection was successful.

With the `select_day`() method the specified day number is selected within the current month, if that is possible. A day value of 0 will deselect any current selection.

In addition to having a day selected, any number of days in the month may be "marked". A marked day is highlighted within the calendar display. The following methods are provided to manipulate marked days:

      result = calendar.mark_day(day)

      result = calendar.unmark_day(day)

      calendar.clear_marks()

`mark_day`() and `unmark_day`() return a boolean indicating whether the method was successful. Note that marks are persistent across month and year changes.

The final `Calendar` widget method is used to retrieve the currently selected date, month and/or year.

      year, month, day = calendar.get_date()

The `Calendar` widget can generate a number of signals indicating date selection and change. The names of these signals are self explanatory, and are:

      month_changed

      day_selected

      day_selected_double_click

      prev_month

      next_month

      prev_year

      next_year

That just leaves us with the need to put all of this together into the calendar.py example program. Figure 9.12, “Calendar Example” illustrates the program operation:

Figure 9.12. Calendar Example

The calendar.py source code is:

        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-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(False)
      157
      158	        vbox = gtk.VBox(False, self.DEF_PAD)
      159	        window.add(vbox)
      160
      161	        # The top part of the window, Calendar, flags and fontsel.
      162	        hbox = gtk.HBox(False, self.DEF_PAD)
      163	        vbox.pack_start(hbox, True, True, self.DEF_PAD)
      164	        hbbox = gtk.HButtonBox()
      165	        hbox.pack_start(hbbox, False, 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, False, 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, False, True, 0)
      189
      190	        vbox2 = gtk.VBox(False, self.DEF_PAD)
      191	        hbox.pack_start(vbox2, False, False, self.DEF_PAD)
      192
      193	        # Build the Right frame with the flags in
      194	        frame = gtk.Frame("Flags")
      195	        vbox2.pack_start(frame, True, True, self.DEF_PAD)
      196	        vbox3 = gtk.VBox(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, True, 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, False, False, 0)
      209
      210	        #  Build the Signal-event part.
      211	        frame = gtk.Frame("Signal events")
      212	        vbox.pack_start(frame, True, True, self.DEF_PAD)
      213
      214	        vbox2 = gtk.VBox(True, self.DEF_PAD_SMALL)
      215	        frame.add(vbox2)
      216
      217	        hbox = gtk.HBox (False, 3)
      218	        vbox2.pack_start(hbox, False, True, 0)
      219	        label = gtk.Label("Signal:")
      220	        hbox.pack_start(label, False, True, 0)
      221	        self.last_sig = gtk.Label("")
      222	        hbox.pack_start(self.last_sig, False, True, 0)
      223
      224	        hbox = gtk.HBox (False, 3)
      225	        vbox2.pack_start(hbox, False, True, 0)
      226	        label = gtk.Label("Previous signal:")
      227	        hbox.pack_start(label, False, True, 0)
      228	        self.prev_sig = gtk.Label("")
      229	        hbox.pack_start(self.prev_sig, False, True, 0)
      230
      231	        hbox = gtk.HBox (False, 3)
      232	        vbox2.pack_start(hbox, False, True, 0)
      233	        label = gtk.Label("Second previous signal:")
      234	        hbox.pack_start(label, False, True, 0)
      235	        self.prev2_sig = gtk.Label("")
      236	        hbox.pack_start(self.prev2_sig, False, True, 0)
      237
      238	        bbox = gtk.HButtonBox ()
      239	        vbox.pack_start(bbox, False, 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()

Prev | Up | Next
9.11. Combo Widget | Home | 9.13. Color Selection