diff --git a/utils/wxPython/CHANGES.txt b/utils/wxPython/CHANGES.txt index 1e64e58800..127a1441f9 100644 --- a/utils/wxPython/CHANGES.txt +++ b/utils/wxPython/CHANGES.txt @@ -30,7 +30,13 @@ mouthful!) and wxCalendar has printing support. Added ActiveXWrapper to the library, and some good demos of it too. It works great for embedding a COM (a.k.a OCX, a.k.a Activex) control -in a window and calling its methods. +in a window and calling its methods. It actually creates a new class +on the fly that derives from wxWindow, the COM CoClass and others +needed to make it all work. The resulting class can be instantiated +just like wxWindow, used in sizers, etc. It also responds to all COM +method calls, properties, etc., and if the class or a mix-in has +matching method names, then the COM events will be propogated back to +them. diff --git a/utils/wxPython/demo/ActiveXWrapper_IE.py b/utils/wxPython/demo/ActiveXWrapper_IE.py index 4a797acc8a..eb3a4a3a67 100644 --- a/utils/wxPython/demo/ActiveXWrapper_IE.py +++ b/utils/wxPython/demo/ActiveXWrapper_IE.py @@ -14,18 +14,22 @@ except: #---------------------------------------------------------------------- -class TestPanel(wxPanel): - def __init__(self, parent, log): - wxPanel.__init__(self, parent, -1)#, style=wxCLIP_CHILDREN) +class TestPanel(wxWindow): + def __init__(self, parent, log, frame=None): + wxWindow.__init__(self, parent, -1)#, style=wxCLIP_CHILDREN) self.log = log self.current = "http://alldunn.com/" + self.frame = frame + if frame: + self.titleBase = frame.GetTitle() + sizer = wxBoxSizer(wxVERTICAL) btnSizer = wxBoxSizer(wxHORIZONTAL) # Make a new class that derives from the WebBrowser class in the - # COM module imported above. This class also drives from wxWindow and - # implements the machinery needed to integrate the two things. + # COM module imported above. This class also derives from wxWindow and + # implements the machinery needed to integrate the two worlds. theClass = MakeActiveXClass(browserModule.WebBrowser, eventObj = self) @@ -50,24 +54,44 @@ class TestPanel(wxPanel): self.location = wxComboBox(self, wxNewId(), "", style=wxCB_DROPDOWN) EVT_COMBOBOX(self, self.location.GetId(), self.OnLocationSelect) + EVT_KEY_UP(self.location, self.OnLocationKey) + #EVT_CHAR(self.location, self.IgnoreReturn) btnSizer.Add(self.location, 1, wxEXPAND|wxALL, 5) sizer.Add(btnSizer, 0, wxEXPAND) sizer.Add(self.ie, 1, wxEXPAND) self.ie.Navigate(self.current) - + self.location.Append(self.current) self.SetSizer(sizer) self.SetAutoLayout(true) + def OnSize(self, evt): + self.Layout() + def __del__(self): self.ie.Cleanup() self.ie = None def OnLocationSelect(self, evt): - pass + url = self.location.GetStringSelection() + self.log.write('OnLocationSelect: %s\n' % url) + self.ie.Navigate(url) + + def OnLocationKey(self, evt): + if evt.KeyCode() == WXK_RETURN: + URL = self.location.GetValue() + self.location.Append(URL) + self.ie.Navigate(URL) + else: + evt.Skip() + + def IgnoreReturn(self, evt): + print 'IgnoreReturn' + if evt.KeyCode() != WXK_RETURN: + evt.Skip() def OnOpenButton(self, event): dlg = wxTextEntryDialog(self, "Open Location", @@ -100,12 +124,22 @@ class TestPanel(wxPanel): self.current = URL self.location.SetValue(URL) + def OnTitleChange(self, text): + self.log.write('OnTitleChange: %s\n' % text) + if self.frame: + self.frame.SetTitle(self.titleBase + ' -- ' + text) + + def OnStatusTextChange(self, text): + self.log.write('OnStatusTextChange: %s\n' % text) + if self.frame: + self.frame.SetStatusText(text) + #---------------------------------------------------------------------- # for the demo framework... def runTest(frame, nb, log): - win = TestPanel(nb, log) + win = TestPanel(nb, log, frame) return win @@ -120,7 +154,8 @@ if __name__ == '__main__': wxFrame.__init__(self, None, -1, "ActiveX test -- Internet Explorer", size=(640, 480), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) - self.tp = TestPanel(self, sys.stdout) + self.CreateStatusBar() + self.tp = TestPanel(self, sys.stdout, self) def OnCloseWindow(self, event): self.tp.ie.Cleanup() diff --git a/utils/wxPython/demo/Main.py b/utils/wxPython/demo/Main.py index 8305df58f2..7758152502 100644 --- a/utils/wxPython/demo/Main.py +++ b/utils/wxPython/demo/Main.py @@ -63,7 +63,7 @@ _treeList = [ class wxPythonDemo(wxFrame): def __init__(self, parent, id, title): - wxFrame.__init__(self, parent, -1, title, size = (725, 550), + wxFrame.__init__(self, parent, -1, title, size = (800, 600), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.cwd = os.getcwd() @@ -185,7 +185,7 @@ class wxPythonDemo(wxFrame): if _useSplitter: if _useNestedSplitter: splitter2.SplitHorizontally(self.nb, self.log) - splitter2.SetSashPosition(360, true) + splitter2.SetSashPosition(450, true) splitter2.SetMinimumPaneSize(20) splitter.SplitVertically(self.tree, splitter2) diff --git a/utils/wxPython/demo/wxCalendar.py b/utils/wxPython/demo/wxCalendar.py index 4a9772fa6b..cf49fc2d9f 100644 --- a/utils/wxPython/demo/wxCalendar.py +++ b/utils/wxPython/demo/wxCalendar.py @@ -5,7 +5,7 @@ # Author: Lorne White (email: lwhite1@planet.eon.net) # # Created: -# Version 0.7 200/03/30 +# Version 0.8 2000/04/16 # Licence: wxWindows license #---------------------------------------------------------------------------- @@ -70,6 +70,7 @@ class TestPanel(wxPanel): self.calend.hide_title = TRUE self.calend.HideGrid() + self.calend.SetWeekColor('WHITE', 'BLACK') # display routine @@ -186,6 +187,7 @@ class TestPanel(wxPanel): except: set_days = [1, 5, 12] + self.calend.AddSelect([4, 11], 'BLUE', 'WHITE') self.calend.SetSelDay(set_days) self.calend.Refresh() @@ -257,6 +259,8 @@ class CalenDlg(wxDialog): self.calend.SetYear(start_year) self.calend.HideTitle() + self.calend.ShowWeekEnd() + self.ResetDisplay() self.Connect(self.calend.GetId(), -1, 2100, self.MouseClick) @@ -303,6 +307,8 @@ class CalenDlg(wxDialog): except: set_days = [1, 5, 12] + self.calend.AddSelect([4, 11], 'BLUE', 'WHITE') + self.calend.SetSelDay(set_days) self.calend.Refresh() @@ -326,6 +332,9 @@ class CalendFrame(wxFrame): self.calend = wxCalendar(self, -1) self.calend.SetCurrentDay() self.calend.grid_color = 'BLUE' + self.calend.SetBusType() +# self.calend.ShowWeekEnd() + self.ResetDisplay() self.Connect(self.calend.GetId(), -1, 2100, self.MouseClick) @@ -344,6 +353,8 @@ class CalendFrame(wxFrame): except: set_days = [1, 5, 12] + self.calend.AddSelect([2, 16], 'GREEN', 'WHITE') + self.calend.SetSelDay(set_days) self.calend.Refresh() @@ -525,20 +536,29 @@ class PrintCalend: cal.font = self.font cal.bold = self.bold - cal_size = wxSize(3.0, 2.0) + cal_size = wxSize(3.0, 3.0) cal.SetSize(cal_size) year, month = self.year, self.month + x = 1.0 for i in range(2): y = 0.5 for j in range(3): cal.SetCal(year, month) # current month cal.SetPos(x, y) - cal.DrawCal(DC, self.sel_lst) + + try: + set_days = test_days[month] + except: + set_days = [1, 5, 12] + + cal.AddSelect([2, 16], 'GREEN', 'WHITE') + + cal.DrawCal(DC, set_days) year, month = self.IncMonth(year, month) - y = y + 2.5 + y = y + 3.5 x = x + 4.0 # next colum DC.EndDrawing() @@ -695,8 +715,9 @@ def runTest(frame, nb, log): overview = """\ This control provides a calendar control class for displaying and selecting dates. In addition, the class is extended and can now be used for printing/previewing. +Additional features include weekend highlighting and business type Monday-Sunday format. -See example for various methods used to set display month, year, and highlighted dates (different colour). +See example for various methods used to set display month, year, and highlighted dates (different font and background colours). by Lorne White diff --git a/utils/wxPython/demo/wxComboBox.py b/utils/wxPython/demo/wxComboBox.py index b4b3112f05..f3f8de8176 100644 --- a/utils/wxPython/demo/wxComboBox.py +++ b/utils/wxPython/demo/wxComboBox.py @@ -18,11 +18,15 @@ class TestComboBox(wxPanel): wxComboBox(self, 500, "default value", wxPoint(80, 50), wxSize(95, -1), sampleList, wxCB_DROPDOWN) EVT_COMBOBOX(self, 500, self.EvtComboBox) + EVT_TEXT(self, 500, self.EvtText) def EvtComboBox(self, event): self.log.WriteText('EvtComboBox: %s\n' % event.GetString()) + def EvtText(self, event): + self.log.WriteText('EvtText: %s\n' % event.GetString()) + #--------------------------------------------------------------------------- def runTest(frame, nb, log): diff --git a/utils/wxPython/lib/activexwrapper.py b/utils/wxPython/lib/activexwrapper.py index a44f4caab5..f0af36b59d 100644 --- a/utils/wxPython/lib/activexwrapper.py +++ b/utils/wxPython/lib/activexwrapper.py @@ -2,7 +2,7 @@ # Name: wxPython.lib.activexwrapper # Purpose: a wxWindow derived class that can hold an ActiveX control # -# Author: Mike Fletcher, Robin Dunn +# Author: Robin Dunn # # RCS-ID: $Id$ # Copyright: (c) 2000 by Total Control Software @@ -13,70 +13,127 @@ from wxPython.wx import * try: import win32ui + import pywin.mfc.activex + import win32com.client except ImportError: - raise ImportError( "Cannot find win32ui module, wxWindows ActiveXControl module cannot be loaded") + raise ImportError( "ActiveXWrapper requires PythonWin. Please install the win32all-xxx.exe package.") -### Following makes it possible to include this module without -# needing to include the (rather large) win32con module... ##from win32con import WS_TABSTOP, WS_VISIBLE -WS_TABSTOP = 0x10000 +WS_TABSTOP = 0x00010000 WS_VISIBLE = 0x10000000 -class ActiveXWrapper( wxWindow ): +#---------------------------------------------------------------------- + + +def MakeActiveXClass(CoClass, eventClass=None, eventObj=None): """ - Class providing easy integration of ActiveXControls into - wxPython GUI environments. Pass an instantiated control class (one - which inherits from pywin.mfc.activex.Control and a particular control - class generated by gencache) in the argument "control". Alternatively, - pass the instantiated control to the SetControl method to allow for - specifying the win32 style, id, etceteras + Dynamically construct a new class that derives from wxWindow, the + ActiveX control and the appropriate COM classes. This new class + can be used just like the wxWindow class, but will also respond + appropriately to the methods and properties of the COM object. If + this class, a derived class or a mix-in class has method names + that match the COM objects event names, they will be called + automatically. + + CoClass -- A COM control class from a module generated by + makepy.py from a COM TypeLibrary. Can also accept a + CLSID. + + eventClass -- If given, this class will be added to the set of + base classes that the new class is drived from. It is + good for mix-in classes for catching events. + + eventObj -- If given, this object will be searched for attributes + by the new class's __getattr__ method, (like a mix-in + object.) This is useful if you want to catch COM + callbacks in an existing object, (such as the parent + window.) + """ - def __init__( self, parent, ID=-1, pos = wxDefaultPosition, size = wxDefaultSize, - style = 0, - name = "ActiveXControlWindow", - control = None, - controlName = "Control", - eraseBackground = 1, - ): - wxWindow.__init__( self, parent, ID, pos, size, style, name ) - win32ui.EnableControlContainer() - self.windowPointer = win32ui.CreateWindowFromHandle(self.GetHandle()) - if control: - self.SetControl( control, name ) - EVT_SIZE( self, self.OnSize) - if not eraseBackground: - def nullfunction( event ): pass - EVT_ERASE_BACKGROUND( self, nullfunction ) - def SetControl( self, controlObject, name="Control", - style=WS_TABSTOP | WS_VISIBLE, ID=None): - """ - Pass a pre-built control object, calls the control's - CreateControl method with the proper arguments to make it a - child of this window - """ - self.control = controlObject - w,h = self.GetSizeTuple() - if not ID: - ID = wxNewId() - self.control.CreateControl( name, style, (0,0,w,h), - self.windowPointer, - ID) + if type(CoClass) == type(""): + # use the CLSID to get the real class + CoClass = win32com.client.CLSIDToClass(CoClass) + + # determine the base classes + axEventClass = CoClass.default_source + baseClasses = [wxWindow, pywin.mfc.activex.Control, CoClass, axEventClass] + if eventClass: + baseClasses.append(eventClass) + baseClasses = tuple(baseClasses) + + # define the class attributes + className = 'AXControl_'+CoClass.__name__ + classDict = { '__init__' : axw__init__, + '__getattr__' : axw__getattr__, + 'axw_OnSize' : axw_OnSize, + 'axw_OEB' : axw_OEB, + '_name' : className, + '_eventBase' : axEventClass, + '_eventObj' : eventObj, + 'Cleanup' : axw_Cleanup, + } + + # make a new class object + import new + classObj = new.classobj(className, baseClasses, classDict) + return classObj - def Cleanup( self ): - """Delete the reference to the control, to ensure that it is dereferenced.""" - self.control = None - self.windowPointer = None - - def OnSize( self, event=None ): - """wxPython resize event, call MoveWindow on the control""" - size = self.GetClientSize() - self.control.MoveWindow( (0,0,size.width,size.height),1) - +# These functions will be used as methods in the new class +def axw__init__(self, parent, ID, pos=wxDefaultPosition, size=wxDefaultSize, style=0): + # init base classes + pywin.mfc.activex.Control.__init__(self) + wxWindow.__init__(self, parent, -1, pos, size, style) + + win32ui.EnableControlContainer() + self._eventObj = self._eventObj # move from class to instance + + # create a pythonwin wrapper around this wxWindow + handle = self.GetHandle() + self._wnd = win32ui.CreateWindowFromHandle(handle) + + # create the control + sz = self.GetSize() + self.CreateControl(self._name, WS_TABSTOP | WS_VISIBLE, + (0, 0, sz.width, sz.height), self._wnd, ID) + + # init the ax events part of the object + self._eventBase.__init__(self, self._dispobj_) + + # hook some wx events + EVT_SIZE(self, self.axw_OnSize) + EVT_ERASE_BACKGROUND(self, self.axw_OEB) + + +def axw__getattr__(self, attr): + try: + return pywin.mfc.activex.Control.__getattr__(self, attr) + except AttributeError: + try: + eo = self.__dict__['_eventObj'] + return getattr(eo, attr) + except AttributeError: + raise AttributeError('Attribute not found: %s' % attr) + + +def axw_OnSize(self, event): + sz = self.GetClientSize() # get wxWindow size + self.MoveWindow((0, 0, sz.width, sz.height), 1) # move the AXControl + + +def axw_OEB(self, event): + pass + + +def axw_Cleanup(self): + #del self._wnd + self.close() + ## anything else??? + diff --git a/utils/wxPython/lib/calendar.py b/utils/wxPython/lib/calendar.py index f958111dae..a6f2610fbc 100644 --- a/utils/wxPython/lib/calendar.py +++ b/utils/wxPython/lib/calendar.py @@ -19,6 +19,7 @@ CalDays = [6, 0, 1, 2, 3, 4, 5] AbrWeekday = {6:"Sun", 0:"Mon", 1:"Tue", 2:"Wed", 3:"Thu", 4:"Fri", 5:"Sat"} _MIDSIZE = 160 +BusCalDays = [0, 1, 2, 3, 4, 5, 6] # calendar drawing routing @@ -34,13 +35,17 @@ class CalDraw: self.DefParms() def DefParms(self): - self.grid_color = 'BLACK' + self.grid_color = 'BLACK' # grid and selection colors self.back_color = 'WHITE' self.sel_color = 'RED' + self.high_color = 'LIGHT BLUE' self.border_color = 'BLACK' self.week_color = 'LIGHT GREY' + self.week_font_color = 'BLACK' # font colors + self.day_font_color = 'BLACK' + self.font = wxSWISS self.bold = wxNORMAL @@ -49,6 +54,13 @@ class CalDraw: self.outer_border = TRUE self.title_offset = 0 + self.cal_week_scale = 0.7 + self.show_weekend = FALSE + self.cal_type = "NORMAL" + + def SetWeekColor(self, font_color, week_color): # set font and background color for week title + self.week_font_color = font_color + self.week_color = week_color def SetSize(self, size): self.set_sizew = size.width @@ -56,6 +68,7 @@ class CalDraw: def InitValues(self): # default dimensions of various elements of the calendar self.rg = {} + self.cal_sel = {} self.set_cy_st = 0 # start position self.set_cx_st = 0 @@ -83,12 +96,11 @@ class CalDraw: self.y_mrg = self.set_y_mrg * self.pheight self.y_end = self.set_y_end * self.pheight - def DrawCal(self, DC, sel_lst): + def DrawCal(self, DC, sel_lst=[]): self.DC = DC self.InitScale() self.DrawBorder() - if self.hide_title is FALSE: self.DrawMonth() @@ -97,10 +109,24 @@ class CalDraw: self.DrawGrid() self.GetRect() - self.DrawSel(sel_lst) # highlighted days + if self.show_weekend is TRUE: # highlight weekend dates + self.SetWeekEnd() + + self.AddSelect(sel_lst) # overrides the weekend highlight + + self.DrawSel() # highlighted days self.DrawWeek() self.DrawNum() + def AddSelect(self, list, cfont=None, cbackgrd = None): + if cfont is None: + cfont = self.sel_color # font digit color + if cbackgrd is None: + cbackgrd = self.high_color # select background color + + for val in list: + self.cal_sel[val] = (cfont, cbackgrd) + def DrawBorder(self): # draw border around the outside of the main display rectangle brush = wxBrush(wxNamedColour(self.back_color), wxSOLID) self.DC.SetBrush(brush) @@ -123,9 +149,13 @@ class CalDraw: day = 1 t = Date(year, month, day) - dow = t.day_of_week # start day in month - dim = t.days_in_month # number of days in month - start_pos = dow+1 + dow = self.dow = t.day_of_week # start day in month + dim = self.dim = t.days_in_month # number of days in month + if self.cal_type == "NORMAL": + start_pos = dow+1 + else: + start_pos = dow + self.st_pos = start_pos self.cal = [] @@ -137,6 +167,17 @@ class CalDraw: i = i + 1 return start_pos + def SetWeekEnd(self, font_color='BLACK', backgrd = 'LIGHT GREY'): + date = 6 - int(self.dow) # start day of first saturday + while date <= self.dim: + self.cal_sel[date] = (font_color, backgrd) # Saturday + date = date + 1 + if date <= self.dim: + self.cal_sel[date] = (font_color, backgrd) # Sunday + date = date + 6 + else: + date = date + 7 + def GetRect(self): # get the display rectange list of the day grid cnt = 0 for y in self.gridy[1:-1]: @@ -168,13 +209,13 @@ class CalDraw: year = str(self.year) tw,th = self.DC.GetTextExtent(year) - adjust = self.cx_st + self.sizew-tw-20 + adjust = self.sizew - tw - self.x_mrg self.title_offset = th * 2 f = wxFont(sizef, self.font, wxNORMAL, self.bold) self.DC.SetFont(f) - self.DC.DrawText(year, adjust, self.cy_st + th) + self.DC.DrawText(year, self.cx_st + adjust, self.cy_st + th) def DrawWeek(self): # draw the week days sizef = 8 @@ -183,6 +224,7 @@ class CalDraw: f = wxFont(sizef, self.font, wxNORMAL, self.bold) self.DC.SetFont(f) + self.DC.SetTextForeground(wxNamedColour(self.week_font_color)) cnt_x = 0 cnt_y = 0 @@ -195,7 +237,12 @@ class CalDraw: self.DC.SetBrush(brush) # self.DC.DrawRectangle(self.gridx[0], self.gridy[0], rect_w+1, height) - for val in CalDays: + if self.cal_type == "NORMAL": + cal_days = CalDays + else: + cal_days = BusCalDays + + for val in cal_days: day = AbrWeekday[val] if self.sizew < 200: day = day[0] @@ -215,13 +262,22 @@ class CalDraw: if self.sizeh < _MIDSIZE: sizef = 8 f = wxFont(sizef, self.font, wxNORMAL, self.bold) - self.DC.SetFont(f) cnt_x = 0 cnt_y = 1 for val in self.cal: x = self.gridx[cnt_x] y = self.gridy[cnt_y] + + try: + num_val = int(val) + num_color = self.cal_sel[num_val][0] + except: + num_color = self.day_font_color + + self.DC.SetTextForeground(wxNamedColour(num_color)) + self.DC.SetFont(f) + self.DC.DrawText(val, x+5, y+5) if cnt_x < 6: cnt_x = cnt_x + 1 @@ -236,14 +292,16 @@ class CalDraw: self.dl_w = int((self.sizew-bdw)/7) self.dl_h = int((self.sizeh-bdh)/7) - self.dl_th = int(2*self.dl_h/3) # week title adjustment + self.dl_th = int(self.dl_h*self.cal_week_scale) # week title adjustment self.cwidth = self.dl_w * 7 self.cheight = self.dl_h * 6 + self.dl_th - def DrawSel(self, sel_lst): # highlighted selected days - for key in sel_lst: - brush = wxBrush(wxNamedColour(self.high_color), wxSOLID) + def DrawSel(self): # highlighted selected days + for key in self.cal_sel.keys(): + sel_color = self.cal_sel[key][1] + brush = wxBrush(wxNamedColour(sel_color), wxSOLID) self.DC.SetBrush(brush) + if self.hide_grid is FALSE: self.DC.SetPen(wxPen(wxNamedColour(self.grid_color), 0)) else: @@ -288,6 +346,7 @@ class CalDraw: class PrtCalDraw(CalDraw): def InitValues(self): self.rg = {} + self.cal_sel = {} self.set_cx_st = 1.0 # start draw border location self.set_cy_st = 1.0 @@ -313,6 +372,13 @@ class wxCalendar(wxWindow): self.hide_grid = FALSE self.sel_color = 'RED' self.hide_title = FALSE + self.show_weekend = FALSE + self.cal_type = "NORMAL" + + self.week_color = 'LIGHT GREY' + self.week_font_color = 'BLACK' # font colors + + self.select_list = [] self.SetBackgroundColour(wxNamedColor(self.back_color)) self.Connect(-1, -1, wxEVT_LEFT_DOWN, self.OnLeftEvent) @@ -464,6 +530,20 @@ class wxCalendar(wxWindow): # calendar drawing + def SetWeekColor(self, font_color, week_color): # set font and background color for week title + self.week_font_color = font_color + self.week_color = week_color + + def AddSelect(self, list, font_color, back_color): + list_val = [list, font_color, back_color] + self.select_list.append(list_val) + + def ShowWeekEnd(self): + self.show_weekend = TRUE # highlight weekend + + def SetBusType(self): + self.cal_type = "BUS" + def OnPaint(self, event): DC = wxPaintDC(self) self.DoDrawing(DC) @@ -474,6 +554,14 @@ class wxCalendar(wxWindow): self.cal = cal = CalDraw(self) + cal.grid_color = self.grid_color + cal.back_color = self.back_color + cal.hide_grid = self.hide_grid + cal.grid_color = self.grid_color + cal.hide_title = self.hide_title + cal.show_weekend = self.show_weekend + cal.cal_type = self.cal_type + if self.size is None: size = self.GetClientSize() else: @@ -481,14 +569,14 @@ class wxCalendar(wxWindow): # drawing attributes - cal.grid_color = 'BLUE' - cal.back_color = self.back_color - cal.hide_grid = self.hide_grid - cal.grid_color = self.grid_color - cal.hide_title = self.hide_title + cal.week_font_color = self.week_font_color + cal.week_color = self.week_color cal.SetSize(size) cal.SetCal(self.year, self.month) + for val in self.select_list: + cal.AddSelect(val[0], val[1], val[2]) + cal.DrawCal(DC, self.sel_lst) self.rg = cal.GetRect()