Poodletooth-iLand/panda/python/Lib/site-packages/wx/lib/activex.py
2015-03-06 06:11:40 -06:00

172 lines
6 KiB
Python

#----------------------------------------------------------------------
# Name: wx.lib.activex
# Purpose: The 3rd (and hopefully final) implementation of an
# ActiveX container for wxPython.
#
# Author: Robin Dunn
#
# Created: 5-June-2008
# Copyright: (c) 2008 by Total Control Software
# Licence: wxWindows license
#----------------------------------------------------------------------
"""
This module provides a wx.Window that hosts ActiveX Controls using
just the ctypes and comtypes packages. This provides a light-weight
COM implementation with full dynamic dispatch support.
The only requirements are ctypes (included with Python 2.5 and
available separately for earlier versions of Python) and the comtypes
package, which is available from
http://starship.python.net/crew/theller/comtypes/. Be sure to get at
least version 0.5, which at the time of this writing is only available
from SVN. You can fetch it with easy_install with a command like
this:
easy_install http://svn.python.org/projects/ctypes/trunk/comtypes
"""
import wx
import ctypes as ct
import ctypes.wintypes as wt
import comtypes
import comtypes.client as cc
import comtypes.hresult as hr
import sys, os
if not hasattr(sys, 'frozen'):
f = os.path.join(os.path.dirname(__file__), 'myole4ax.tlb')
cc.GetModule(f)
from comtypes.gen import myole4ax
kernel32 = ct.windll.kernel32
user32 = ct.windll.user32
atl = ct.windll.atl
WS_CHILD = 0x40000000
WS_VISIBLE = 0x10000000
WS_CLIPCHILDREN = 0x2000000
WS_CLIPSIBLINGS = 0x4000000
CW_USEDEFAULT = 0x80000000
WM_KEYDOWN = 256
WM_DESTROY = 2
#------------------------------------------------------------------------------
class ActiveXCtrl(wx.PyAxBaseWindow):
"""
A wx.Window for hosting ActiveX controls. The COM interface of
the ActiveX control is accessible through the ctrl property of
this class, and this class is also set as the event sink for COM
events originating from the ActiveX control. In other words, to
catch the COM events you mearly have to derive from this class and
provide a method with the correct name. See the comtypes package
documentation for more details.
"""
def __init__(self, parent, axID, wxid=-1, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=0, name="activeXCtrl"):
"""
All parameters are like those used in normal wx.Windows with
the addition of axID which is a string that is either a ProgID
or a CLSID used to identify the ActiveX control.
"""
pos = wx.Point(*pos) # in case the arg is a tuple
size = wx.Size(*size) # ditto
x = pos.x
y = pos.y
if x == -1: x = CW_USEDEFAULT
if y == -1: y = 20
w = size.width
h = size.height
if w == -1: w = 20
if h == -1: h = 20
# create the control
atl.AtlAxWinInit()
hInstance = kernel32.GetModuleHandleA(None)
hwnd = user32.CreateWindowExA(0, "AtlAxWin", axID,
WS_CHILD | WS_VISIBLE
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
x,y, w,h, parent.GetHandle(), None,
hInstance, 0)
assert hwnd != 0
# get the Interface for the Ax control
unknown = ct.POINTER(comtypes.IUnknown)()
res = atl.AtlAxGetControl(hwnd, ct.byref(unknown))
assert res == hr.S_OK
self._ax = cc.GetBestInterface(unknown)
# Fetch the interface for IOleInPlaceActiveObject. We'll use this
# later to call its TranslateAccelerator method so the AX Control can
# deal with things like tab traversal and such within itself.
self.ipao = self._ax.QueryInterface(myole4ax.IOleInPlaceActiveObject)
# Use this object as the event sink for the ActiveX events
self._evt_connections = []
self.AddEventSink(self)
# Turn the window handle into a wx.Window and set this object to be that window
win = wx.PyAxBaseWindow_FromHWND(parent, hwnd)
self.PostCreate(win)
# Set some wx.Window properties
if wxid == wx.ID_ANY:
wxid = wx.Window.NewControlId()
self.SetId(wxid)
self.SetName(name)
self.SetMinSize(size)
self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroyWindow)
def AddEventSink(self, sink, interface=None):
"""
Add a new target to search for method names that match the COM
Event names.
"""
self._evt_connections.append(cc.GetEvents(self._ax, sink, interface))
def GetCtrl(self):
"""Easy access to the COM interface for the ActiveX Control"""
return self._ax
# And an even easier property
ctrl = property(GetCtrl)
def MSWTranslateMessage(self, msg):
# Pass native messages to the IOleInPlaceActiveObject
# interface before wx processes them, so navigation keys and
# accelerators can be dealt with the way that the AXControl
# wants them to be done. MSWTranslateMessage is called before
# wxWidgets handles and eats the navigation keys itself.
res = self.ipao.TranslateAccelerator(msg)
if res == hr.S_OK:
return True
else:
return wx.PyAxBaseWindow.MSWTranslateMessage(self, msg)
# TBD: Are the focus handlers needed?
def OnSetFocus(self, evt):
self.ipao.OnFrameWindowActivate(True)
def OnKillFocus(self, evt):
self.ipao.OnFrameWindowActivate(False)
def OnDestroyWindow(self, evt):
# release our event sinks while the window still exists
self._evt_connections = None
#------------------------------------------------------------------------------