== Introduction == Embedding ActiveX controls in a wxFrame == What Objects are Involved == Obviously this is win32 specific. In the example given, I create a (very simple) wrapper around the Office Web Components chart control. Recent versions of MS Office (example was verified with Office 2000) should come with Office Web Components, although they may be an optional installation item. == Process Overview == First thing to do is to create a wrapper around the desired ActiveX component. On my ActiveState Python install, the easiest way to do this is to use the makepy.py script (in my installation this is at c:\Python22\Lib\site-packages\win32com\client. This launches a selection box in which you can select the ActiveX/COM components for which you wish to generate a wrapper. Select Microsoft Office Web Components, then OK. The makepy.py script outputs, in the win32com\gen_py directory, a Python module named after the GUID of the control in question (in my case with the snappy name 0002E540-0000-0000-C000-000000000046x0x1x0.py). Although win32com can use this directly in an automated fashion, if you wish to distribute a Python script using the ActiveX component, it may be easier to take a copy and give it a more friendly name (e.g. _OfficeWebComponents.py) and put it in a suitable directory with the other parts of your script. The example given does this. Given all of the above, you can test the sample given. == Special Concerns == Main issue is to ensure that your generated wrapper matches the version of a control installed on your machine. == Code Sample == {{{ #!python from wxPython.wx import * if wxPlatform == '__WXMSW__': from wxPython.lib.activexwrapper import MakeActiveXClass import _OfficeWebComponents try: OWCModule = _OfficeWebComponents except: raise ImportError("Could not import Office Web Components") """ OWCChartWrapper provides a means to relatively straightforwardly display plotted information by using the chart ActiveX control which forms part of the Microsoft Office Web Controls to display chart data. This file imports a wrapper generated by makepy.py, a tools for generating Python wrappers to COM objects. The wrapper was copied from c:\Python22\Lib\site-packages\win32com\gen_py (which is where makepy puts it, under the name of the COM object class ID) and given a more sensible name. DO NOT edit _OfficeWebComponents.py - it's a generated file. This module was tested against Office 2000 Web Components, but should probably work with newer versions of the components. You will need a license for Office which matches the version of the Web Components you are using, or this won't work. """ class lineChartPanel(wxPanel): def __init__(self, parent): wxPanel.__init__(self, parent, -1, style=wxCLIP_CHILDREN|wxNO_FULL_REPAINT_ON_RESIZE) # Create a class encapsulating the Office Web Components chart control cChart = MakeActiveXClass(OWCModule.ChartSpace, eventObj = self) # Create a local instance of the Chart Class self.oChart = cChart(self, -1) # Create an alias for the control properties self.c = self.oChart.Constants self.oChart.Charts.Add() #oChart.Charts[0].Type = c.chChartTypeSmoothLine self.series_data = {} # Sizer and so on... sizer = wxBoxSizer(wxVERTICAL) sizer.Add(self.oChart, 1, wxEXPAND) self.SetSizer(sizer) self.SetAutoLayout(true) EVT_SIZE(self, self.onSize) EVT_WINDOW_DESTROY(self, self.onDestroy) def onDestroy(self, evt): if self.oChart: self.oChart.Cleanup() self.oChart = None def onSize(self, evt): self.Layout() def setCaption(self, chart_type, caption): """Set the chart caption""" self.oChart.Charts[0].Type = chart_type self.oChart.Charts[0].HasTitle = True self.oChart.Charts[0].Title.Caption = caption self.oChart.Charts[0].Title.Font.Name = "Helvetica" self.oChart.Charts[0].Title.Font.Size = 12 self.oChart.Charts[0].Title.Font.Bold = True def setAxis(self, axis, text, major, minor): if axis == 'X': position = self.c.chAxisPositionBottom else: position = self.c.chAxisPositionLeft self.oChart.Charts[0].Axes(position).HasTitle = True self.oChart.Charts[0].Axes(position).Title.Caption = text self.oChart.Charts[0].Axes(position).Title.Font.Size = 8 self.oChart.Charts[0].Axes(position).MajorUnit = major self.oChart.Charts[0].Axes(position).MinorUnit = minor def addDataSet(self, set_name, data_list): """Add a category, with its data, to the chart.""" self.series_data[set_name] = data_list def finaliseChartData(self): """Once all data has been defined, insert all of the data sets.""" ordered_keys = self.series_data.keys() ordered_keys.sort() self.oChart.Charts[0].SeriesCollection.Add() self.oChart.Charts[0].SeriesCollection[0].SetData(self.c.chDimCategories, self.c.chDataLiteral, ordered_keys) b = [self.series_data[k] for k in ordered_keys] self.oChart.Charts[0].SeriesCollection[0].SetData(self.c.chDimValues, self.c.chDataLiteral, b) #---------------------------------------------------------------------- if __name__ == '__main__': class TestFrame(wxFrame): def __init__(self): wxFrame.__init__(self, None, -1, "ActiveX test -- Internet Explorer", size=(640, 480), style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.CreateStatusBar() self.tp = lineChartPanel(self) self.tp.setCaption(self.tp.c.chChartTypeSmoothLine, 'Test') self.tp.addDataSet(1, 6) self.tp.addDataSet(2, 8) self.tp.addDataSet(3, 10) self.tp.addDataSet(4, 12) self.tp.addDataSet(5, 14) self.tp.addDataSet(6, 16) self.tp.finaliseChartData() EVT_CLOSE(self, self.OnCloseWindow) def OnCloseWindow(self, evt): self.tp.Destroy() self.Destroy() app = wxPySimpleApp() frame = TestFrame() frame.Show(true) app.MainLoop() }}} === Comments === You can't just use the downloaded version of OWC to test this - if you don't have an Office license, the Office Web Components run in a function-limited way. The OWC documentation is stored (on an English version of Office) under "C:\Program Files\Microsoft Office\Office\1033\MSOWCVBA.CHM". Examples for Visual BASIC are not too difficult to translate into Python. =============================================================================== Hi, I'm not familiar with the protocol on this site, so I thought I'd dump this here. I am using Python 2.5.4 with wxPython2.8-win32-unicode-2.8.11.0-py25.exe. I had to edit the above code as follows to get this to work. Please find every place a PTB is inserted (my initials) to see the changes. {{{ #PTB: All true and false were changed to True and False #PTB: was from wxPython.wx import * import wx #PTB was wxPlatform if wx.Platform == '__WXMSW__': #PTB was from wxPython.lib.activexwrapper import MakeActiveXClass from wx.lib.activexwrapper import MakeActiveXClass import _OfficeWebComp11 try: OWCModule = _OfficeWebComp11 except: raise ImportError("Could not import Office Web Components") """ OWCChartWrapper provides a means to relatively straightforwardly display plotted information by using the chart ActiveX control which forms part of the Microsoft Office Web Controls to display chart data. This file imports a wrapper generated by makepy.py, a tools for generating Python wrappers to COM objects. The wrapper was copied from c:\Python22\Lib\site-packages\win32com\gen_py (which is where makepy puts it, under the name of the COM object class ID) and given a more sensible name. DO NOT edit _OfficeWebComponents.py - it's a generated file. This module was tested against Office 2000 Web Components, but should probably work with newer versions of the components. You will need a license for Office which matches the version of the Web Components you are using, or this won't work. """ class lineChartPanel(wx.Panel): #PTB: was wxPanel def __init__(self, parent): #PTB: was wxPanel.__init__(self, parent, -1, style=wxCLIP_CHILDREN|wxNO_FULL_REPAINT_ON_RESIZE) wx.Panel.__init__(self, parent, -1, style=wx.CLIP_CHILDREN|wx.NO_FULL_REPAINT_ON_RESIZE) # Create a class encapsulating the Office Web Components chart control cChart = MakeActiveXClass(OWCModule.ChartSpace, eventObj = self) # Create a local instance of the Chart Class self.oChart = cChart(self, -1) # Create an alias for the control properties self.c = self.oChart.Constants self.oChart.Charts.Add() #oChart.Charts[0].Type = c.chChartTypeSmoothLine self.series_data = {} # Sizer and so on... """ PTB: was sizer = wxBoxSizer(wxVERTICAL) sizer.Add(self.oChart, 1, wxEXPAND) """ sizer = wx.BoxSizer(wx.VERTICAL) sizer.Add(self.oChart, 1, wx.EXPAND) self.SetSizer(sizer) self.SetAutoLayout(True) """ PTB: was EVT_SIZE(self, self.onSize) EVT_WINDOW_DESTROY(self, self.onDestroy) """ wx.EVT_SIZE(self, self.onSize) wx.EVT_WINDOW_DESTROY(self, self.onDestroy) def onDestroy(self, evt): if self.oChart: self.oChart.Cleanup() self.oChart = None def onSize(self, evt): self.Layout() def setCaption(self, chart_type, caption): """Set the chart caption""" self.oChart.Charts[0].Type = chart_type self.oChart.Charts[0].HasTitle = True self.oChart.Charts[0].Title.Caption = caption self.oChart.Charts[0].Title.Font.Name = "Helvetica" self.oChart.Charts[0].Title.Font.Size = 12 self.oChart.Charts[0].Title.Font.Bold = True def setAxis(self, axis, text, major, minor): if axis == 'X': position = self.c.chAxisPositionBottom else: position = self.c.chAxisPositionLeft self.oChart.Charts[0].Axes(position).HasTitle = True self.oChart.Charts[0].Axes(position).Title.Caption = text self.oChart.Charts[0].Axes(position).Title.Font.Size = 8 self.oChart.Charts[0].Axes(position).MajorUnit = major self.oChart.Charts[0].Axes(position).MinorUnit = minor def addDataSet(self, set_name, data_list): """Add a category, with its data, to the chart.""" self.series_data[set_name] = data_list def finaliseChartData(self): """Once all data has been defined, insert all of the data sets.""" ordered_keys = self.series_data.keys() ordered_keys.sort() self.oChart.Charts[0].SeriesCollection.Add() self.oChart.Charts[0].SeriesCollection[0].SetData(self.c.chDimCategories, self.c.chDataLiteral, ordered_keys) b = [self.series_data[k] for k in ordered_keys] self.oChart.Charts[0].SeriesCollection[0].SetData(self.c.chDimValues, self.c.chDataLiteral, b) #---------------------------------------------------------------------- if __name__ == '__main__': class TestFrame(wx.Frame): #PTB: was wxFrame def __init__(self): #PTB was wxFrame wx.Frame.__init__(self, None, -1, "ActiveX test -- Internet Explorer", size=(640, 480),style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE) #PTB was style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE) self.CreateStatusBar() self.tp = lineChartPanel(self) self.tp.setCaption(self.tp.c.chChartTypeSmoothLine, 'Test') self.tp.addDataSet(1, 6) self.tp.addDataSet(2, 8) self.tp.addDataSet(3, 10) self.tp.addDataSet(4, 12) self.tp.addDataSet(5, 14) self.tp.addDataSet(6, 16) self.tp.finaliseChartData() #PTB was EVT_CLOSE(self, self.OnCloseWindow) wx.EVT_CLOSE(self, self.OnCloseWindow) def OnCloseWindow(self, evt): self.tp.Destroy() self.Destroy() app = wx.PySimpleApp() #PTB: was app = wxPySimpleApp frame = TestFrame() frame.Show(True) app.MainLoop() }}}