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:
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() |