From: John H. <ec...@ya...> - 2009-11-02 16:43:05
|
Using the same approach as PDFWindow, I managed to create a wrapper for FlashWindow. Unlike PDFWindow, this one actually works. However, layoutEditor doesn't recognize it and screws up. How do I added it to layoutEditor. Here's the wrapper code, follow by test sample program: """ __version__ = "$Revision: 1.19 $" __date__ = "$Date: 2004/05/13 02:40:24 $" """ import wx if wx.Platform == '__WXMSW__': from wx.lib import flashwin else: # need a graceful exit pass from PythonCard import event, log, widget FlashWindowEvents = ( ) class FlashWindowSpec(widget.WidgetSpec): def __init__(self): self.name = 'FlashWindow' self.parent = 'Widget' events = list(FlashWindowEvents) attributes = { 'size' : { 'presence' : 'optional', 'default' : [ 50, 50 ] }, 'text' : { 'presence' : 'optional', 'default' : '' }, } widget.WidgetSpec.__init__(self, 'FlashWindow', 'Widget', events, attributes ) class FlashWindow(widget.Widget, flashwin.FlashWindow): """ An HTML window using the MS HTML control. """ _spec = FlashWindowSpec() def __init__(self, aParent, aResource): flashwin.FlashWindow.__init__( self, aParent, -1, # widget.makeNewId(aResource.id), aResource.position, aResource.size, style=wx.SUNKEN_BORDER, #style = wx.CLIP_SIBLINGS | wx.NO_FULL_REPAINT_ON_RESIZE, name = aResource.name ) widget.Widget.__init__(self, aParent, aResource) self._setText(aResource.text) self._bindEvents(event.WIDGET_EVENTS + FlashWindowEvents) def _getText(self) : #return self.GetOpenedPage() return self.GetText() def _setText(self, aString): if aString == '' or aString[0] == '<': self.LoadMovie(0, aString) else: # filename or URL self.LoadMovie(0, aString) text = property(_getText, _setText) # KEA 2004-05-02 # this will probably end up in Scriptable or Component # it should be completely generic # the only problem part would be the reference to the parent (background) # where the events are actually defined which would make this problematic # for a compound component or events bound to a Panel # what we really want is a reference to the application instance # there is probably some method to give us that in wxWidgets # UPDATE - I think GetTopLevelParent is what I was looking for def _bindEvents(self, eventList): # shouldn't components be subclasses of Scriptable? # components would have their own handlers but when # looking for a handler match it will search the parents # for now just grab handlers from the background # the references below would be self.findHandler instead of # background.findHandler #background = self.GetParent().GetParent() background = wx.GetTopLevelParent(self) if wx.GetApp()._showDebugMenu: bindUnusedEvents = True else: bindUnusedEvents = False # helper variable to simplify test for whether to bind InsteadOfTypeEvents # there is a good chance we will need to know # which events are bound, if we want to dynamically add or remove # events later, so go ahead and keep a reference to the list self.boundEvents = {} self.eventIdToHandler = {} self.wxEventIdMap = {} if 0: print "\nBINDING...", self.name for eventClass in eventList: #for eventClass in ButtonEvents: # need to figure out a way to avoid the need # for this id to class mapping which is used in _dispatch below self.wxEventIdMap[eventClass.id] = eventClass # command handler overrides normal mouseClick or select handler # so dispatch will automatically dispatch to the command handler # by looking up the handler this way # it also means that if there is a command association with this component # then the regular mouseClick or select handler will never be bound, just ignored if issubclass(eventClass, event.CommandTypeEvent) and self.command: handler = background.findHandler('on_' + self.command + '_command') if not handler: handler = background.findHandler('on_' + self.name + '_' + eventClass.name) else: handler = background.findHandler('on_' + self.name + '_' + eventClass.name) if not handler: handler = background.findHandler('on_' + eventClass.name) if handler or bindUnusedEvents: # only bind events that have an event handler # in this scenario unused events are never bound # which is more efficient, but the Message Watcher needs # to be changed # alternatively we can bind everything and then in _dispatch # if there isn't a match in eventIdToHandler then we know # the event isn't used and we can set used to False # the complication would be that we probably have to have to # always call Skip() which may or may not be a hassle with components # this doesn't bind command events # they would be of the form on_somename_command # or perhaps on_command but I don't think we would want # to support that # the event binding would be specific to a component # since on dispatch command overrides something like mouseClickEvent # but the name of the command is not related to the component # need to look at whether self.command has a value and then bind # with ButtonMouseClickEvent.binding if that isn't already bound # then in dispatch have to check again I think # need to avoid double binding # also binding shouldn't be order-specific # so how to avoid binding mouseDrag to _dispatch # if mouseMove is already bound or if binding mouseMove # not rebinding if mouseDrag is already bound # perhaps MouseDragEvent keeps a reference to MouseMoveEvent # and that is inserted into boundEvents, then we check boundEvents # prior to rebinding? if not self.boundEvents.get(eventClass.binding, None): background.Bind(eventClass.binding, self._dispatch, self) self.boundEvents[eventClass.binding] = eventClass.name if handler: if 0: print " binding", self.name, eventClass.name, handler.__name__, eventClass.id # KEA 2004-05-02 # change to just using the method directly, Handler class not needed # actually the Handler class isn't needed at all # so if the initial list built to simplify findHandler # just stores a reference to the method that would be fine # as long as the whole system uses that # the only reason we don't just build the list ourselves # in _bindEvents is that every component needs to do findHandler # so it is more efficient to do once when the Scriptable object # is created than to reparse for each component #self.eventIdToHandler[eventClass.id] = handler #self.eventIdToHandler[eventClass.id] = handler.getFunction() self.eventIdToHandler[eventClass.id] = handler if 0: print "\n boundEvents:" for name in self.boundEvents.values(): print " ", name print "\n\n" print "\n self.eventIdToHandler:" for id in self.eventIdToHandler: # KEA 2004-05-02 # change to just using the method directly, Handler class not needed #print " ", id, self.eventIdToHandler[id]._function print " ", id, self.eventIdToHandler[id] print "\n\n" import sys from PythonCard import registry registry.Registry.getInstance().register(sys.modules[__name__].FlashWindow) #Sample program and rsrc file #!/usr/bin/python """ __version__ = "$Revision: 1.19 $" __date__ = "$Date: 2004/08/12 19:18:59 $" """ from PythonCard import dialog, model import wx class SimpleFlashViewer(model.Background): def on_initialize(self, event): self.flash = self.components.FlashDisplay btnFlags = wx.RIGHT | wx.ALIGN_CENTER_VERTICAL sizer3 = wx.BoxSizer(wx.HORIZONTAL) sizer3.Add((5, 5), 0) # spacer sizer3.Add(self.flash, 1, wx.EXPAND) sizer3.Add((10, 5), 0) # spacer sizer2 = wx.BoxSizer(wx.HORIZONTAL) sizer2.Add((5, 5), 1) # spacer sizer2.Add(self.components.btnOpenFile, 0, btnFlags, 5) sizer2.Add(self.components.btnOpenURL, 0, btnFlags, 5) sizer1 = wx.BoxSizer(wx.VERTICAL) sizer1.Add(sizer3, 1, wx.EXPAND) sizer1.Add((5, 5), 0) # spacer sizer1.Add(sizer2, 0, wx.EXPAND) sizer1.Fit(self) sizer1.SetSizeHints(self) self.panel.SetSizer(sizer1) self.panel.SetAutoLayout(1) self.panel.Layout() def on_btnOpenFile_mouseClick(self, event): wildcard = "SWF files (*.swf)|*.swf;*.SWF|All files (*.*)|*.*" result = dialog.openFileDialog(None, "Open file", '', '', wildcard) if result.accepted: self.flash.LoadMovie(0, result.paths[0]) return def on_btnOpenURL_mouseClick(self, event): # you can retrieve flash files from internet too result = dialog.textEntryDialog(self, "Enter a URL of a .swf file", "Enter URL", '') if result.accepted and result.returnedString=="Ok": # setting the movie property works too self.flash.movie = result.text return if __name__ == '__main__': app = model.Application(SimpleFlashViewer) app.MainLoop() # rsrc file {'application':{'type':'Application', 'name':'SimpleFlashViewer', 'backgrounds': [ {'type':'Background', 'name':'bgMin', 'title':'SimpleFlashViewer PythonCard Application', 'size':(698, 703), 'statusBar':1, 'style':['resizeable'], 'menubar': {'type':'MenuBar', 'menus': [ {'type':'Menu', 'name':'menuFile', 'label':'&File', 'items': [ {'type':'MenuItem', 'name':'menuFileExit', 'label':'E&xit\tAlt+X', 'command':'exit', }, ] }, ] }, 'components': [ {'type':'FlashWindow', 'name':'FlashDisplay', 'position':(0, 30), 'size':(685, 553), 'backgroundColor':(255, 255, 255, 255), }, {'type':'Button', 'name':'btnOpenFile', 'position':(524, 593), 'label':'Open File', }, {'type':'Button', 'name':'btnOpenURL', 'position':(599, 593), 'label':'Open URL', }, ] # end components } # end background ] # end backgrounds } } -- John Henry |