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()

OfficeWebComponents (last edited 2010-08-26 02:58:31 by c-76-123-96-54)

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.