我如何在Python中使用win32com检索Excel IRibbonUI实例?



我正在尝试使用Python的win32com包使Excel加载项ribbon上的特定控件无效,以便让它们的回调重新启动。

阅读微软的对象引用和IRibbonUI文档,我所看到的建议是在其onLoad回调中保存对ribbon的引用。这也是我过去在VBA编码时实现这一点的方式。不幸的是,我不确定如何使用python的win32com包达到这一点。

我使用PyXLL作为使用Python编写外接程序的一种方法,并在未来的发行中使用xll而不是xlam。通过使用这个,我能够在功能区onLoad回调中访问功能区com对象,但不能在功能区中包含的控件的onClick回调中访问,因为传递给这些函数的唯一参数是控件的com对象。

相关调试信息

  • 参数传递到功能区onLoad回调是win32com.gen_py.Microsoft Office 16.0 Object Library.IRibbonUI的一个实例
  • 参数的_oleobj_值是PyIDispatch实例
  • 错误似乎集中在win32com.client
  • 中的DispatchBaseClass
class DispatchBaseClass:
def __init__(self, oobj=None):
if oobj is None:
oobj = pythoncom.new(self.CLSID)
elif isinstance(oobj, DispatchBaseClass):
try:
oobj = oobj._oleobj_.QueryInterface(
self.CLSID, pythoncom.IID_IDispatch
)  # Must be a valid COM instance
except pythoncom.com_error as details:
import winerror
# Some stupid objects fail here, even tho it is _already_ IDispatch!!??
# Eg, Lotus notes.
# So just let it use the existing object if E_NOINTERFACE
if details.hresult != winerror.E_NOINTERFACE:
raise
oobj = oobj._oleobj_
self.__dict__["_oleobj_"] = oobj  # so we dont call __setattr__
  • 我的想法是保存对实际类的引用,重新创建它,设置CLSID类变量,然后实例化新类。
def ribbon_loaded(ribbon):
r_class = ribbon.__class__
# was thinking I could pickle this class for use elsewhere
class RibbonUI(r_class):  # also tried type(r_class)
CLSID = ribbon.CLSID

# just checking below that this would work
# if CLSID is not set on the new class above __init__ fails
# but, even when provided __new__ fails with the next line
new_ribbon = RibbonUI()
new_ribbon.InvalidateControl("ribbon_control_1")

如果没有在新类上设置CLSID,错误是

2022-07-06 20:48:09,294 - INFO : ribbon.CLSID: IID('{000C03A7-0000-0000-C000-000000000046}')
2022-07-06 20:48:09,314 - ERROR : Error calling ribbon function 'components.ribbon.ribbon_loaded'
2022-07-06 20:48:15,364 - ERROR : Traceback (most recent call last):
2022-07-06 20:48:15,364 - ERROR :   File "C:UsersmhillPycharmProjectsexcel-addincomponentsribbon.py", line 46, in ribbon_loaded
2022-07-06 20:48:15,365 - ERROR :     new_ribbon = RibbonUI()
2022-07-06 20:48:15,366 - ERROR :   File "c:usersmhillPyCharmProjectsexcel-addin.venvlibsite-packageswin32comclient__init__.py", line 514, in __init__
2022-07-06 20:48:15,366 - ERROR :     oobj = pythoncom.new(self.CLSID)
2022-07-06 20:48:15,366 - ERROR : pywintypes.com_error: (-2147221164, 'Class not registered', None, None)

创建新类时,指定CLSID类变量误差成为

2022-07-06 20:48:22,429 - INFO : ribbon.CLSID: IID('{000C03A7-0000-0000-C000-000000000046}')
2022-07-06 20:48:22,429 - ERROR : Error calling ribbon function 'components.ribbon.ribbon_loaded'
2022-07-06 20:48:28,949 - ERROR : Traceback (most recent call last):
2022-07-06 20:48:28,950 - ERROR :   File "C:UsersmhillPycharmProjectsexcel-addincomponentsribbon.py", line 46, in ribbon_loaded
2022-07-06 20:48:28,951 - ERROR :     new_ribbon = RibbonUI()
2022-07-06 20:48:28,951 - ERROR : TypeError: type.__new__() takes exactly 3 arguments (0 given)

相关问题提到创建一个IDTExtensibility2对象,但不太确定该怎么做。

<标题>

除了模仿从功能区的onLoad回调中保存对功能区对象的全局引用,正如微软的文档所建议的,我如何才能在功能区onLoad回调中正确保存对iribbonu.com对象的引用,并能够在控件的onClick回调中访问它?

哎呀,看起来全局变量选项是推荐的路由

<标题>摘录


例如,在功能区XML中,您可以将onLoad操作添加到customUI元素如下所示(假设您的代码位于名为your_module.py):

<customUI
xmlns="http://schemas.microsoft.com/office/2009/07/customui"
onLoad="your_module.on_load"
>
<!-- your ribbon definition here -->
</customUI>

然后在你的模块("your_module.py"用在上面)你会加动作吗函数"on_load"这需要IRibbonUI对象。然后可以保存这是一个全局变量,这样您就可以称之为"Invalidate"方法以后。

_ribbon = None
def on_load(control):
global _ribbon
_ribbon = control
# Later when you want to invalidate a control you would call
_ribbon.InvalidateControl(control_id)

相关内容

  • 没有找到相关文章

最新更新