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
1 from wxPython.wx import *
2 if wxPlatform == '__WXMSW__':
3 from wxPython.lib.activexwrapper import MakeActiveXClass
4 import _OfficeWebComponents
5
6 try:
7 OWCModule = _OfficeWebComponents
8 except:
9 raise ImportError("Could not import Office Web Components")
10
11
12 """
13 OWCChartWrapper provides a means to relatively straightforwardly display
14 plotted information by using the chart ActiveX control which forms part of
15 the Microsoft Office Web Controls to display chart data.
16
17 This file imports a wrapper generated by makepy.py, a tools for generating
18 Python wrappers to COM objects. The wrapper was copied from
19 c:\Python22\Lib\site-packages\win32com\gen_py (which is where makepy puts it,
20 under the name of the COM object class ID) and given a more sensible name.
21
22 DO NOT edit _OfficeWebComponents.py - it's a generated file.
23
24 This module was tested against Office 2000 Web Components, but should probably
25 work with newer versions of the components. You will need a license for Office
26 which matches the version of the Web Components you are using, or this won't
27 work.
28 """
29
30 class lineChartPanel(wxPanel):
31 def __init__(self, parent):
32 wxPanel.__init__(self, parent, -1, style=wxCLIP_CHILDREN|wxNO_FULL_REPAINT_ON_RESIZE)
33
34 # Create a class encapsulating the Office Web Components chart control
35 cChart = MakeActiveXClass(OWCModule.ChartSpace, eventObj = self)
36
37 # Create a local instance of the Chart Class
38 self.oChart = cChart(self, -1)
39
40 # Create an alias for the control properties
41 self.c = self.oChart.Constants
42 self.oChart.Charts.Add()
43 #oChart.Charts[0].Type = c.chChartTypeSmoothLine
44 self.series_data = {}
45
46 # Sizer and so on...
47 sizer = wxBoxSizer(wxVERTICAL)
48 sizer.Add(self.oChart, 1, wxEXPAND)
49 self.SetSizer(sizer)
50 self.SetAutoLayout(true)
51 EVT_SIZE(self, self.onSize)
52 EVT_WINDOW_DESTROY(self, self.onDestroy)
53
54 def onDestroy(self, evt):
55 if self.oChart:
56 self.oChart.Cleanup()
57 self.oChart = None
58
59 def onSize(self, evt):
60 self.Layout()
61
62 def setCaption(self, chart_type, caption):
63 """Set the chart caption"""
64 self.oChart.Charts[0].Type = chart_type
65 self.oChart.Charts[0].HasTitle = True
66 self.oChart.Charts[0].Title.Caption = caption
67 self.oChart.Charts[0].Title.Font.Name = "Helvetica"
68 self.oChart.Charts[0].Title.Font.Size = 12
69 self.oChart.Charts[0].Title.Font.Bold = True
70
71 def setAxis(self, axis, text, major, minor):
72 if axis == 'X':
73 position = self.c.chAxisPositionBottom
74 else:
75 position = self.c.chAxisPositionLeft
76 self.oChart.Charts[0].Axes(position).HasTitle = True
77 self.oChart.Charts[0].Axes(position).Title.Caption = text
78 self.oChart.Charts[0].Axes(position).Title.Font.Size = 8
79 self.oChart.Charts[0].Axes(position).MajorUnit = major
80 self.oChart.Charts[0].Axes(position).MinorUnit = minor
81
82 def addDataSet(self, set_name, data_list):
83 """Add a category, with its data, to the chart."""
84 self.series_data[set_name] = data_list
85
86 def finaliseChartData(self):
87 """Once all data has been defined, insert all of the data sets."""
88 ordered_keys = self.series_data.keys()
89 ordered_keys.sort()
90 self.oChart.Charts[0].SeriesCollection.Add()
91 self.oChart.Charts[0].SeriesCollection[0].SetData(self.c.chDimCategories,
92 self.c.chDataLiteral,
93 ordered_keys)
94 b = [self.series_data[k] for k in ordered_keys]
95 self.oChart.Charts[0].SeriesCollection[0].SetData(self.c.chDimValues,
96 self.c.chDataLiteral,
97 b)
98
99 #----------------------------------------------------------------------
100
101
102 if __name__ == '__main__':
103 class TestFrame(wxFrame):
104 def __init__(self):
105 wxFrame.__init__(self, None, -1, "ActiveX test -- Internet Explorer",
106 size=(640, 480),
107 style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
108 self.CreateStatusBar()
109 self.tp = lineChartPanel(self)
110 self.tp.setCaption(self.tp.c.chChartTypeSmoothLine, 'Test')
111 self.tp.addDataSet(1, 6)
112 self.tp.addDataSet(2, 8)
113 self.tp.addDataSet(3, 10)
114 self.tp.addDataSet(4, 12)
115 self.tp.addDataSet(5, 14)
116 self.tp.addDataSet(6, 16)
117 self.tp.finaliseChartData()
118 EVT_CLOSE(self, self.OnCloseWindow)
119
120 def OnCloseWindow(self, evt):
121 self.tp.Destroy()
122 self.Destroy()
123
124 app = wxPySimpleApp()
125 frame = TestFrame()
126 frame.Show(true)
127 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()