如何在Python中模拟vb的控件数组以用于win32com?

1 投票
2 回答
1937 浏览
提问于 2025-04-15 17:36

我需要从一个 ActiveX DLL 动态创建 COM 对象,每个对象都可以触发事件,而这些事件需要用事件处理程序来处理。

我可以很简单地使用 win32com.client.Dispatchwin32com.client.WithEvents,并为每个对象关联一个“独立”的事件处理类。就像这样:

class evt_1:
    def OnEvent(self):
        print "got event from object 1"

class evt_2:
    def OnEvent(self):
        print "got event from object 2"

obj_1 = win32com.client.Dispatch("mycom")
ev_1  = win32com.client.WithEvents(obj_1, evt_1)

obj_2 = win32com.client.Dispatch("mycom")
ev_1  = win32com.client.WithEvents(obj_2, evt_2)

但是如果我动态创建这些对象,比如放在一个列表里:

listOfObjects = []
for i in range(10):
    obj = win32com.client.Dispatch("mycom")
    listOfObjects.append(obj)
    ev = win32com.client.WithEvents(obj, MyEventHandlerClass)

我希望事件处理程序只写一次,因为我在运行时才知道会创建多少个对象。而且我不知道如何在事件处理程序内部获取触发事件的对象。

在 VB 6 中,我使用 ActiveX 控件时用过控件数组,事件处理程序会简单地获取触发事件的控件的“索引”值。

你觉得在 Python 中能做类似的事情吗?
我不太确定 Python 的装饰器是干什么用的,但它们能否用来为每个 COM 对象的索引“装饰” MyEventHandlerClass?

2 个回答

0

在VB.NET中,控制数组被去掉了,所以我觉得在win32com中也不支持这个功能。不是很确定这对你是否有帮助,但你能把索引传递给事件处理类吗?

class MyEventHandler:
    def __init__(self, index):
        self.obj_index = index

    def OnEvent(self):
        print "got event from object %d" % self.obj_index

listOfObjects = []
for i in range(10):
    obj = win32com.client.Dispatch("mycom")
    listOfObjects.append(obj)
    ev = win32com.client.WithEvents(obj, MyEventHandlerClass(i))

如果事件需要访问数组中的所有控件(而不仅仅是索引),你可以通过在事件处理器中循环遍历你的对象列表来模拟一个控制数组,并确定哪个对象触发了事件……比如说,一个RadioButton_CheckChanged()事件可能看起来是这样的:

def RadioButton_CheckChanged():
    for radiobutton in listOfRadioButtons:
        if radiobutton.Checked:
            # this is the one that was clicked on
0

win32com在处理事件时有一个大缺陷,就是你必须传入一个类对象,而不是类的实例。

不过,你可以通过使用new.classobj动态创建类来给你的类添加状态,这样就能在win32com中使用了:

from win32com.client import Dispatch, WithEvents
from new import classobj

class MyEventHandler(object):
    def OnVisible(self, visible):
        print "got event from object %d" % self.obj_index

listOfObjects = []
for i in range(3):
    handler = classobj('Handler_%s' % i,(MyEventHandler,),{})
    handler.obj_index = i
    ie = Dispatch("InternetExplorer.Application")
    listOfObjects.append(ie)
    WithEvents(ie, handler)

listOfObjects[0].Visible = 1
listOfObjects[2].Visible = 1

输出结果:

got event from object 0
got event from object 2

如果你想以更合理的方式来实现这个功能,可以看看comtypes模块(具体可以参考事件处理部分)。

撰写回答