Timo wrote:
Hello, I would like to have a gtk.Calendar to popup under a gtk.Entry as
soon as the user clicks on the entry.
So I use the focus-in-event to capture when the user clicks in the
entry. But I can't seem to find a way to popup a calendar.
Timo
_______________________________________________
pygtk mailing list [email protected]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/
Here is a custom widget I use. You can default the format of the date
to anything you like. When you right click in the widget it pops up
a calendar dialog.
You can also type the date into the widget in a wide set of formats.
When the date changes it also sends a 'date_changed' signal.
Hope this helps.
import gtk
from gtk import gdk
import gobject
import time
class InvalidDate(Exception):
def __init__(self,date):
super(InvalidDate, self).__init__()
self.message = "Invalid date \"%s\"." % (date)
def __str__(self):
return self.message
class DateEntry(gtk.Entry) :
#date = None
calendar_dialog = False
timestamp = None
format = '%e-%b-%Y'
widget = None
window = None
__gsignals__ = dict(date_changed=(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()))
def __init__(self, window, title = None) :
super(DateEntry, self).__init__()
self.connect('focus_out_event',self.on_focus_out_event)
self.connect('button_press_event',self.on_button_press_event)
self.connect('activate', lambda widget: widget.get_toplevel().child_focus(gtk.DIR_TAB_FORWARD))
if not window :
raise ValueError('Parent window needed')
self.window = window
self.title = title
self.set_width_chars(11)
#self.set_max_length(11)
def __str__(self) :
if self.timestamp == None :
date = 'Unknown'
else :
date = time.strftime(self.format, self.timestamp)
return date
def on_button_press_event (self,widget,event) :
#print "date_widget:on_button_press_event()"
if event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS :
text = super(DateEntry, self).get_text()
if text == None or len(text.strip()) == 0 :
self.timestamp = None #we don't want to emit a signal as the popup will do so when needed
self.popup_calendar()
return True
else :
return False
def popup_calendar(self) :
self.calendar_dialog = True
#print "date_widget:popup_calendar() -- ",self.timestamp
dialog = gtk.Dialog (self.title, self.window,
gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OK, gtk.RESPONSE_OK))
#self.dialog.set_position(gtk.WIN_POS_MOUSE)
calendar = gtk.Calendar()
dialog.vbox.pack_start (calendar, True, True, 0)
calendar.connect('day_selected_double_click', self.calendar_check, dialog)
timestamp = self.timestamp
if (timestamp == None) :
timestamp = time.localtime()
if (timestamp) :
calendar.select_month(timestamp[1] - 1,timestamp[0])
calendar.select_day(timestamp[2])
dialog.show_all()
result = dialog.run()
if result == gtk.RESPONSE_OK :
self.calendar_check(calendar, dialog)
else :
dialog.destroy()
self.calendar_dialog = False
def calendar_check(self,widget, dialog) :
(year,month,day) = widget.get_date()
current = time.strptime("%d-%d-%d" % (year,month + 1,day),'%Y-%m-%d')
#print self,"calendar_check",current
super(DateEntry, self).set_text(time.strftime(self.format, current))
self.check_for_signal(current)
dialog.destroy()
def set_format(self,format) :
#print "date_widget:set_format"
if format :
self.format = format
def set_today(self) :
# round the current time into a date
timestamp = time.strptime(time.strftime('%d-%b-%Y',time.localtime()),'%d-%b-%Y')
self.check_for_signal(timestamp)
super(DateEntry, self).set_text(self.get_date())
def set_date(self,date,format = None) :
#print "date_widget:set_date()"
if date == None or len(date.strip()) == 0 :
self.check_for_signal(None)
super(DateEntry, self).set_text('')
return
if format == None :
format = self.check_formats(date)
else :
self.timestamp = time.strptime(date,format)
super(DateEntry, self).set_text(self.get_date())
if format == None :
raise ValueError,'Unknown date format - %s' % (date)
def set_pg_date (self, field) :
return self.set_date(str(field.strftime('%d-%m-%Y')))
def get_date(self,format = None) :
#print "date_widget:get_date()"
# check if the widget has the focus
if self.is_focus() :
# the widget has the focus
# we need to check if the current text is OK
text = super(DateEntry, self).get_text()
if len(text) > 0 :
timestamp = self.check_formats(text)
if not timestamp :
raise InvalidDate(text)
else :
return None
if self.timestamp == None : return None
if format == None : format = self.format
return time.strftime(format, self.timestamp)
def check_for_signal(self,current) :
#print "timestamp = ",self.timestamp," current ",current
if (current != self.timestamp) :
#print self,"emit date_changed",current
self.timestamp = current
self.emit('date_changed')
def on_focus_out_event(self,widget,event) :
#print "date_widget:on_focus_out()"
#text = self.get_text() # get the text entered
text = super(DateEntry, self).get_text()
if text == None or len(text.strip()) == 0 :
#print "no text in widget"
# no text clear the date
self.check_for_signal(None)
return
timestamp = self.check_formats(text)
if timestamp == None and not self.calendar_dialog :
#raise InvalidDate(text)
self.dialog = gtk.MessageDialog(self.window,
gtk.DIALOG_DESTROY_WITH_PARENT | gtk.DIALOG_MODAL,
gtk.MESSAGE_ERROR,
gtk.BUTTONS_CANCEL,
"Unknown date format\n%s" % (text))
self.dialog.connect("response", self.on_dialog_response)
#self.dialog.set_position(gtk.WIN_POS_MOUSE)
self.dialog.show()
def check_formats (self, text) :
# try multple formats for converting to a timestamp
try :
timestamp = time.strptime(text,self.format)
except :
pass
else :
super(DateEntry, self).set_text(time.strftime(self.format, timestamp))
self.check_for_signal(timestamp)
return timestamp
for format in ['%d-%m-%Y','%d-%b-%Y','%d-%B-%Y','%d-%m-%y','%d-%b-%y','%d-%B-%y','%Y-%m-%d','%Y-%b-%d','%Y-%B-%d',
'%d/%m/%Y','%d/%b/%Y','%d/%B/%Y','%d/%m/%y','%d/%b/%y','%d/%B/%y','%Y/%m/%d','%Y/%b/%d','%Y/%B/%d'] :
try :
timestamp = time.strptime(text, format)
except :
pass
else :
super(DateEntry, self).set_text(time.strftime(self.format, timestamp))
self.check_for_signal(timestamp)
return timestamp
return None
def on_dialog_response(self,dialog,response) :
#print "date_widget:on_dialog_response()"
#raise (AttributeError, 'Invalid date')
gobject.timeout_add(100, self.grab_focus)
self.dialog.destroy()
def set_text(self, text) :
raise (AttributeError, 'Use set_date()')
def get_text(self) :
return self.get_date()
if __name__ == "__main__":
class window:
def __init__(self) :
window = gtk.Window()
window.connect("destroy", gtk.main_quit)
vbox = gtk.VBox()
window.add(vbox)
# a date widget for testing
date = DateEntry(window)
vbox.pack_start(date)
# button for testing the get_date()
button = gtk.Button('get date')
vbox.pack_start(button, False, False)
button.connect('clicked', self.on_button_clicked, date)
date.connect("date_changed", self.date_changed_cb)
window.show_all()
#date.set_date('10-jan-2007','%d-%b-%Y')
date.set_date(None,'%d-%b-%Y')
def date_changed_cb(self, widget):
print self,"date-changed \"%s\"" % (widget.get_date())
def setup_date(self, widget, event, date) :
if widget.changed :
date.set_date(widget.get_text())
widget.changed = False
def setup_changed(self,widget) :
widget.changed = True
def main(self):
gtk.main()
def on_button_clicked(self, button, widget) :
try :
date = widget.get_date()
except datewidget.InvalidDate,msg :
print "oh! \"%s\"" % (msg)
else :
print "Date = %s" % (date)
window = window()
window.main()
_______________________________________________
pygtk mailing list [email protected]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://faq.pygtk.org/