开发者

How to mimic vb's control array in python for win32com?

开发者 https://www.devze.com 2022-12-15 04:22 出处:网络
I need to dynamically create com objects from an activex dll and each of the objects can raise events which should be handled with event handlers.

I need to dynamically create com objects from an activex dll and each of the objects can raise events which should be handled with event handlers.

I can do this easily with win32com.client.Dispatch and win32com.client.WithEvents and associate a "separate" class of event handlers with each of the objects. Like so:

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

class evt_2:
    def On开发者_如何学GoEvent(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)

But if I dynamically create the objects, lets say in a list:

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

I want to code the event handlers only once, since I don't know how many objects I would be creating until run time. And I don't know how to get the object that raised the event from inside the event handler.

In VB 6, I've used the activex control using control arrays, and the event handlers simply get an "index" value of the control that raised the event.

Do you think something similar can be done in python ?

I am not sure what python decorators work for, but can they be used to "decorate" the MyEventHandlerClass for each index of the com object?


It's a major flaw of win32com's event handling that you have to pass in a class object rather than a class instance.

You can attach state to your classes using win32com, however, by creating classes dynamically using new.classobj:

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

Output:

got event from object 0
got event from object 2

You might want to look into the comtypes module (see event handling) if you want to do this in a saner way.


Control Arrays were removed in VB.NET so I don't think they would be supported in the win32com. Not sure if this would work for you but can you pass the index to the EventHandler class?

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

If the event needs access to all of the controls in the array (not just the index), you can mimic a control array by looping through your listOfObjects in the EventHandler, and determining which object raised the Event... so for example, a RadioButton_CheckChanged() event would look like:

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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号