# Authors: Joe VanAndel, Greg McFarlane and Daniel Michelson import string import sys import time import Tkinter import Pmw class FullTimeCounter(Pmw.MegaWidget): """Up-down counter A TimeCounter is a single-line entry widget with Up and Down arrows which increment and decrement the Time value in the entry. """ def __init__(self, parent = None, **kw): # Define the megawidget options. INITOPT = Pmw.INITOPT optiondefs = ( ('autorepeat', 1, INITOPT), ('buttonaspect', 1.0, INITOPT), ('initwait', 300, INITOPT), ('labelmargin', 0, INITOPT), ('labelpos', None, INITOPT), ('max', '', self._max), ('min', '', self._min), ('padx', 0, INITOPT), ('pady', 0, INITOPT), ('repeatrate', 50, INITOPT), ('value', '', INITOPT), ) self.defineoptions(kw, optiondefs) # Initialise the base class (after defining the options). Pmw.MegaWidget.__init__(self, parent) self.arrowDirection = {} self._flag = 'stopped' self._timerId = None self._createComponents() value = self['value'] if value is None or value == '': now = time.time() value = time.strftime('%Y:%m:%d:%H:%M',time.gmtime(now)) self._setTimeFromStr(value) # Check keywords and initialise options. self.initialiseoptions() def _createComponents(self): # Create the components. interior = self.interior() # If there is no label, put the arrows and the entry directly # into the interior, otherwise create a frame for them. In # either case the border around the arrows and the entry will # be raised (but not around the label). if self['labelpos'] is None: frame = interior else: frame = self.createcomponent('frame', (), None, Tkinter.Frame, (interior,)) frame.grid(column=2, row=2, sticky='nsew') interior.grid_columnconfigure(2, weight=1) interior.grid_rowconfigure(2, weight=1) frame.configure(relief = 'raised', borderwidth = 1) # Create the down arrow buttons. # Create the year down arrow. self._downYearArrowBtn = self.createcomponent('downyeararrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._downYearArrowBtn] = 0 self._downYearArrowBtn.grid(column = 0, row = 2) # Create the month down arrow. self._downMonthArrowBtn = self.createcomponent('downmontharrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._downMonthArrowBtn] = 0 self._downMonthArrowBtn.grid(column = 1, row = 2) # Create the day down arrow. self._downDayArrowBtn = self.createcomponent('downdayarrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._downDayArrowBtn] = 0 self._downDayArrowBtn.grid(column = 2, row = 2) # Create the hour down arrow. self._downHourArrowBtn = self.createcomponent('downhourarrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._downHourArrowBtn] = 0 self._downHourArrowBtn.grid(column = 3, row = 2) # Create the minute down arrow. self._downMinuteArrowBtn = self.createcomponent('downminutearrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._downMinuteArrowBtn] = 0 self._downMinuteArrowBtn.grid(column = 4, row = 2) # Create the entry fields. # Create the year entry field. self._yearCounterEntry = self.createcomponent('yearentryfield', (('yearentry', 'yearentryfield_entry'),), None, Pmw.EntryField, (frame,), validate='integer', entry_width = 4) self._yearCounterEntry.grid(column = 0, row = 1, sticky = 'news') # Create the month entry field. self._monthCounterEntry = self.createcomponent('monthentryfield', (('monthentry', 'monthentryfield_entry'),), None, Pmw.EntryField, (frame,), validate='integer', entry_width = 2) self._monthCounterEntry.grid(column = 1, row = 1, sticky = 'news') # Create the day entry field. self._dayCounterEntry = self.createcomponent('dayentryfield', (('dayentry', 'dayentryfield_entry'),), None, Pmw.EntryField, (frame,), validate='integer', entry_width = 2) self._dayCounterEntry.grid(column = 2, row = 1, sticky = 'news') # Create the hour entry field. self._hourCounterEntry = self.createcomponent('hourentryfield', (('hourentry', 'hourentryfield_entry'),), None, Pmw.EntryField, (frame,), validate='integer', entry_width = 2) self._hourCounterEntry.grid(column = 3, row = 1, sticky = 'news') # Create the minute entry field. self._minuteCounterEntry = self.createcomponent('minuteentryfield', (('minuteentry', 'minuteentryfield_entry'),), None, Pmw.EntryField, (frame,), validate='integer', entry_width = 2) self._minuteCounterEntry.grid(column = 4, row = 1, sticky = 'news') # Create the up arrow buttons. # Create the year up arrow. self._upYearArrowBtn = self.createcomponent('upyeararrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._upYearArrowBtn] = 1 self._upYearArrowBtn.grid(column = 0, row = 0) # Create the month up arrow. self._upMonthArrowBtn = self.createcomponent('upmontharrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._upMonthArrowBtn] = 1 self._upMonthArrowBtn.grid(column = 1, row = 0) # Create the day up arrow. self._upDayArrowBtn = self.createcomponent('updayarrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._upDayArrowBtn] = 1 self._upDayArrowBtn.grid(column = 2, row = 0) # Create the hour up arrow. self._upHourArrowBtn = self.createcomponent('uphourarrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._upHourArrowBtn] = 1 self._upHourArrowBtn.grid(column = 3, row = 0) # Create the minute up arrow. self._upMinuteArrowBtn = self.createcomponent('upminutearrow', (), 'Arrow', Tkinter.Canvas, (frame,), width = 16, height = 16, relief = 'raised', borderwidth = 2) self.arrowDirection[self._upMinuteArrowBtn] = 1 self._upMinuteArrowBtn.grid(column = 4, row = 0) # Make it resize nicely. padx = self['padx'] pady = self['pady'] for col in range(5): # YY, MM, DD, HH, mm frame.grid_columnconfigure(col, weight = 1, pad = padx) frame.grid_rowconfigure(0, pad = pady) frame.grid_rowconfigure(2, pad = pady) frame.grid_rowconfigure(1, weight = 1) # Create the label. self.createlabel(interior) # Set bindings. # Up year self._upYearArrowBtn.bind('', lambda event, s=self,button=self._upYearArrowBtn: s._drawArrow(button, 1)) self._upYearArrowBtn.bind('<1>', lambda event, s=self,button=self._upYearArrowBtn: s._countUp(button)) self._upYearArrowBtn.bind('', lambda event, s=self, button=self._upYearArrowBtn: s._stopUpDown(button)) # Up month self._upMonthArrowBtn.bind('', lambda event, s=self,button=self._upMonthArrowBtn: s._drawArrow(button, 1)) self._upMonthArrowBtn.bind('<1>', lambda event, s=self,button=self._upMonthArrowBtn: s._countUp(button)) self._upMonthArrowBtn.bind('', lambda event, s=self, button=self._upMonthArrowBtn: s._stopUpDown(button)) # Up day self._upDayArrowBtn.bind('', lambda event, s=self,button=self._upDayArrowBtn: s._drawArrow(button, 1)) self._upDayArrowBtn.bind('<1>', lambda event, s=self,button=self._upDayArrowBtn: s._countUp(button)) self._upDayArrowBtn.bind('', lambda event, s=self, button=self._upDayArrowBtn: s._stopUpDown(button)) # Up hour self._upHourArrowBtn.bind('', lambda event, s=self,button=self._upHourArrowBtn: s._drawArrow(button, 1)) self._upHourArrowBtn.bind('<1>', lambda event, s=self,button=self._upHourArrowBtn: s._countUp(button)) self._upHourArrowBtn.bind('', lambda event, s=self, button=self._upHourArrowBtn: s._stopUpDown(button)) # Up minute self._upMinuteArrowBtn.bind('', lambda event, s=self,button=self._upMinuteArrowBtn: s._drawArrow(button, 1)) self._upMinuteArrowBtn.bind('<1>', lambda event, s=self,button=self._upMinuteArrowBtn: s._countUp(button)) self._upMinuteArrowBtn.bind('', lambda event, s=self, button=self._upMinuteArrowBtn: s._stopUpDown(button)) # Down year self._downYearArrowBtn.bind('', lambda event, s=self,button=self._downYearArrowBtn: s._drawArrow(button, 0)) self._downYearArrowBtn.bind('<1>', lambda event, s=self,button=self._downYearArrowBtn: s._countDown(button)) self._downYearArrowBtn.bind('', lambda event, s=self, button=self._downYearArrowBtn: s._stopUpDown(button)) # Down month self._downMonthArrowBtn.bind('', lambda event, s=self,button=self._downMonthArrowBtn: s._drawArrow(button, 0)) self._downMonthArrowBtn.bind('<1>', lambda event, s=self,button=self._downMonthArrowBtn: s._countDown(button)) self._downMonthArrowBtn.bind('', lambda event, s=self, button=self._downMonthArrowBtn: s._stopUpDown(button)) # Down day self._downDayArrowBtn.bind('', lambda event, s=self,button=self._downDayArrowBtn: s._drawArrow(button, 0)) self._downDayArrowBtn.bind('<1>', lambda event, s=self,button=self._downDayArrowBtn: s._countDown(button)) self._downDayArrowBtn.bind('', lambda event, s=self, button=self._downDayArrowBtn: s._stopUpDown(button)) # Down hour self._downHourArrowBtn.bind('', lambda event, s=self,button=self._downHourArrowBtn: s._drawArrow(button, 0)) self._downHourArrowBtn.bind('<1>', lambda event, s=self,button=self._downHourArrowBtn: s._countDown(button)) self._downHourArrowBtn.bind('', lambda event, s=self, button=self._downHourArrowBtn: s._stopUpDown(button)) # Down minute self._downMinuteArrowBtn.bind('', lambda event, s=self,button=self._downMinuteArrowBtn: s._drawArrow(button, 0)) self._downMinuteArrowBtn.bind('<1>', lambda event, s=self,button=self._downMinuteArrowBtn: s._countDown(button)) self._downMinuteArrowBtn.bind('', lambda event, s=self, button=self._downMinuteArrowBtn: s._stopUpDown(button)) self._yearCounterEntry.bind('', self.invoke) self._monthCounterEntry.bind('', self.invoke) self._dayCounterEntry.bind('', self.invoke) self._hourCounterEntry.bind('', self.invoke) self._minuteCounterEntry.bind('', self.invoke) self._yearCounterEntry.bind('', self._resizeArrow) self._monthCounterEntry.bind('', self._resizeArrow) self._dayCounterEntry.bind('', self._resizeArrow) self._hourCounterEntry.bind('', self._resizeArrow) self._minuteCounterEntry.bind('', self._resizeArrow) def _drawArrow(self, arrow, direction): arrow.delete('arrow') fg = self._yearCounterEntry.cget('entry_foreground') bw = (string.atoi(arrow['borderwidth']) + string.atoi(arrow['highlightthickness'])) / 2 h = string.atoi(arrow['height']) + 2 * bw w = string.atoi(arrow['width']) + 2 * bw if direction == 0: # down arrow arrow.create_polygon( 0.25 * w + bw, 0.25 * h + bw, 0.50 * w + bw, 0.75 * h + bw, 0.75 * w + bw, 0.25 * h + bw, fill=fg, tag='arrow') else: arrow.create_polygon( 0.25 * w + bw, 0.75 * h + bw, 0.50 * w + bw, 0.25 * h + bw, 0.75 * w + bw, 0.75 * h + bw, fill=fg, tag='arrow') def _resizeArrow(self, event = None): for btn in (self._upYearArrowBtn, self._upMonthArrowBtn, self._upDayArrowBtn, self._upHourArrowBtn, self._upMinuteArrowBtn, self._downYearArrowBtn, self._downMonthArrowBtn, self._downDayArrowBtn, self._downHourArrowBtn, self._downMinuteArrowBtn): bw = (string.atoi(btn['borderwidth']) + \ string.atoi(btn['highlightthickness'])) newHeight = self._yearCounterEntry.winfo_reqheight() - 2 * bw newWidth = newHeight * self['buttonaspect'] btn.configure(width=newWidth, height=newHeight) self._drawArrow(btn, self.arrowDirection[btn]) def _min(self): self._minVal = None def _max(self): self._maxVal = None def _setTimeFromStr(self, str): list = string.split(str, ':') if len(list) != 5: raise ValueError, 'invalid value: ' + str self._year = string.atoi(list[0]) self._month = string.atoi(list[1]) self._day = string.atoi(list[2]) self._hour = string.atoi(list[3]) self._minute = string.atoi(list[4]) self._setHMS() def getstring(self): return '%04d:%02d:%02d:%02d:%02d' % (self._year, self._month, self._day, self._hour, self._minute) def getint(self): pass def _countUp(self, button): self._relief = self._upYearArrowBtn.cget('relief') button.configure(relief='sunken') if button == self._upYearArrowBtn: datetype = "year" elif button == self._upMonthArrowBtn: datetype = "month" elif button == self._upDayArrowBtn: datetype = "day" elif button == self._upHourArrowBtn: datetype = "hour" elif button == self._upMinuteArrowBtn: datetype = "minute" self._count(1, datetype, 'start') def _countDown(self, button): self._relief = self._downYearArrowBtn.cget('relief') button.configure(relief='sunken') if button == self._downYearArrowBtn: datetype = "year" elif button == self._downMonthArrowBtn: datetype = "month" elif button == self._downDayArrowBtn: datetype = "day" elif button == self._downHourArrowBtn: datetype = "hour" elif button == self._downMinuteArrowBtn: datetype = "minute" self._count(-1, datetype, 'start') def _count(self, factor, datetype, newFlag=None): if newFlag != 'force': if newFlag is not None: self._flag = newFlag if self._flag == 'stopped': return if datetype == "year": self._year = self._year + factor elif datetype == "month": self._month = self._month + factor elif datetype == "day": self._day = self._day + factor elif datetype == "hour": self._hour = self._hour + factor elif datetype == "minute": self._minute = self._minute + factor secs = time.mktime((self._year, self._month, self._day, self._hour, self._minute, 0, 0, 0, -1)) tt = time.localtime(secs) # NOT gmtime! self._year = tt[0] self._month = tt[1] self._day = tt[2] self._hour = tt[3] self._minute = tt[4] self._setHMS() if newFlag != 'force': if self['autorepeat']: if self._flag == 'start': delay = self['initwait'] self._flag = 'running' else: delay = self['repeatrate'] self._timerId = self.after( delay, lambda self=self, factor=factor, datetype=datetype: self._count(factor, datetype, 'running')) def _setHMS(self): self._yearCounterEntry.setentry('%04d' % self._year) self._monthCounterEntry.setentry('%02d' % self._month) self._dayCounterEntry.setentry('%02d' % self._day) self._hourCounterEntry.setentry('%02d' % self._hour) self._minuteCounterEntry.setentry('%02d' % self._minute) def _stopUpDown(self, button): if self._timerId is not None: self.after_cancel(self._timerId) self._timerId = None button.configure(relief=self._relief) self._flag = 'stopped' def invoke(self, event = None): cmd = self['command'] if callable(cmd): cmd() def destroy(self): if self._timerId is not None: self.after_cancel(self._timerId) self._timerId = None Pmw.MegaWidget.destroy(self) if __name__=="__main__": def showString(): stringVal = _time.getstring() print stringVal root = Tkinter.Tk() Pmw.initialise(root) root.title('FullTimeCounter') exitButton = Tkinter.Button(root, text = 'Exit', command = root.destroy) exitButton.pack(side = 'bottom') _time = FullTimeCounter(root, labelpos = 'n', label_text = 'YYYY:MM:DD:HH:mm') _time.pack(fill = 'both', expand = 1, padx=10, pady=5) button = Tkinter.Button(root, text = 'Show', command = showString) button.pack() root.mainloop()